From 18c14add399c35153883f8b84a2e11a7c22f6721 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 9 Sep 2021 14:05:10 -0700 Subject: [PATCH 01/38] Add a `try_clone()` function to `OwnedFd`. As suggested in #88564. This adds a `try_clone()` to `OwnedFd` by refactoring the code out of the existing `File`/`Socket` code. --- library/std/src/os/fd/owned.rs | 23 +++++++++++ library/std/src/os/windows/io/handle.rs | 33 +++++++++++++++ library/std/src/os/windows/io/socket.rs | 54 +++++++++++++++++++++++++ library/std/src/sys/unix/fd.rs | 17 +------- library/std/src/sys/windows/fs.rs | 2 +- library/std/src/sys/windows/handle.rs | 15 +------ library/std/src/sys/windows/net.rs | 47 +-------------------- 7 files changed, 115 insertions(+), 76 deletions(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 52d7d4690d39f..597e050b00d5a 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,6 +8,7 @@ use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; +use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed file descriptor. @@ -67,6 +68,28 @@ impl BorrowedFd<'_> { } } +impl OwnedFd { + /// Creates a new `OwnedFd` instance that shares the same underlying file handle + /// as the existing `OwnedFd` instance. + pub fn try_clone(&self) -> crate::io::Result { + // We want to atomically duplicate this file descriptor and set the + // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This + // is a POSIX flag that was added to Linux in 2.6.24. + #[cfg(not(target_os = "espidf"))] + let cmd = libc::F_DUPFD_CLOEXEC; + + // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics + // will never be supported, as this is a bare metal framework with + // no capabilities for multi-process execution. While F_DUPFD is also + // not supported yet, it might be (currently it returns ENOSYS). + #[cfg(target_os = "espidf")] + let cmd = libc::F_DUPFD; + + let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; + Ok(unsafe { Self::from_raw_fd(fd) }) + } +} + #[unstable(feature = "io_safety", issue = "87074")] impl AsRawFd for BorrowedFd<'_> { #[inline] diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 72a17adb3b470..64c3761511425 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -11,6 +11,7 @@ use crate::marker::PhantomData; use crate::mem::forget; use crate::ptr::NonNull; use crate::sys::c; +use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed handle. @@ -110,6 +111,38 @@ impl BorrowedHandle<'_> { } } +impl OwnedHandle { + /// Creates a new `OwnedHandle` instance that shares the same underlying file handle + /// as the existing `OwnedHandle` instance. + pub fn try_clone(&self) -> crate::io::Result { + let handle = self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?; + + Ok(unsafe { OwnedHandle::from_raw_handle(handle) }) + } + + pub(crate) fn duplicate( + &self, + access: c::DWORD, + inherit: bool, + options: c::DWORD, + ) -> io::Result { + let mut ret = 0 as c::HANDLE; + cvt(unsafe { + let cur_proc = c::GetCurrentProcess(); + c::DuplicateHandle( + cur_proc, + self.as_raw_handle(), + cur_proc, + &mut ret, + access, + inherit as c::BOOL, + options, + ) + })?; + unsafe { Ok(Self::from_raw_handle(ret)) } + } +} + impl TryFrom for OwnedHandle { type Error = (); diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 23db66df09f7a..9e27ead90fb56 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -7,6 +7,7 @@ use crate::fmt; use crate::marker::PhantomData; use crate::mem::forget; use crate::sys::c; +use crate::sys::cvt; /// A borrowed socket. /// @@ -69,6 +70,59 @@ impl BorrowedSocket<'_> { } } +impl OwnedSocket { + /// Creates a new `OwnedSocket` instance that shares the same underlying socket + /// as the existing `OwnedSocket` instance. + pub fn try_clone(&self) -> io::Result { + let mut info = unsafe { mem::zeroed::() }; + let result = unsafe { + c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) + }; + cvt(result)?; + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, + ) + }; + + if socket != c::INVALID_SOCKET { + unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } + } else { + let error = unsafe { c::WSAGetLastError() }; + + if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED, + ) + }; + + if socket == c::INVALID_SOCKET { + return Err(last_error()); + } + + unsafe { + let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); + socket.set_no_inherit()?; + Ok(socket) + } + } + } +} + impl AsRawSocket for BorrowedSocket<'_> { #[inline] fn as_raw_socket(&self) -> RawSocket { diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 0956726084e02..3c2b36fe691bc 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -266,22 +266,9 @@ impl FileDesc { } } + #[inline] pub fn duplicate(&self) -> io::Result { - // We want to atomically duplicate this file descriptor and set the - // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This - // is a POSIX flag that was added to Linux in 2.6.24. - #[cfg(not(target_os = "espidf"))] - let cmd = libc::F_DUPFD_CLOEXEC; - - // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics - // will never be supported, as this is a bare metal framework with - // no capabilities for multi-process execution. While F_DUPFD is also - // not supported yet, it might be (currently it returns ENOSYS). - #[cfg(target_os = "espidf")] - let cmd = libc::F_DUPFD; - - let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; - Ok(unsafe { FileDesc::from_raw_fd(fd) }) + Ok(Self(self.0.try_clone()?)) } } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 0c1a50e231cd4..08ff35361f4b6 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -455,7 +455,7 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? }) + Ok(Self(self.0.try_clone()?)) } fn reparse_point<'a>( diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 21d86b002264a..8de5729daa38d 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -235,20 +235,7 @@ impl Handle { inherit: bool, options: c::DWORD, ) -> io::Result { - let mut ret = 0 as c::HANDLE; - cvt(unsafe { - let cur_proc = c::GetCurrentProcess(); - c::DuplicateHandle( - cur_proc, - self.as_raw_handle(), - cur_proc, - &mut ret, - access, - inherit as c::BOOL, - options, - ) - })?; - unsafe { Ok(Handle::from_raw_handle(ret)) } + Ok(Self(self.0.duplicate(access, inherit, options)?)) } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 33152cc97abc0..681875985bdc9 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -208,52 +208,7 @@ impl Socket { } pub fn duplicate(&self) -> io::Result { - let mut info = unsafe { mem::zeroed::() }; - let result = unsafe { - c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) - }; - cvt(result)?; - let socket = unsafe { - c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, - ) - }; - - if socket != c::INVALID_SOCKET { - unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } - } else { - let error = unsafe { c::WSAGetLastError() }; - - if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { - return Err(io::Error::from_raw_os_error(error)); - } - - let socket = unsafe { - c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED, - ) - }; - - if socket == c::INVALID_SOCKET { - return Err(last_error()); - } - - unsafe { - let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); - socket.set_no_inherit()?; - Ok(socket) - } - } + Ok(Self(self.0.duplicate()?)) } fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { From 622dfcceb9328b359e28adaec8192390e494ca1e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 9 Sep 2021 14:44:54 -0700 Subject: [PATCH 02/38] Fix Windows compilation errors. --- library/std/src/os/windows/io/handle.rs | 3 ++- library/std/src/os/windows/io/socket.rs | 11 +++++++++-- library/std/src/sys/windows/fs.rs | 2 +- library/std/src/sys/windows/net.rs | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 64c3761511425..92c5f49e58a00 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -7,6 +7,7 @@ use crate::convert::TryFrom; use crate::ffi::c_void; use crate::fmt; use crate::fs; +use crate::io; use crate::marker::PhantomData; use crate::mem::forget; use crate::ptr::NonNull; @@ -114,7 +115,7 @@ impl BorrowedHandle<'_> { impl OwnedHandle { /// Creates a new `OwnedHandle` instance that shares the same underlying file handle /// as the existing `OwnedHandle` instance. - pub fn try_clone(&self) -> crate::io::Result { + pub fn try_clone(&self) -> crate::io::Result { let handle = self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?; Ok(unsafe { OwnedHandle::from_raw_handle(handle) }) diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 9e27ead90fb56..0d77643404742 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -4,7 +4,9 @@ use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use crate::fmt; +use crate::io; use crate::marker::PhantomData; +use crate::mem; use crate::mem::forget; use crate::sys::c; use crate::sys::cvt; @@ -91,7 +93,7 @@ impl OwnedSocket { }; if socket != c::INVALID_SOCKET { - unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } + unsafe { Ok(Self(OwnedSocket::from_raw_socket(socket))) } } else { let error = unsafe { c::WSAGetLastError() }; @@ -115,7 +117,7 @@ impl OwnedSocket { } unsafe { - let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); + let socket = Self(OwnedSocket::from_raw_socket(socket)); socket.set_no_inherit()?; Ok(socket) } @@ -123,6 +125,11 @@ impl OwnedSocket { } } +/// Returns the last error from the Windows socket interface. +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) +} + impl AsRawSocket for BorrowedSocket<'_> { #[inline] fn as_raw_socket(&self) -> RawSocket { diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 08ff35361f4b6..34455b7e3161a 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -455,7 +455,7 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Ok(Self(self.0.try_clone()?)) + Ok(Self { handle: self.handle.try_clone()? }) } fn reparse_point<'a>( diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 681875985bdc9..39417baebd44c 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -208,7 +208,7 @@ impl Socket { } pub fn duplicate(&self) -> io::Result { - Ok(Self(self.0.duplicate()?)) + Ok(Self(self.0.try_clone()?)) } fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { From c986c6b4ffec634d3c0ecbc3867a818bc41a59be Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 9 Sep 2021 15:30:17 -0700 Subject: [PATCH 03/38] Fix more Windows compilation errors. --- library/std/src/os/windows/io/handle.rs | 4 +--- library/std/src/os/windows/io/socket.rs | 17 +++++++++++++++-- library/std/src/sys/windows/handle.rs | 6 +++++- library/std/src/sys/windows/net.rs | 15 +-------------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 92c5f49e58a00..9522a05495c6f 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -116,9 +116,7 @@ impl OwnedHandle { /// Creates a new `OwnedHandle` instance that shares the same underlying file handle /// as the existing `OwnedHandle` instance. pub fn try_clone(&self) -> crate::io::Result { - let handle = self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?; - - Ok(unsafe { OwnedHandle::from_raw_handle(handle) }) + self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS) } pub(crate) fn duplicate( diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 0d77643404742..7acd0af88b39a 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -93,7 +93,7 @@ impl OwnedSocket { }; if socket != c::INVALID_SOCKET { - unsafe { Ok(Self(OwnedSocket::from_raw_socket(socket))) } + unsafe { Ok(OwnedSocket::from_raw_socket(socket)) } } else { let error = unsafe { c::WSAGetLastError() }; @@ -117,12 +117,25 @@ impl OwnedSocket { } unsafe { - let socket = Self(OwnedSocket::from_raw_socket(socket)); + let socket = OwnedSocket::from_raw_socket(socket); socket.set_no_inherit()?; Ok(socket) } } } + + #[cfg(not(target_vendor = "uwp"))] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + sys::cvt(unsafe { + c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) + }) + .map(drop) + } + + #[cfg(target_vendor = "uwp")] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP")) + } } /// Returns the last error from the Windows socket interface. diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 8de5729daa38d..76a97e89be194 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -229,12 +229,16 @@ impl Handle { Ok(written as usize) } + pub fn try_clone(&self) -> io::Result { + Ok(Self(self.0.try_clone()?)) + } + pub fn duplicate( &self, access: c::DWORD, inherit: bool, options: c::DWORD, - ) -> io::Result { + ) -> io::Result { Ok(Self(self.0.duplicate(access, inherit, options)?)) } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 39417baebd44c..75d4b3bd76862 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -129,7 +129,7 @@ impl Socket { unsafe { let socket = Self::from_raw_socket(socket); - socket.set_no_inherit()?; + socket.0.set_no_inherit()?; Ok(socket) } } @@ -371,19 +371,6 @@ impl Socket { } } - #[cfg(not(target_vendor = "uwp"))] - fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { - c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) - }) - .map(drop) - } - - #[cfg(target_vendor = "uwp")] - fn set_no_inherit(&self) -> io::Result<()> { - Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP")) - } - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { Shutdown::Write => c::SD_SEND, From 2d6a4c85ca037ac07cac6029c2b174678c39a40d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 9 Sep 2021 15:37:43 -0700 Subject: [PATCH 04/38] Fix another Windows compilation error. --- library/std/src/os/windows/io/socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 7acd0af88b39a..e0af4f1f6cb16 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -126,7 +126,7 @@ impl OwnedSocket { #[cfg(not(target_vendor = "uwp"))] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { + cvt(unsafe { c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) }) .map(drop) From 53e072f2207747e8b60dcbb77b763c1598cfb192 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 5 Oct 2021 14:11:49 -0700 Subject: [PATCH 05/38] Fix compilation on WASI, which doesn't yet support `dup`. --- library/std/src/os/fd/owned.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 597e050b00d5a..0b6588db92c83 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,6 +8,7 @@ use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; +#[cfg(not(target_os = "wasi"))] use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -71,6 +72,7 @@ impl BorrowedFd<'_> { impl OwnedFd { /// Creates a new `OwnedFd` instance that shares the same underlying file handle /// as the existing `OwnedFd` instance. + #[cfg(not(target_os = "wasi"))] pub fn try_clone(&self) -> crate::io::Result { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This @@ -88,6 +90,14 @@ impl OwnedFd { let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; Ok(unsafe { Self::from_raw_fd(fd) }) } + + #[cfg(target_os = "wasi")] + pub fn try_clone(&self) -> crate::io::Result { + Err(crate::io::Error::new_const( + crate::io::ErrorKind::Unsupported, + &"operation not supported on WASI yet", + )) + } } #[unstable(feature = "io_safety", issue = "87074")] From 8f68bdc38024c471f925ce8b6572ec41546229e1 Mon Sep 17 00:00:00 2001 From: woppopo Date: Sat, 4 Dec 2021 21:57:39 +0900 Subject: [PATCH 06/38] Make `Borrow` and `BorrowMut` impls `const` --- library/core/src/array/mod.rs | 6 ++++-- library/core/src/borrow.rs | 15 ++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index b27c36baf37c5..e89659c41eae8 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -149,14 +149,16 @@ impl AsMut<[T]> for [T; N] { } #[stable(feature = "array_borrow", since = "1.4.0")] -impl Borrow<[T]> for [T; N] { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const Borrow<[T]> for [T; N] { fn borrow(&self) -> &[T] { self } } #[stable(feature = "array_borrow", since = "1.4.0")] -impl BorrowMut<[T]> for [T; N] { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const BorrowMut<[T]> for [T; N] { fn borrow_mut(&mut self) -> &mut [T] { self } diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index f28be20aaa1e6..58eabecf3f091 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -205,7 +205,8 @@ pub trait BorrowMut: Borrow { } #[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const Borrow for T { #[rustc_diagnostic_item = "noop_method_borrow"] fn borrow(&self) -> &T { self @@ -213,28 +214,32 @@ impl Borrow for T { } #[stable(feature = "rust1", since = "1.0.0")] -impl BorrowMut for T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const BorrowMut for T { fn borrow_mut(&mut self) -> &mut T { self } } #[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for &T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const Borrow for &T { fn borrow(&self) -> &T { &**self } } #[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for &mut T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const Borrow for &mut T { fn borrow(&self) -> &T { &**self } } #[stable(feature = "rust1", since = "1.0.0")] -impl BorrowMut for &mut T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const BorrowMut for &mut T { fn borrow_mut(&mut self) -> &mut T { &mut **self } From 70855b24b89e348aef0e28a0fe6db6d5bf19d11e Mon Sep 17 00:00:00 2001 From: luojia65 Date: Sun, 5 Dec 2021 16:32:14 +0800 Subject: [PATCH 07/38] Add spin_loop hint for RISC-V architecture This commit also updates `stdarch` git submodule. --- library/core/src/hint.rs | 5 +++++ library/stdarch | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 95798879155c5..f49aefea81bac 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -137,6 +137,11 @@ pub fn spin_loop() { unsafe { crate::arch::arm::__yield() }; } } + + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + { + crate::arch::riscv::pause(); + } } /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what diff --git a/library/stdarch b/library/stdarch index cfba59fccd90b..43b4556c44197 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit cfba59fccd90b3b52a614120834320f764ab08d1 +Subproject commit 43b4556c44197af4ef82e42a12dfc513a1397f87 From f4f3b2d7bcbed614b224dd429eedc50980b29ac9 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 00:57:53 +0000 Subject: [PATCH 08/38] When `.await` is called on a non-`Future` expression, suggest removal Keep track of the origin of a `T: Future` obligation when caused by an `.await` expression. Address #66731. --- compiler/rustc_ast_lowering/src/expr.rs | 5 ++- compiler/rustc_middle/src/traits/mod.rs | 2 + compiler/rustc_parse/src/parser/expr.rs | 4 +- .../src/traits/error_reporting/mod.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 26 ++++++++++++ .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 31 ++++++++++++-- .../ui/async-await/async-error-span.stderr | 4 +- .../ui/async-await/async-fn-nonsend.stderr | 12 +++--- .../incorrect-syntax-suggestions.stderr | 24 +++++------ .../ui/async-await/issue-64130-1-sync.stderr | 4 +- .../ui/async-await/issue-64130-2-send.stderr | 4 +- .../ui/async-await/issue-64130-3-other.stderr | 4 +- .../issue-64130-4-async-move.stderr | 4 +- .../issue-64130-non-send-future-diags.stderr | 4 +- .../issue-67252-unnamed-future.stderr | 4 +- src/test/ui/async-await/issue-70594.rs | 1 + src/test/ui/async-await/issue-70594.stderr | 32 +++++++++++---- .../issue-70935-complex-spans.stderr | 21 +++------- src/test/ui/async-await/issue-71137.stderr | 4 +- .../ui/async-await/issues/issue-51719.stderr | 4 +- .../ui/async-await/issues/issue-51751.stderr | 4 +- .../ui/async-await/issues/issue-62009-1.rs | 5 ++- .../async-await/issues/issue-62009-1.stderr | 41 ++++++++++++------- .../async-await/issues/issue-62009-2.stderr | 4 +- .../issue-65436-raw-ptr-not-send.stderr | 12 ++---- .../issues/non-async-enclosing-span.stderr | 4 +- .../async-await/suggest-missing-await.stderr | 8 ++-- .../async-await/unresolved_type_param.stderr | 20 ++++----- .../ui/lint/must_not_suspend/boxed.stderr | 2 +- .../ui/lint/must_not_suspend/dedup.stderr | 2 +- .../ui/lint/must_not_suspend/gated.stderr | 2 +- .../ui/lint/must_not_suspend/mutex.stderr | 2 +- src/test/ui/lint/must_not_suspend/ref.stderr | 2 +- .../ui/lint/must_not_suspend/trait.stderr | 4 +- src/test/ui/lint/must_not_suspend/unit.stderr | 2 +- src/test/ui/lint/must_not_suspend/warn.stderr | 2 +- 36 files changed, 190 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c9578c2f50f90..2cf0dbaf425b8 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -607,6 +607,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// } /// ``` fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { + let dot_await_span = expr.span.shrink_to_hi().to(await_span); match self.generator_kind { Some(hir::GeneratorKind::Async(_)) => {} Some(hir::GeneratorKind::Gen) | None => { @@ -623,7 +624,7 @@ impl<'hir> LoweringContext<'_, 'hir> { err.emit(); } } - let span = self.mark_span_with_reason(DesugaringKind::Await, await_span, None); + let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None); let gen_future_span = self.mark_span_with_reason( DesugaringKind::Await, await_span, @@ -682,7 +683,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); - this.arena.alloc(this.expr(await_span, expr_break, ThinVec::new())) + this.arena.alloc(this.expr(span, expr_break, ThinVec::new())) }); self.arm(ready_pat, break_x) }; diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 49a64cb246ad0..5173d7e2a51dc 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -348,6 +348,8 @@ pub enum ObligationCauseCode<'tcx> { /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` OpaqueType, + AwaitableExpr, + /// Well-formed checking. If a `WellFormedLoc` is provided, /// then it will be used to eprform HIR-based wf checking /// after an error occurs, in order to generate a more precise error span. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1dbd7bad0f023..791053670ad26 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2831,8 +2831,8 @@ impl<'a> Parser<'a> { ExprKind::Call(f, args) } - fn mk_await_expr(&mut self, self_arg: P, lo: Span) -> P { - let span = lo.to(self.prev_token.span); + fn mk_await_expr(&mut self, self_arg: P, _lo: Span) -> P { + let span = self.prev_token.span; let await_expr = self.mk_expr(span, ExprKind::Await(self_arg), AttrVec::new()); self.recover_from_await_method_call(); await_expr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index d9f86fbc23b5d..df8c6ef69b20c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -439,6 +439,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_remove_reference(&obligation, &mut err, trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref); self.note_version_mismatch(&mut err, &trait_ref); + self.suggest_remove_await(&obligation, &mut err); if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { self.suggest_await_before_try(&mut err, &obligation, trait_ref, span); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 2e87d6fdd3dc2..957b8c379a39b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -89,6 +89,12 @@ pub trait InferCtxtExt<'tcx> { trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ); + fn suggest_remove_await( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + ); + fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, @@ -873,6 +879,25 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + fn suggest_remove_await( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + ) { + let span = obligation.cause.span; + + if let ObligationCauseCode::AwaitableExpr = obligation.cause.code { + // FIXME: use `trait_ref.self_ty().no_bound_vars()` to typecheck if `()` and if not + // maybe suggest returning instead? + err.span_suggestion_verbose( + span, + "do not `.await` the expression", + String::new(), + Applicability::MachineApplicable, + ); + } + } + /// Check if the trait bound is implemented for a different mutability and note it in the /// final error. fn suggest_change_mut( @@ -1935,6 +1960,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(_) + | ObligationCauseCode::AwaitableExpr | ObligationCauseCode::LetElse => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index a02a7d7cbfeb2..de713b7de2e5f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -810,7 +810,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = item_ty.subst(self.tcx, substs); self.write_resolution(hir_id, Ok((def_kind, def_id))); - self.add_required_obligations(span, def_id, &substs); + self.add_required_obligations_with_code( + span, + def_id, + &substs, + match lang_item { + hir::LangItem::FuturePoll => ObligationCauseCode::AwaitableExpr, + // FIXME: see if there are other obligation specializations we could do here beyond + // what we do above for `.await`. + _ => traits::ItemObligation(def_id), + }, + ); (Res::Def(def_kind, def_id), ty) } @@ -1492,12 +1502,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Add all the obligations that are required, substituting and normalized appropriately. - #[tracing::instrument(level = "debug", skip(self, span, def_id, substs))] crate fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { + self.add_required_obligations_with_code( + span, + def_id, + substs, + traits::ItemObligation(def_id), + ) + } + + #[tracing::instrument(level = "debug", skip(self, span, def_id, substs))] + fn add_required_obligations_with_code( + &self, + span: Span, + def_id: DefId, + substs: &SubstsRef<'tcx>, + code: ObligationCauseCode<'tcx>, + ) { let (bounds, _) = self.instantiate_bounds(span, def_id, &substs); for obligation in traits::predicates_for_generics( - traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), + traits::ObligationCause::new(span, self.body_id, code), self.param_env, bounds, ) { diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index 2e3f8bb52560a..7d4447b6d5578 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -14,10 +14,10 @@ LL | let a; | ^ cannot infer type | note: the type is part of the `async fn` body because of this `await` - --> $DIR/async-error-span.rs:14:5 + --> $DIR/async-error-span.rs:14:17 | LL | get_future().await; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index bf7ab148e23df..bff282085735c 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -6,13 +6,13 @@ LL | assert_send(local_dropped_before_await()); | = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await - --> $DIR/async-fn-nonsend.rs:24:5 + --> $DIR/async-fn-nonsend.rs:24:10 | LL | let x = non_send(); | - has type `impl Debug` which is not `Send` LL | drop(x); LL | fut().await; - | ^^^^^^^^^^^ await occurs here, with `x` maybe used later + | ^^^^^^ await occurs here, with `x` maybe used later LL | } | - `x` is later dropped here note: required by a bound in `assert_send` @@ -29,12 +29,12 @@ LL | assert_send(non_send_temporary_in_match()); | = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await - --> $DIR/async-fn-nonsend.rs:33:20 + --> $DIR/async-fn-nonsend.rs:33:25 | LL | match Some(non_send()) { | ---------- has type `impl Debug` which is not `Send` LL | Some(_) => fut().await, - | ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later + | ^^^^^^ await occurs here, with `non_send()` maybe used later ... LL | } | - `non_send()` is later dropped here @@ -52,13 +52,13 @@ LL | assert_send(non_sync_with_method_call()); | = help: the trait `Send` is not implemented for `dyn std::fmt::Write` note: future is not `Send` as this value is used across an await - --> $DIR/async-fn-nonsend.rs:42:9 + --> $DIR/async-fn-nonsend.rs:42:14 | LL | let f: &mut std::fmt::Formatter = panic!(); | - has type `&mut Formatter<'_>` which is not `Send` LL | if non_sync().fmt(f).unwrap() == () { LL | fut().await; - | ^^^^^^^^^^^ await occurs here, with `f` maybe used later + | ^^^^^^ await occurs here, with `f` maybe used later LL | } LL | } | - `f` is later dropped here diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 52615df6008ff..27f4b0dac618b 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -162,52 +162,52 @@ LL | let _ = (await bar())?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:71:13 + --> $DIR/incorrect-syntax-suggestions.rs:71:19 | LL | fn foo13() -> Result<(), ()> { | ----- this is not `async` LL | let _ = bar().await(); - | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:76:13 + --> $DIR/incorrect-syntax-suggestions.rs:76:19 | LL | fn foo14() -> Result<(), ()> { | ----- this is not `async` LL | let _ = bar().await()?; - | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:81:13 + --> $DIR/incorrect-syntax-suggestions.rs:81:19 | LL | fn foo15() -> Result<(), ()> { | ----- this is not `async` LL | let _ = bar().await; - | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:85:13 + --> $DIR/incorrect-syntax-suggestions.rs:85:19 | LL | fn foo16() -> Result<(), ()> { | ----- this is not `async` LL | let _ = bar().await?; - | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:90:17 + --> $DIR/incorrect-syntax-suggestions.rs:90:23 | LL | fn foo() -> Result<(), ()> { | --- this is not `async` LL | let _ = bar().await?; - | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:97:17 + --> $DIR/incorrect-syntax-suggestions.rs:97:23 | LL | let foo = || { | -- this is not `async` LL | let _ = bar().await?; - | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:113:17 diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr index 010611fae4381..e205de4738f24 100644 --- a/src/test/ui/async-await/issue-64130-1-sync.stderr +++ b/src/test/ui/async-await/issue-64130-1-sync.stderr @@ -6,12 +6,12 @@ LL | is_sync(bar()); | = help: within `impl Future`, the trait `Sync` is not implemented for `Foo` note: future is not `Sync` as this value is used across an await - --> $DIR/issue-64130-1-sync.rs:15:5 + --> $DIR/issue-64130-1-sync.rs:15:10 | LL | let x = Foo; | - has type `Foo` which is not `Sync` LL | baz().await; - | ^^^^^^^^^^^ await occurs here, with `x` maybe used later + | ^^^^^^ await occurs here, with `x` maybe used later LL | } | - `x` is later dropped here note: required by a bound in `is_sync` diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr index bb598b53594e9..2225000e2e579 100644 --- a/src/test/ui/async-await/issue-64130-2-send.stderr +++ b/src/test/ui/async-await/issue-64130-2-send.stderr @@ -6,12 +6,12 @@ LL | is_send(bar()); | = help: within `impl Future`, the trait `Send` is not implemented for `Foo` note: future is not `Send` as this value is used across an await - --> $DIR/issue-64130-2-send.rs:15:5 + --> $DIR/issue-64130-2-send.rs:15:10 | LL | let x = Foo; | - has type `Foo` which is not `Send` LL | baz().await; - | ^^^^^^^^^^^ await occurs here, with `x` maybe used later + | ^^^^^^ await occurs here, with `x` maybe used later LL | } | - `x` is later dropped here note: required by a bound in `is_send` diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr index 4de7929e18149..17867a6a3f62e 100644 --- a/src/test/ui/async-await/issue-64130-3-other.stderr +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -8,12 +8,12 @@ LL | is_qux(bar()); | ^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo` | note: future does not implement `Qux` as this value is used across an await - --> $DIR/issue-64130-3-other.rs:18:5 + --> $DIR/issue-64130-3-other.rs:18:10 | LL | let x = Foo; | - has type `Foo` which does not implement `Qux` LL | baz().await; - | ^^^^^^^^^^^ await occurs here, with `x` maybe used later + | ^^^^^^ await occurs here, with `x` maybe used later LL | } | - `x` is later dropped here note: required by a bound in `is_qux` diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index 2d46dfb7269d1..d631e6dc7f7e9 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -6,13 +6,13 @@ LL | pub fn foo() -> impl Future + Send { | = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)` note: future is not `Send` as this value is used across an await - --> $DIR/issue-64130-4-async-move.rs:21:26 + --> $DIR/issue-64130-4-async-move.rs:21:31 | LL | match client.status() { | ------ has type `&Client` which is not `Send` LL | 200 => { LL | let _x = get().await; - | ^^^^^^^^^^^ await occurs here, with `client` maybe used later + | ^^^^^^ await occurs here, with `client` maybe used later ... LL | } | - `client` is later dropped here diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr index 8eedb3597330e..1da80d98bf8fc 100644 --- a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -6,12 +6,12 @@ LL | is_send(foo()); | = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>` note: future is not `Send` as this value is used across an await - --> $DIR/issue-64130-non-send-future-diags.rs:17:5 + --> $DIR/issue-64130-non-send-future-diags.rs:17:10 | LL | let g = x.lock().unwrap(); | - has type `MutexGuard<'_, u32>` which is not `Send` LL | baz().await; - | ^^^^^^^^^^^ await occurs here, with `g` maybe used later + | ^^^^^^ await occurs here, with `g` maybe used later LL | } | - `g` is later dropped here note: required by a bound in `is_send` diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr index b61694ad53e5b..f32e074d75d62 100644 --- a/src/test/ui/async-await/issue-67252-unnamed-future.stderr +++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr @@ -6,12 +6,12 @@ LL | spawn(async { | = help: within `impl Future`, the trait `Send` is not implemented for `*mut ()` note: future is not `Send` as this value is used across an await - --> $DIR/issue-67252-unnamed-future.rs:20:9 + --> $DIR/issue-67252-unnamed-future.rs:20:16 | LL | let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` | -- has type `*mut ()` which is not `Send` LL | AFuture.await; - | ^^^^^^^^^^^^^ await occurs here, with `_a` maybe used later + | ^^^^^^ await occurs here, with `_a` maybe used later LL | }); | - `_a` is later dropped here note: required by a bound in `spawn` diff --git a/src/test/ui/async-await/issue-70594.rs b/src/test/ui/async-await/issue-70594.rs index 9e7c5847b3b2e..bfed4b0b05c6e 100644 --- a/src/test/ui/async-await/issue-70594.rs +++ b/src/test/ui/async-await/issue-70594.rs @@ -6,6 +6,7 @@ async fn fun() { //~| error: `.await` is not allowed in a `const` //~| error: `.await` is not allowed in a `const` //~| error: `()` is not a future + //~| error: `()` is not a future } fn main() {} diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr index ab05251526b0d..a2d4257577e32 100644 --- a/src/test/ui/async-await/issue-70594.stderr +++ b/src/test/ui/async-await/issue-70594.stderr @@ -1,34 +1,48 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-70594.rs:4:9 + --> $DIR/issue-70594.rs:4:12 | LL | async fn fun() { | --- this is not `async` LL | [1; ().await]; - | ^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0744]: `.await` is not allowed in a `const` - --> $DIR/issue-70594.rs:4:9 + --> $DIR/issue-70594.rs:4:12 | LL | [1; ().await]; - | ^^^^^^^^ + | ^^^^^ error[E0744]: `.await` is not allowed in a `const` - --> $DIR/issue-70594.rs:4:9 + --> $DIR/issue-70594.rs:4:11 | LL | [1; ().await]; - | ^^^^^^^^ + | ^^^^^^ error[E0277]: `()` is not a future - --> $DIR/issue-70594.rs:4:9 + --> $DIR/issue-70594.rs:4:12 | LL | [1; ().await]; - | ^^^^^^^^ `()` is not a future + | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required because of the requirements on the impl of `IntoFuture` for `()` -error: aborting due to 4 previous errors +error[E0277]: `()` is not a future + --> $DIR/issue-70594.rs:4:11 + | +LL | [1; ().await]; + | ^^^^^^ `()` is not a future + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited +help: do not `.await` the expression + | +LL - [1; ().await]; +LL + [1; ()]; + | + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0277, E0728, E0744. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-70935-complex-spans.stderr b/src/test/ui/async-await/issue-70935-complex-spans.stderr index 8451fb840992c..4929aa29d0f40 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.stderr @@ -6,25 +6,16 @@ LL | fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { | = help: the trait `Sync` is not implemented for `Sender` note: future is not `Send` as this value is used across an await - --> $DIR/issue-70935-complex-spans.rs:13:9 - | -LL | / baz(|| async{ -LL | | foo(tx.clone()); -LL | | }).await; - | |________________^ first, await occurs here, with the value maybe used later... -note: the value is later dropped here - --> $DIR/issue-70935-complex-spans.rs:15:17 - | -LL | }).await; - | ^ -note: this has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send` - --> $DIR/issue-70935-complex-spans.rs:13:13 + --> $DIR/issue-70935-complex-spans.rs:15:11 | LL | baz(|| async{ - | _____________^ + | _____________- LL | | foo(tx.clone()); LL | | }).await; - | |_________^ + | | - ^^^^^^- the value is later dropped here + | | | | + | |_________| await occurs here, with the value maybe used later + | has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send` error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-71137.stderr b/src/test/ui/async-await/issue-71137.stderr index dddea12162a0b..eade6aa2d3dcc 100644 --- a/src/test/ui/async-await/issue-71137.stderr +++ b/src/test/ui/async-await/issue-71137.stderr @@ -6,12 +6,12 @@ LL | fake_spawn(wrong_mutex()); | = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>` note: future is not `Send` as this value is used across an await - --> $DIR/issue-71137.rs:14:5 + --> $DIR/issue-71137.rs:14:25 | LL | let mut guard = m.lock().unwrap(); | --------- has type `MutexGuard<'_, i32>` which is not `Send` LL | (async { "right"; }).await; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut guard` maybe used later + | ^^^^^^ await occurs here, with `mut guard` maybe used later LL | *guard += 1; LL | } | - `mut guard` is later dropped here diff --git a/src/test/ui/async-await/issues/issue-51719.stderr b/src/test/ui/async-await/issues/issue-51719.stderr index 5b9adb253d968..19cc339ec0a07 100644 --- a/src/test/ui/async-await/issues/issue-51719.stderr +++ b/src/test/ui/async-await/issues/issue-51719.stderr @@ -1,8 +1,8 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-51719.rs:8:19 + --> $DIR/issue-51719.rs:8:25 | LL | let _gen = || foo().await; - | -- ^^^^^^^^^^^ only allowed inside `async` functions and blocks + | -- ^^^^^ only allowed inside `async` functions and blocks | | | this is not `async` diff --git a/src/test/ui/async-await/issues/issue-51751.stderr b/src/test/ui/async-await/issues/issue-51751.stderr index f120bd119c540..6dd3726608ba8 100644 --- a/src/test/ui/async-await/issues/issue-51751.stderr +++ b/src/test/ui/async-await/issues/issue-51751.stderr @@ -1,11 +1,11 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-51751.rs:9:20 + --> $DIR/issue-51751.rs:9:27 | LL | fn main() { | ---- this is not `async` LL | let result = inc(10000); LL | let finished = result.await; - | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-62009-1.rs b/src/test/ui/async-await/issues/issue-62009-1.rs index 3ee7ab2e9d12f..71108b4e1d856 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.rs +++ b/src/test/ui/async-await/issues/issue-62009-1.rs @@ -6,10 +6,11 @@ fn main() { async { let (); }.await; //~^ ERROR `await` is only allowed inside `async` functions and blocks async { - //~^ ERROR `await` is only allowed inside `async` functions and blocks let task1 = print_dur().await; }.await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks (|_| 2333).await; //~^ ERROR `await` is only allowed inside `async` functions and blocks - //~^^ ERROR + //~| ERROR is not a future + //~| ERROR is not a future } diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index 19d6f9bc43866..c09903e48c602 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -1,43 +1,54 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-62009-1.rs:6:5 + --> $DIR/issue-62009-1.rs:6:23 | LL | fn main() { | ---- this is not `async` LL | async { let (); }.await; - | ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-62009-1.rs:8:5 + --> $DIR/issue-62009-1.rs:10:7 | -LL | fn main() { - | ---- this is not `async` +LL | fn main() { + | ---- this is not `async` ... -LL | / async { -LL | | -LL | | let task1 = print_dur().await; -LL | | }.await; - | |___________^ only allowed inside `async` functions and blocks +LL | }.await; + | ^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-62009-1.rs:12:5 + --> $DIR/issue-62009-1.rs:12:16 | LL | fn main() { | ---- this is not `async` ... LL | (|_| 2333).await; - | ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future - --> $DIR/issue-62009-1.rs:12:5 + --> $DIR/issue-62009-1.rs:12:16 | LL | (|_| 2333).await; - | ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future + | ^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future | = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` -error: aborting due to 4 previous errors +error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future + --> $DIR/issue-62009-1.rs:12:15 + | +LL | (|_| 2333).await; + | ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future + | + = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` + = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited +help: do not `.await` the expression + | +LL - (|_| 2333).await; +LL + (|_| 2333); + | + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0277, E0728. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issues/issue-62009-2.stderr b/src/test/ui/async-await/issues/issue-62009-2.stderr index 47b74b5574fea..9c2f20df6576f 100644 --- a/src/test/ui/async-await/issues/issue-62009-2.stderr +++ b/src/test/ui/async-await/issues/issue-62009-2.stderr @@ -1,10 +1,10 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-62009-2.rs:8:5 + --> $DIR/issue-62009-2.rs:8:23 | LL | fn main() { | ---- this is not `async` LL | (async || 2333)().await; - | ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr index 6ebefbebe5362..cac174061a2b5 100644 --- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -6,16 +6,12 @@ LL | assert_send(async { | = help: within `impl Future`, the trait `Send` is not implemented for `*const u8` note: future is not `Send` as this value is used across an await - --> $DIR/issue-65436-raw-ptr-not-send.rs:14:9 + --> $DIR/issue-65436-raw-ptr-not-send.rs:14:35 | LL | bar(Foo(std::ptr::null())).await; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ first, await occurs here, with `std::ptr::null()` maybe used later... -note: `std::ptr::null()` is later dropped here - --> $DIR/issue-65436-raw-ptr-not-send.rs:14:41 - | -LL | bar(Foo(std::ptr::null())).await; - | ---------------- ^ - | | + | ---------------- ^^^^^^- `std::ptr::null()` is later dropped here + | | | + | | await occurs here, with `std::ptr::null()` maybe used later | has type `*const u8` which is not `Send` help: consider moving this into a `let` binding to create a shorter lived borrow --> $DIR/issue-65436-raw-ptr-not-send.rs:14:13 diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr index f826a86f08985..b6583022c161a 100644 --- a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr @@ -1,11 +1,11 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/non-async-enclosing-span.rs:9:13 + --> $DIR/non-async-enclosing-span.rs:9:28 | LL | fn main() { | ---- this is not `async` LL | let x = move || {}; LL | let y = do_the_thing().await; - | ^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 3cca9616a358a..a812840d40b88 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -39,7 +39,7 @@ LL | dummy(); | + error[E0308]: `if` and `else` have incompatible types - --> $DIR/suggest-missing-await.rs:35:9 + --> $DIR/suggest-missing-await.rs:35:17 | LL | let _x = if true { | ______________- @@ -48,7 +48,7 @@ LL | | dummy() LL | | LL | | } else { LL | | dummy().await - | | ^^^^^^^^^^^^^ expected opaque type, found `()` + | | ^^^^^ expected opaque type, found `()` LL | | LL | | }; | |_____- `if` and `else` have incompatible types @@ -61,7 +61,7 @@ LL | dummy().await | ++++++ error[E0308]: `match` arms have incompatible types - --> $DIR/suggest-missing-await.rs:45:14 + --> $DIR/suggest-missing-await.rs:45:22 | LL | let _x = match 0usize { | ______________- @@ -70,7 +70,7 @@ LL | | 0 => dummy(), LL | | 1 => dummy(), | | ------- this is found to be of type `impl Future` LL | | 2 => dummy().await, - | | ^^^^^^^^^^^^^ expected opaque type, found `()` + | | ^^^^^ expected opaque type, found `()` LL | | LL | | }; | |_____- `match` arms have incompatible types diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr index 130667a49c53a..8c0ecb8785d33 100644 --- a/src/test/ui/async-await/unresolved_type_param.stderr +++ b/src/test/ui/async-await/unresolved_type_param.stderr @@ -5,10 +5,10 @@ LL | bar().await; | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` - --> $DIR/unresolved_type_param.rs:9:5 + --> $DIR/unresolved_type_param.rs:9:10 | LL | bar().await; - | ^^^^^^^^^^^ + | ^^^^^^ error[E0698]: type inside `async fn` body must be known in this context --> $DIR/unresolved_type_param.rs:9:5 @@ -17,10 +17,10 @@ LL | bar().await; | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` - --> $DIR/unresolved_type_param.rs:9:5 + --> $DIR/unresolved_type_param.rs:9:10 | LL | bar().await; - | ^^^^^^^^^^^ + | ^^^^^^ error[E0698]: type inside `async fn` body must be known in this context --> $DIR/unresolved_type_param.rs:9:5 @@ -29,10 +29,10 @@ LL | bar().await; | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` - --> $DIR/unresolved_type_param.rs:9:5 + --> $DIR/unresolved_type_param.rs:9:10 | LL | bar().await; - | ^^^^^^^^^^^ + | ^^^^^^ error[E0698]: type inside `async fn` body must be known in this context --> $DIR/unresolved_type_param.rs:9:5 @@ -41,10 +41,10 @@ LL | bar().await; | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` - --> $DIR/unresolved_type_param.rs:9:5 + --> $DIR/unresolved_type_param.rs:9:10 | LL | bar().await; - | ^^^^^^^^^^^ + | ^^^^^^ error[E0698]: type inside `async fn` body must be known in this context --> $DIR/unresolved_type_param.rs:9:5 @@ -53,10 +53,10 @@ LL | bar().await; | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` - --> $DIR/unresolved_type_param.rs:9:5 + --> $DIR/unresolved_type_param.rs:9:10 | LL | bar().await; - | ^^^^^^^^^^^ + | ^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/lint/must_not_suspend/boxed.stderr b/src/test/ui/lint/must_not_suspend/boxed.stderr index edc62b6d687ad..b3c9b43810cd9 100644 --- a/src/test/ui/lint/must_not_suspend/boxed.stderr +++ b/src/test/ui/lint/must_not_suspend/boxed.stderr @@ -4,7 +4,7 @@ error: boxed `Umm` held across a suspend point, but should not be LL | let _guard = bar(); | ^^^^^^ LL | other().await; - | ------------- the value is held across this suspend point + | ------ the value is held across this suspend point | note: the lint level is defined here --> $DIR/boxed.rs:3:9 diff --git a/src/test/ui/lint/must_not_suspend/dedup.stderr b/src/test/ui/lint/must_not_suspend/dedup.stderr index 542b7a3bc7e98..bc1b611299a2b 100644 --- a/src/test/ui/lint/must_not_suspend/dedup.stderr +++ b/src/test/ui/lint/must_not_suspend/dedup.stderr @@ -2,7 +2,7 @@ error: `No` held across a suspend point, but should not be --> $DIR/dedup.rs:16:12 | LL | wheeee(No {}).await; - | -------^^^^^------- the value is held across this suspend point + | ^^^^^ ------ the value is held across this suspend point | note: the lint level is defined here --> $DIR/dedup.rs:3:9 diff --git a/src/test/ui/lint/must_not_suspend/gated.stderr b/src/test/ui/lint/must_not_suspend/gated.stderr index be077deb3f197..0d4319670e662 100644 --- a/src/test/ui/lint/must_not_suspend/gated.stderr +++ b/src/test/ui/lint/must_not_suspend/gated.stderr @@ -31,7 +31,7 @@ error: `MutexGuard` held across a suspend point, but should not be LL | let _guard = m.lock().unwrap(); | ^^^^^^ LL | other().await; - | ------------- the value is held across this suspend point + | ------ the value is held across this suspend point | note: the lint level is defined here --> $DIR/gated.rs:2:9 diff --git a/src/test/ui/lint/must_not_suspend/mutex.stderr b/src/test/ui/lint/must_not_suspend/mutex.stderr index dde506c19e725..a968b7ca0330f 100644 --- a/src/test/ui/lint/must_not_suspend/mutex.stderr +++ b/src/test/ui/lint/must_not_suspend/mutex.stderr @@ -4,7 +4,7 @@ error: `MutexGuard` held across a suspend point, but should not be LL | let _guard = m.lock().unwrap(); | ^^^^^^ LL | other().await; - | ------------- the value is held across this suspend point + | ------ the value is held across this suspend point | note: the lint level is defined here --> $DIR/mutex.rs:3:9 diff --git a/src/test/ui/lint/must_not_suspend/ref.stderr b/src/test/ui/lint/must_not_suspend/ref.stderr index 78b44b00625d1..6d30f134ec421 100644 --- a/src/test/ui/lint/must_not_suspend/ref.stderr +++ b/src/test/ui/lint/must_not_suspend/ref.stderr @@ -5,7 +5,7 @@ LL | let guard = &mut self.u; | ^^^^^^ LL | LL | other().await; - | ------------- the value is held across this suspend point + | ------ the value is held across this suspend point | note: the lint level is defined here --> $DIR/ref.rs:3:9 diff --git a/src/test/ui/lint/must_not_suspend/trait.stderr b/src/test/ui/lint/must_not_suspend/trait.stderr index d19ffddd482e0..dd3978b02a852 100644 --- a/src/test/ui/lint/must_not_suspend/trait.stderr +++ b/src/test/ui/lint/must_not_suspend/trait.stderr @@ -5,7 +5,7 @@ LL | let _guard1 = r#impl(); | ^^^^^^^ ... LL | other().await; - | ------------- the value is held across this suspend point + | ------ the value is held across this suspend point | note: the lint level is defined here --> $DIR/trait.rs:3:9 @@ -25,7 +25,7 @@ LL | let _guard2 = r#dyn(); | ^^^^^^^ LL | LL | other().await; - | ------------- the value is held across this suspend point + | ------ the value is held across this suspend point | help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point --> $DIR/trait.rs:22:9 diff --git a/src/test/ui/lint/must_not_suspend/unit.stderr b/src/test/ui/lint/must_not_suspend/unit.stderr index 425c076823d2f..42d037b350b19 100644 --- a/src/test/ui/lint/must_not_suspend/unit.stderr +++ b/src/test/ui/lint/must_not_suspend/unit.stderr @@ -4,7 +4,7 @@ error: `Umm` held across a suspend point, but should not be LL | let _guard = bar(); | ^^^^^^ LL | other().await; - | ------------- the value is held across this suspend point + | ------ the value is held across this suspend point | note: the lint level is defined here --> $DIR/unit.rs:3:9 diff --git a/src/test/ui/lint/must_not_suspend/warn.stderr b/src/test/ui/lint/must_not_suspend/warn.stderr index 42374d4acac27..417c397dad010 100644 --- a/src/test/ui/lint/must_not_suspend/warn.stderr +++ b/src/test/ui/lint/must_not_suspend/warn.stderr @@ -4,7 +4,7 @@ warning: `Umm` held across a suspend point, but should not be LL | let _guard = bar(); | ^^^^^^ LL | other().await; - | ------------- the value is held across this suspend point + | ------ the value is held across this suspend point | note: the lint level is defined here --> $DIR/warn.rs:4:9 From f0026106470c3a2c452ebe91582ab454062be935 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 01:46:28 +0000 Subject: [PATCH 09/38] Reduce verbosity when calling `for`-loop on non-`Iterator` expression --- compiler/rustc_middle/src/traits/mod.rs | 2 ++ .../src/traits/error_reporting/suggestions.rs | 7 +++++-- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 4 ++-- src/test/ui/issues/issue-33941.stderr | 6 +++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 5173d7e2a51dc..ee7e5a1f78eac 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -350,6 +350,8 @@ pub enum ObligationCauseCode<'tcx> { AwaitableExpr, + ForLoopIterator, + /// Well-formed checking. If a `WellFormedLoc` is provided, /// then it will be used to eprform HIR-based wf checking /// after an error occurs, in order to generate a more precise error span. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 957b8c379a39b..7bc67ca5380a2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -887,8 +887,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let span = obligation.cause.span; if let ObligationCauseCode::AwaitableExpr = obligation.cause.code { - // FIXME: use `trait_ref.self_ty().no_bound_vars()` to typecheck if `()` and if not - // maybe suggest returning instead? + // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` + // and if not maybe suggest doing something else? If we kept the expression around we + // could also check if it is an fn call (very likely) and suggest changing *that*, if + // it is from the local crate. err.span_suggestion_verbose( span, "do not `.await` the expression", @@ -1961,6 +1963,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(_) | ObligationCauseCode::AwaitableExpr + | ObligationCauseCode::ForLoopIterator | ObligationCauseCode::LetElse => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index de713b7de2e5f..50c2c33349104 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -816,8 +816,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &substs, match lang_item { hir::LangItem::FuturePoll => ObligationCauseCode::AwaitableExpr, - // FIXME: see if there are other obligation specializations we could do here beyond - // what we do above for `.await`. + hir::LangItem::IntoIterIntoIter => ObligationCauseCode::ForLoopIterator, + // FIXME: This could also be used for `?`. See if there are others. _ => traits::ItemObligation(def_id), }, ); diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index eb98a3a29a698..c6650d60c21e9 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -16,10 +16,10 @@ error[E0271]: type mismatch resolving ` $DIR/issue-33941.rs:4:14 | LL | for _ in HashMap::new().iter().cloned() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference | - = note: expected reference `&_` - found tuple `(&_, &_)` + = note: expected tuple `(&_, &_)` + found reference `&_` = note: required because of the requirements on the impl of `Iterator` for `Cloned>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned>` From f0608fc34f54c0bb9768403d070175791c720ef5 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 02:17:57 +0000 Subject: [PATCH 10/38] Reduce verbosity for `?` on non-`Try` expressions --- compiler/rustc_middle/src/traits/mod.rs | 2 ++ .../src/traits/error_reporting/suggestions.rs | 1 + .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 2 +- library/core/src/ops/try_trait.rs | 18 ++++-------------- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index ee7e5a1f78eac..468b6f379decb 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -352,6 +352,8 @@ pub enum ObligationCauseCode<'tcx> { ForLoopIterator, + QuestionMark, + /// Well-formed checking. If a `WellFormedLoc` is provided, /// then it will be used to eprform HIR-based wf checking /// after an error occurs, in order to generate a more precise error span. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 7bc67ca5380a2..a2730ecc90d11 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1964,6 +1964,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::BlockTailExpression(_) | ObligationCauseCode::AwaitableExpr | ObligationCauseCode::ForLoopIterator + | ObligationCauseCode::QuestionMark | ObligationCauseCode::LetElse => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 50c2c33349104..99c9a3fe827ed 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -817,7 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match lang_item { hir::LangItem::FuturePoll => ObligationCauseCode::AwaitableExpr, hir::LangItem::IntoIterIntoIter => ObligationCauseCode::ForLoopIterator, - // FIXME: This could also be used for `?`. See if there are others. + hir::LangItem::TryTraitBranch => ObligationCauseCode::QuestionMark, _ => traits::ItemObligation(def_id), }, ); diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index f4f0a5898097f..6a414ae8c4b80 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -115,15 +115,14 @@ use crate::ops::ControlFlow; #[unstable(feature = "try_trait_v2", issue = "84277")] #[rustc_on_unimplemented( on( - all(from_method = "from_output", from_desugaring = "TryBlock"), + all(from_desugaring = "TryBlock"), message = "a `try` block must return `Result` or `Option` \ (or another type that implements `{Try}`)", label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", ), on( - all(from_method = "branch", from_desugaring = "QuestionMark"), - message = "the `?` operator can only be applied to values \ - that implement `{Try}`", + all(from_desugaring = "QuestionMark"), + message = "the `?` operator can only be applied to values that implement `{Try}`", label = "the `?` operator cannot be applied to type `{Self}`" ) )] @@ -226,7 +225,6 @@ pub trait Try: FromResidual { #[rustc_on_unimplemented( on( all( - from_method = "from_residual", from_desugaring = "QuestionMark", _Self = "std::result::Result", R = "std::option::Option" @@ -238,7 +236,6 @@ pub trait Try: FromResidual { ), on( all( - from_method = "from_residual", from_desugaring = "QuestionMark", _Self = "std::result::Result", ), @@ -252,7 +249,6 @@ pub trait Try: FromResidual { ), on( all( - from_method = "from_residual", from_desugaring = "QuestionMark", _Self = "std::option::Option", R = "std::result::Result", @@ -264,7 +260,6 @@ pub trait Try: FromResidual { ), on( all( - from_method = "from_residual", from_desugaring = "QuestionMark", _Self = "std::option::Option", ), @@ -277,7 +272,6 @@ pub trait Try: FromResidual { ), on( all( - from_method = "from_residual", from_desugaring = "QuestionMark", _Self = "std::ops::ControlFlow", R = "std::ops::ControlFlow", @@ -290,7 +284,6 @@ pub trait Try: FromResidual { ), on( all( - from_method = "from_residual", from_desugaring = "QuestionMark", _Self = "std::ops::ControlFlow", // `R` is not a `ControlFlow`, as that case was matched previously @@ -301,10 +294,7 @@ pub trait Try: FromResidual { enclosing_scope = "this function returns a `ControlFlow`", ), on( - all( - from_method = "from_residual", - from_desugaring = "QuestionMark" - ), + all(from_desugaring = "QuestionMark"), message = "the `?` operator can only be used in {ItemContext} \ that returns `Result` or `Option` \ (or another type that implements `{FromResidual}`)", From 51d3489e3d7b527a925f84ffbf04e059c208dccf Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 02:27:18 +0000 Subject: [PATCH 11/38] Further silence `?` errors --- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 99c9a3fe827ed..a01b6f95c8918 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -817,7 +817,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match lang_item { hir::LangItem::FuturePoll => ObligationCauseCode::AwaitableExpr, hir::LangItem::IntoIterIntoIter => ObligationCauseCode::ForLoopIterator, - hir::LangItem::TryTraitBranch => ObligationCauseCode::QuestionMark, + hir::LangItem::TryTraitFromResidual | hir::LangItem::TryTraitBranch => { + ObligationCauseCode::QuestionMark + } _ => traits::ItemObligation(def_id), }, ); From 335a6e282638429f6e5a04cbb124e21ca1398360 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 02:50:30 +0000 Subject: [PATCH 12/38] Remove yet more output from `for`-loop and `?` errors --- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 9 +++++---- src/test/ui/issues/issue-33941.stderr | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index a01b6f95c8918..fb4ced96b2177 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -816,11 +816,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &substs, match lang_item { hir::LangItem::FuturePoll => ObligationCauseCode::AwaitableExpr, - hir::LangItem::IntoIterIntoIter => ObligationCauseCode::ForLoopIterator, - hir::LangItem::TryTraitFromResidual | hir::LangItem::TryTraitBranch => { - ObligationCauseCode::QuestionMark + hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => { + ObligationCauseCode::ForLoopIterator } - _ => traits::ItemObligation(def_id), + hir::LangItem::TryTraitFromOutput + | hir::LangItem::TryTraitFromResidual + | hir::LangItem::TryTraitBranch => ObligationCauseCode::QuestionMark, }, ); (Res::Def(def_kind, def_id), ty) diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index c6650d60c21e9..52341517756ca 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -23,6 +23,20 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: required because of the requirements on the impl of `Iterator` for `Cloned>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned>` +<<<<<<< HEAD error: aborting due to 2 previous errors +======= +error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` + --> $DIR/issue-33941.rs:4:14 + | +LL | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference + | + = note: expected tuple `(&_, &_)` + found reference `&_` + = note: required because of the requirements on the impl of `Iterator` for `Cloned>` + +error: aborting due to 3 previous errors +>>>>>>> 330b90f5fc1 (Remove yet more output from `for`-loop and `?` errors) For more information about this error, try `rustc --explain E0271`. From 26b1f6c678b91cfe976c1281154c551263f13549 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 03:03:00 +0000 Subject: [PATCH 13/38] Remove unnecessary argument --- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 791053670ad26..14fadb51b4b07 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1146,7 +1146,7 @@ impl<'a> Parser<'a> { /// Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) { - return Ok(self.mk_await_expr(self_arg, lo)); + return Ok(self.mk_await_expr(self_arg)); } let fn_span_lo = self.token.span; @@ -2831,7 +2831,7 @@ impl<'a> Parser<'a> { ExprKind::Call(f, args) } - fn mk_await_expr(&mut self, self_arg: P, _lo: Span) -> P { + fn mk_await_expr(&mut self, self_arg: P) -> P { let span = self.prev_token.span; let await_expr = self.mk_expr(span, ExprKind::Await(self_arg), AttrVec::new()); self.recover_from_await_method_call(); From fa156c29531a5d42fb590e8c1ec5797f3e09a32e Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 03:04:36 +0000 Subject: [PATCH 14/38] Fix mistake --- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index fb4ced96b2177..f810d8ab478af 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -822,6 +822,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::LangItem::TryTraitFromOutput | hir::LangItem::TryTraitFromResidual | hir::LangItem::TryTraitBranch => ObligationCauseCode::QuestionMark, + _ => traits::ItemObligation(def_id), }, ); (Res::Def(def_kind, def_id), ty) From 4f5ba7a3c3bb17ef959b679ffb83746ebfa9d93b Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 20:07:23 +0000 Subject: [PATCH 15/38] Keep info on pre-desugaring expression for better "incorrect `.await`" suggestion Keep the `HirId` of `.await`ed expressions so in the case of a `fn` call on on a sync `fn`, we can suggest maybe turning it into an `async fn`. --- compiler/rustc_ast_lowering/src/expr.rs | 51 +++++++++++++++---- compiler/rustc_ast_lowering/src/lib.rs | 11 ++-- compiler/rustc_hir/src/hir.rs | 14 ++--- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_lint/src/array_into_iter.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 2 +- compiler/rustc_save_analysis/src/sig.rs | 2 +- .../src/traits/error_reporting/suggestions.rs | 38 +++++++++++++- compiler/rustc_typeck/src/astconv/mod.rs | 2 +- compiler/rustc_typeck/src/check/expr.rs | 7 +-- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 3 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 4 +- src/test/ui/async-await/unnecessary-await.rs | 14 +++++ .../ui/async-await/unnecessary-await.stderr | 22 ++++++++ 14 files changed, 138 insertions(+), 36 deletions(-) create mode 100644 src/test/ui/async-await/unnecessary-await.rs create mode 100644 src/test/ui/async-await/unnecessary-await.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2cf0dbaf425b8..16fdd714575d4 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -479,8 +479,12 @@ impl<'hir> LoweringContext<'_, 'hir> { expr: &'hir hir::Expr<'hir>, overall_span: Span, ) -> &'hir hir::Expr<'hir> { - let constructor = - self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, ThinVec::new())); + let constructor = self.arena.alloc(self.expr_lang_item_path( + method_span, + lang_item, + ThinVec::new(), + None, + )); self.expr_call(overall_span, constructor, std::slice::from_ref(expr)) } @@ -584,8 +588,12 @@ impl<'hir> LoweringContext<'_, 'hir> { // `future::from_generator`: let unstable_span = self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let gen_future = - self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator, ThinVec::new()); + let gen_future = self.expr_lang_item_path( + unstable_span, + hir::LangItem::FromGenerator, + ThinVec::new(), + None, + ); // `future::from_generator(generator)`: hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator]) @@ -657,16 +665,19 @@ impl<'hir> LoweringContext<'_, 'hir> { span, hir::LangItem::PinNewUnchecked, arena_vec![self; ref_mut_pinned], + Some(expr.hir_id), ); let get_context = self.expr_call_lang_item_fn_mut( gen_future_span, hir::LangItem::GetContext, arena_vec![self; task_context], + Some(expr.hir_id), ); let call = self.expr_call_lang_item_fn( span, hir::LangItem::FuturePoll, arena_vec![self; new_unchecked, get_context], + Some(expr.hir_id), ); self.arena.alloc(self.expr_unsafe(call)) }; @@ -679,7 +690,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident); let x_expr = self.expr_ident(span, x_ident, x_pat_hid); let ready_field = self.single_pat_field(span, x_pat); - let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); + let ready_pat = self.pat_lang_item_variant( + span, + hir::LangItem::PollReady, + ready_field, + Some(expr.hir_id), + ); let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); @@ -690,7 +706,12 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::task::Poll::Pending => {}` let pending_arm = { - let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]); + let pending_pat = self.pat_lang_item_variant( + span, + hir::LangItem::PollPending, + &[], + Some(expr.hir_id), + ); let empty_block = self.expr_block_empty(span); self.arm(pending_pat, empty_block) }; @@ -1161,7 +1182,8 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> { let e1 = self.lower_expr_mut(e1); let e2 = self.lower_expr_mut(e2); - let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span)); + let fn_path = + hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None); let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]) @@ -1195,7 +1217,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ExprKind::Struct( - self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))), + self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span), None)), fields, None, ) @@ -1390,6 +1412,7 @@ impl<'hir> LoweringContext<'_, 'hir> { head_span, hir::LangItem::IteratorNext, arena_vec![self; ref_mut_iter], + None, ); let arms = arena_vec![self; none_arm, some_arm]; @@ -1418,6 +1441,7 @@ impl<'hir> LoweringContext<'_, 'hir> { head_span, hir::LangItem::IntoIterIntoIter, arena_vec![self; head], + None, ) }; @@ -1473,6 +1497,7 @@ impl<'hir> LoweringContext<'_, 'hir> { unstable_span, hir::LangItem::TryTraitBranch, arena_vec![self; sub_expr], + None, ) }; @@ -1629,8 +1654,10 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, lang_item: hir::LangItem, args: &'hir [hir::Expr<'hir>], + hir_id: Option, ) -> hir::Expr<'hir> { - let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new())); + let path = + self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new(), hir_id)); self.expr_call_mut(span, path, args) } @@ -1639,8 +1666,9 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, lang_item: hir::LangItem, args: &'hir [hir::Expr<'hir>], + hir_id: Option, ) -> &'hir hir::Expr<'hir> { - self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args)) + self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args, hir_id)) } fn expr_lang_item_path( @@ -1648,10 +1676,11 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, lang_item: hir::LangItem, attrs: AttrVec, + hir_id: Option, ) -> hir::Expr<'hir> { self.expr( span, - hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))), + hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id)), attrs, ) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d0fbc2d0f11d4..55a7e07933159 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2140,21 +2140,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field) + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field, None) } fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field) + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field, None) } fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field) + self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field, None) } fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> { - self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[]) + self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[], None) } fn single_pat_field( @@ -2177,8 +2177,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, lang_item: hir::LangItem, fields: &'hir [hir::PatField<'hir>], + hir_id: Option, ) -> &'hir hir::Pat<'hir> { - let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span)); + let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id); self.pat(span, hir::PatKind::Struct(qpath, fields, false)) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 487ae87052ba3..44564b58b145c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1629,13 +1629,13 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { | LangItem::RangeFrom | LangItem::RangeFull | LangItem::RangeToInclusive, - _, + .. ) ), // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. ExprKind::Call(ref func, _) => { - matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _))) + matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..))) } _ => false, @@ -1790,8 +1790,8 @@ pub enum QPath<'hir> { /// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`. TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>), - /// Reference to a `#[lang = "foo"]` item. - LangItem(LangItem, Span), + /// Reference to a `#[lang = "foo"]` item. `HirId` of the inner expr. + LangItem(LangItem, Span, Option), } impl<'hir> QPath<'hir> { @@ -1800,7 +1800,7 @@ impl<'hir> QPath<'hir> { match *self { QPath::Resolved(_, path) => path.span, QPath::TypeRelative(qself, ps) => qself.span.to(ps.ident.span), - QPath::LangItem(_, span) => span, + QPath::LangItem(_, span, _) => span, } } @@ -1810,7 +1810,7 @@ impl<'hir> QPath<'hir> { match *self { QPath::Resolved(_, path) => path.span, QPath::TypeRelative(qself, _) => qself.span, - QPath::LangItem(_, span) => span, + QPath::LangItem(_, span, _) => span, } } @@ -1820,7 +1820,7 @@ impl<'hir> QPath<'hir> { match *self { QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span, QPath::TypeRelative(_, segment) => segment.ident.span, - QPath::LangItem(_, span) => span, + QPath::LangItem(_, span, _) => span, } } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 4240a4045a1ec..419d28cfa44de 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1733,7 +1733,7 @@ impl<'a> State<'a> { colons_before_params, ) } - hir::QPath::LangItem(lang_item, span) => { + hir::QPath::LangItem(lang_item, span, _) => { self.word("#[lang = \""); self.print_ident(Ident::new(lang_item.name(), span)); self.word("\"]"); diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 4a24f803e8463..b6151757588dd 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { if let hir::ExprKind::Call(path, [arg]) = &arg.kind { if let hir::ExprKind::Path(hir::QPath::LangItem( hir::LangItem::IntoIterIntoIter, - _, + .., )) = &path.kind { self.for_expr_span = arg.span; diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 468b6f379decb..f3c4ade3ba8e3 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -348,7 +348,7 @@ pub enum ObligationCauseCode<'tcx> { /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` OpaqueType, - AwaitableExpr, + AwaitableExpr(Option), ForLoopIterator, diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 7864b47ab0a7f..1d9c44bffa3fc 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -286,7 +286,7 @@ impl<'hir> Sig for hir::Ty<'hir> { refs: vec![SigElement { id, start, end }], }) } - hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => { + hir::TyKind::Path(hir::QPath::LangItem(lang_item, _, _)) => { Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name()))) } hir::TyKind::TraitObject(bounds, ..) => { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index a2730ecc90d11..34fbff62a65bc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -886,7 +886,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) { let span = obligation.cause.span; - if let ObligationCauseCode::AwaitableExpr = obligation.cause.code { + if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code { // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` // and if not maybe suggest doing something else? If we kept the expression around we // could also check if it is an fn call (very likely) and suggest changing *that*, if @@ -897,6 +897,40 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { String::new(), Applicability::MachineApplicable, ); + // FIXME: account for associated `async fn`s. + let hir = self.tcx.hir(); + if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) { + if let hir::Node::Expr(hir::Expr { + span, kind: hir::ExprKind::Call(base, _), .. + }) = node + { + if let ty::PredicateKind::Trait(pred) = + obligation.predicate.kind().skip_binder() + { + err.span_label(*span, &format!("this call returns `{}`", pred.self_ty())); + } + if let Some(typeck_results) = + self.in_progress_typeck_results.map(|t| t.borrow()) + { + let ty = typeck_results.expr_ty_adjusted(base); + if let ty::FnDef(def_id, _substs) = ty.kind() { + if let Some(hir::Node::Item(hir::Item { span, ident, .. })) = + hir.get_if_local(*def_id) + { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "alternatively, consider making `fn {}` asynchronous", + ident + ), + "async ".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } } } @@ -1962,7 +1996,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(_) - | ObligationCauseCode::AwaitableExpr + | ObligationCauseCode::AwaitableExpr(_) | ObligationCauseCode::ForLoopIterator | ObligationCauseCode::QuestionMark | ObligationCauseCode::LetElse => {} diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 08261fedd4a25..1316b454fa88c 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2355,7 +2355,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|(ty, _, _)| ty) .unwrap_or_else(|_| tcx.ty_error()) } - hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { + hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => { let def_id = tcx.require_lang_item(lang_item, Some(span)); let (substs, _) = self.create_substs_for_ast_path( span, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 311106474bea0..bc6ad3c968671 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -277,8 +277,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::AddrOf(kind, mutbl, oprnd) => { self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) } - ExprKind::Path(QPath::LangItem(lang_item, _)) => { - self.check_lang_item_path(lang_item, expr) + ExprKind::Path(QPath::LangItem(lang_item, _, hir_id)) => { + self.check_lang_item_path(lang_item, expr, hir_id) } ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]), ExprKind::InlineAsm(asm) => self.check_expr_asm(asm), @@ -498,8 +498,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, lang_item: hir::LangItem, expr: &'tcx hir::Expr<'tcx>, + hir_id: Option, ) -> Ty<'tcx> { - self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1 + self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id, hir_id).1 } pub(crate) fn check_expr_path( diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index f810d8ab478af..a101166fff1b4 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -797,6 +797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lang_item: hir::LangItem, span: Span, hir_id: hir::HirId, + expr_hir_id: Option, ) -> (Res, Ty<'tcx>) { let def_id = self.tcx.require_lang_item(lang_item, Some(span)); let def_kind = self.tcx.def_kind(def_id); @@ -815,7 +816,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_id, &substs, match lang_item { - hir::LangItem::FuturePoll => ObligationCauseCode::AwaitableExpr, + hir::LangItem::FuturePoll => ObligationCauseCode::AwaitableExpr(expr_hir_id), hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => { ObligationCauseCode::ForLoopIterator } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 74d7f0a80b6ca..3220c1bc2249a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -938,8 +938,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) } - QPath::LangItem(lang_item, span) => { - self.resolve_lang_item_path(lang_item, span, hir_id) + QPath::LangItem(lang_item, span, id) => { + self.resolve_lang_item_path(lang_item, span, hir_id, id) } } } diff --git a/src/test/ui/async-await/unnecessary-await.rs b/src/test/ui/async-await/unnecessary-await.rs new file mode 100644 index 0000000000000..70c38aaeb2511 --- /dev/null +++ b/src/test/ui/async-await/unnecessary-await.rs @@ -0,0 +1,14 @@ +// edition:2018 + +async fn foo () { } +fn bar () -> impl std::future::Future { async {} } +fn boo () {} + +async fn baz() -> std::io::Result<()> { + foo().await; + boo().await; //~ ERROR `()` is not a future + bar().await; + std::io::Result::Ok(()) +} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/async-await/unnecessary-await.stderr b/src/test/ui/async-await/unnecessary-await.stderr new file mode 100644 index 0000000000000..4caa15e67b7c9 --- /dev/null +++ b/src/test/ui/async-await/unnecessary-await.stderr @@ -0,0 +1,22 @@ +error[E0277]: `()` is not a future + --> $DIR/unnecessary-await.rs:9:10 + | +LL | boo().await; + | -----^^^^^^ `()` is not a future + | | + | this call returns `()` + | + = help: the trait `Future` is not implemented for `()` +help: do not `.await` the expression + | +LL - boo().await; +LL + boo(); + | +help: alternatively, consider making `fn boo` asynchronous + | +LL | async fn boo () {} + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From fc2298c0052cbfe54c36b775e62772799945096f Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 20:44:25 +0000 Subject: [PATCH 16/38] Fix clippy uses of QPath::LangItem --- .../clippy/clippy_lints/src/methods/str_splitn.rs | 2 +- .../clippy_lints/src/needless_question_mark.rs | 2 +- src/tools/clippy/clippy_lints/src/strings.rs | 2 +- src/tools/clippy/clippy_lints/src/try_err.rs | 2 +- .../clippy/clippy_lints/src/unused_io_amount.rs | 2 +- src/tools/clippy/clippy_lints/src/utils/author.rs | 2 +- src/tools/clippy/clippy_utils/src/higher.rs | 12 ++++++------ src/tools/clippy/clippy_utils/src/hir_utils.rs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 2595f734f1151..e5fafdb075c66 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -204,7 +204,7 @@ fn parse_iter_usage( match e.kind { ExprKind::Call( Expr { - kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)), + kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)), .. }, _, diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 1ffed6a052499..0e7ae43ce2dd5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -105,7 +105,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { }; if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind; if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; - if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind; + if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind; if expr.span.ctxt() == inner_expr.span.ctxt(); let expr_ty = cx.typeck_results().expr_ty(expr); let inner_ty = cx.typeck_results().expr_ty(inner_expr); diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 368274440d5dc..c2163a24b7f44 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -260,7 +260,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if method_names[0] == sym!(as_bytes); // Check for slicer - if let ExprKind::Struct(QPath::LangItem(LangItem::Range, _), _, _) = right.kind; + if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind; then { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs index e0e7ec9a452c1..4da32c52e750a 100644 --- a/src/tools/clippy/clippy_lints/src/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/try_err.rs @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind; if let ExprKind::Call(match_fun, try_args) = match_arg.kind; if let ExprKind::Path(ref match_fun_path) = match_fun.kind; - if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, _)); + if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..)); if let Some(try_arg) = try_args.get(0); if let ExprKind::Call(err_fun, err_args) = try_arg.kind; if let Some(err_arg) = err_args.get(0); diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index d4b5c9770a271..111413e51930b 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { if let hir::ExprKind::Call(func, [ref arg_0, ..]) = res.kind { if matches!( func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _)) + hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) ) { check_map_error(cx, arg_0, expr); } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index d20bf3413185c..f186e1f05a0b4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -260,7 +260,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } fn qpath(&self, qpath: &Binding<&QPath<'_>>) { - if let QPath::LangItem(lang_item, _) = *qpath.value { + if let QPath::LangItem(lang_item, ..) = *qpath.value { out!("if matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _));"); } else { out!("if match_qpath({qpath}, &[{}]);", path_to_string(qpath.value)); diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 7297265d08cfb..fc32e49420e4b 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -218,7 +218,7 @@ impl<'a> Range<'a> { hir::ExprKind::Call(path, args) if matches!( path.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _)) + hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..)) ) => { Some(Range { @@ -228,27 +228,27 @@ impl<'a> Range<'a> { }) }, hir::ExprKind::Struct(path, fields, None) => match &path { - hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range { + hir::QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range { start: None, end: None, limits: ast::RangeLimits::HalfOpen, }), - hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range { + hir::QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range { start: Some(get_field("start", fields)?), end: None, limits: ast::RangeLimits::HalfOpen, }), - hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range { + hir::QPath::LangItem(hir::LangItem::Range, ..) => Some(Range { start: Some(get_field("start", fields)?), end: Some(get_field("end", fields)?), limits: ast::RangeLimits::HalfOpen, }), - hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range { + hir::QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range { start: None, end: Some(get_field("end", fields)?), limits: ast::RangeLimits::Closed, }), - hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range { + hir::QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range { start: None, end: Some(get_field("end", fields)?), limits: ast::RangeLimits::HalfOpen, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 7438b6eabf9e6..5b059e3788699 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -346,7 +346,7 @@ impl HirEqInterExpr<'_, '_, '_> { (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => { self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg) }, - (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item, + (&QPath::LangItem(llang_item, ..), &QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item, _ => false, } } From 0ccf58b928c3197bb5531c422e3ad5c5bd899191 Mon Sep 17 00:00:00 2001 From: luojia65 Date: Thu, 9 Dec 2021 22:33:25 +0800 Subject: [PATCH 17/38] Update stdarch dependency --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 43b4556c44197..b70ae88ef2a6c 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 43b4556c44197af4ef82e42a12dfc513a1397f87 +Subproject commit b70ae88ef2a6c83acad0a1e83d5bd78f9655fd05 From a3cdbc4d91a8fda28c29f171ebf70ff1b522c871 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 22:06:25 +0000 Subject: [PATCH 18/38] Fix rebase and clippy tests --- compiler/rustc_ast_lowering/src/expr.rs | 24 ++++-- compiler/rustc_parse/src/parser/expr.rs | 6 +- compiler/rustc_passes/src/region.rs | 11 ++- .../src/traits/error_reporting/suggestions.rs | 78 ++++++++++--------- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 4 +- .../incorrect-syntax-suggestions.stderr | 32 ++++---- src/test/ui/async-await/issue-70594.rs | 1 - src/test/ui/async-await/issue-70594.stderr | 21 ++--- .../ui/async-await/issues/issue-51719.stderr | 4 +- .../ui/async-await/issues/issue-51751.stderr | 4 +- .../ui/async-await/issues/issue-62009-1.rs | 1 - .../async-await/issues/issue-62009-1.stderr | 25 ++---- .../async-await/issues/issue-62009-2.stderr | 4 +- .../issues/non-async-enclosing-span.stderr | 4 +- .../async-await/suggest-missing-await.stderr | 8 +- .../ui/async-await/unnecessary-await.stderr | 2 + src/test/ui/issues/issue-33941.stderr | 14 ---- .../clippy_lints/src/needless_late_init.rs | 11 ++- .../tests/ui/needless_late_init_fixable.fixed | 38 --------- .../tests/ui/needless_late_init_fixable.rs | 2 - .../ui/needless_late_init_fixable.stderr | 26 ++++--- 21 files changed, 136 insertions(+), 184 deletions(-) delete mode 100644 src/tools/clippy/tests/ui/needless_late_init_fixable.fixed diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 16fdd714575d4..75a45a437e77e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -130,7 +130,15 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AsyncGeneratorKind::Block, |this| this.with_new_scopes(|this| this.lower_block_expr(block)), ), - ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr), + ExprKind::Await(ref expr) => { + let span = if expr.span.hi() < e.span.hi() { + expr.span.shrink_to_hi().with_hi(e.span.hi()) + } else { + // this is a recovered `await expr` + e.span + }; + self.lower_expr_await(span, expr) + } ExprKind::Closure( capture_clause, asyncness, @@ -639,6 +647,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.allow_gen_future.clone(), ); let expr = self.lower_expr_mut(expr); + let expr_hir_id = expr.hir_id; let pinned_ident = Ident::with_dummy_span(sym::pinned); let (pinned_pat, pinned_pat_hid) = @@ -665,19 +674,19 @@ impl<'hir> LoweringContext<'_, 'hir> { span, hir::LangItem::PinNewUnchecked, arena_vec![self; ref_mut_pinned], - Some(expr.hir_id), + Some(expr_hir_id), ); let get_context = self.expr_call_lang_item_fn_mut( gen_future_span, hir::LangItem::GetContext, arena_vec![self; task_context], - Some(expr.hir_id), + Some(expr_hir_id), ); let call = self.expr_call_lang_item_fn( span, hir::LangItem::FuturePoll, arena_vec![self; new_unchecked, get_context], - Some(expr.hir_id), + Some(expr_hir_id), ); self.arena.alloc(self.expr_unsafe(call)) }; @@ -694,7 +703,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span, hir::LangItem::PollReady, ready_field, - Some(expr.hir_id), + Some(expr_hir_id), ); let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = @@ -710,7 +719,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span, hir::LangItem::PollPending, &[], - Some(expr.hir_id), + Some(expr_hir_id), ); let empty_block = self.expr_block_empty(span); self.arm(pending_pat, empty_block) @@ -731,7 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unit = self.expr_unit(span); let yield_expr = self.expr( span, - hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr.hir_id) }), + hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr_hir_id) }), ThinVec::new(), ); let yield_expr = self.arena.alloc(yield_expr); @@ -778,6 +787,7 @@ impl<'hir> LoweringContext<'_, 'hir> { into_future_span, hir::LangItem::IntoFutureIntoFuture, arena_vec![self; expr], + Some(expr_hir_id), ); // match { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 14fadb51b4b07..1dbd7bad0f023 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1146,7 +1146,7 @@ impl<'a> Parser<'a> { /// Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) { - return Ok(self.mk_await_expr(self_arg)); + return Ok(self.mk_await_expr(self_arg, lo)); } let fn_span_lo = self.token.span; @@ -2831,8 +2831,8 @@ impl<'a> Parser<'a> { ExprKind::Call(f, args) } - fn mk_await_expr(&mut self, self_arg: P) -> P { - let span = self.prev_token.span; + fn mk_await_expr(&mut self, self_arg: P, lo: Span) -> P { + let span = lo.to(self.prev_token.span); let await_expr = self.mk_expr(span, ExprKind::Await(self_arg), AttrVec::new()); self.recover_from_await_method_call(); await_expr diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index ae423070392e1..8968c163987dc 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -421,11 +421,14 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // Mark this expr's scope and all parent scopes as containing `yield`. let mut scope = Scope { id: expr.hir_id.local_id, data: ScopeData::Node }; loop { - let data = YieldData { - span: expr.span, - expr_and_pat_count: visitor.expr_and_pat_count, - source: *source, + let span = match expr.kind { + hir::ExprKind::Yield(expr, hir::YieldSource::Await { .. }) => { + expr.span.shrink_to_hi().to(expr.span) + } + _ => expr.span, }; + let data = + YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source }; visitor.scope_tree.yield_in_scope.insert(scope, data); if visitor.pessimistic_yield { debug!("resolve_expr in pessimistic_yield - marking scope {:?} for fixup", scope); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 34fbff62a65bc..67c0b88d7aad4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -886,46 +886,48 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) { let span = obligation.cause.span; - if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code { - // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` - // and if not maybe suggest doing something else? If we kept the expression around we - // could also check if it is an fn call (very likely) and suggest changing *that*, if - // it is from the local crate. - err.span_suggestion_verbose( - span, - "do not `.await` the expression", - String::new(), - Applicability::MachineApplicable, - ); - // FIXME: account for associated `async fn`s. + if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code.peel_derives() { let hir = self.tcx.hir(); if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) { - if let hir::Node::Expr(hir::Expr { - span, kind: hir::ExprKind::Call(base, _), .. - }) = node - { - if let ty::PredicateKind::Trait(pred) = - obligation.predicate.kind().skip_binder() - { - err.span_label(*span, &format!("this call returns `{}`", pred.self_ty())); - } - if let Some(typeck_results) = - self.in_progress_typeck_results.map(|t| t.borrow()) - { - let ty = typeck_results.expr_ty_adjusted(base); - if let ty::FnDef(def_id, _substs) = ty.kind() { - if let Some(hir::Node::Item(hir::Item { span, ident, .. })) = - hir.get_if_local(*def_id) - { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "alternatively, consider making `fn {}` asynchronous", - ident - ), - "async ".to_string(), - Applicability::MaybeIncorrect, - ); + if let hir::Node::Expr(expr) = node { + // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` + // and if not maybe suggest doing something else? If we kept the expression around we + // could also check if it is an fn call (very likely) and suggest changing *that*, if + // it is from the local crate. + err.span_suggestion_verbose( + expr.span.shrink_to_hi().with_hi(span.hi()), + "do not `.await` the expression", + String::new(), + Applicability::MachineApplicable, + ); + // FIXME: account for associated `async fn`s. + if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr { + if let ty::PredicateKind::Trait(pred) = + obligation.predicate.kind().skip_binder() + { + err.span_label( + *span, + &format!("this call returns `{}`", pred.self_ty()), + ); + } + if let Some(typeck_results) = + self.in_progress_typeck_results.map(|t| t.borrow()) + { + let ty = typeck_results.expr_ty_adjusted(base); + if let ty::FnDef(def_id, _substs) = ty.kind() { + if let Some(hir::Node::Item(hir::Item { span, ident, .. })) = + hir.get_if_local(*def_id) + { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "alternatively, consider making `fn {}` asynchronous", + ident + ), + "async ".to_string(), + Applicability::MaybeIncorrect, + ); + } } } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index a101166fff1b4..b4507c5857b69 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -816,7 +816,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_id, &substs, match lang_item { - hir::LangItem::FuturePoll => ObligationCauseCode::AwaitableExpr(expr_hir_id), + hir::LangItem::IntoFutureIntoFuture => { + ObligationCauseCode::AwaitableExpr(expr_hir_id) + } hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => { ObligationCauseCode::ForLoopIterator } diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 27f4b0dac618b..b4323c314badc 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -162,68 +162,68 @@ LL | let _ = (await bar())?; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:71:19 + --> $DIR/incorrect-syntax-suggestions.rs:71:18 | LL | fn foo13() -> Result<(), ()> { | ----- this is not `async` LL | let _ = bar().await(); - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:76:19 + --> $DIR/incorrect-syntax-suggestions.rs:76:18 | LL | fn foo14() -> Result<(), ()> { | ----- this is not `async` LL | let _ = bar().await()?; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:81:19 + --> $DIR/incorrect-syntax-suggestions.rs:81:18 | LL | fn foo15() -> Result<(), ()> { | ----- this is not `async` LL | let _ = bar().await; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:85:19 + --> $DIR/incorrect-syntax-suggestions.rs:85:18 | LL | fn foo16() -> Result<(), ()> { | ----- this is not `async` LL | let _ = bar().await?; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:90:23 + --> $DIR/incorrect-syntax-suggestions.rs:90:22 | LL | fn foo() -> Result<(), ()> { | --- this is not `async` LL | let _ = bar().await?; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:97:23 + --> $DIR/incorrect-syntax-suggestions.rs:97:22 | LL | let foo = || { | -- this is not `async` LL | let _ = bar().await?; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:113:17 + --> $DIR/incorrect-syntax-suggestions.rs:113:29 | LL | fn foo() -> Result<(), ()> { | --- this is not `async` LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/incorrect-syntax-suggestions.rs:121:17 + --> $DIR/incorrect-syntax-suggestions.rs:121:29 | LL | let foo = || { | -- this is not `async` LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + | ^ only allowed inside `async` functions and blocks error: aborting due to 33 previous errors diff --git a/src/test/ui/async-await/issue-70594.rs b/src/test/ui/async-await/issue-70594.rs index bfed4b0b05c6e..9e7c5847b3b2e 100644 --- a/src/test/ui/async-await/issue-70594.rs +++ b/src/test/ui/async-await/issue-70594.rs @@ -6,7 +6,6 @@ async fn fun() { //~| error: `.await` is not allowed in a `const` //~| error: `.await` is not allowed in a `const` //~| error: `()` is not a future - //~| error: `()` is not a future } fn main() {} diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr index a2d4257577e32..405709286822a 100644 --- a/src/test/ui/async-await/issue-70594.stderr +++ b/src/test/ui/async-await/issue-70594.stderr @@ -1,16 +1,16 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-70594.rs:4:12 + --> $DIR/issue-70594.rs:4:11 | LL | async fn fun() { | --- this is not `async` LL | [1; ().await]; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0744]: `.await` is not allowed in a `const` - --> $DIR/issue-70594.rs:4:12 + --> $DIR/issue-70594.rs:4:9 | LL | [1; ().await]; - | ^^^^^ + | ^^^^^^^^ error[E0744]: `.await` is not allowed in a `const` --> $DIR/issue-70594.rs:4:11 @@ -18,16 +18,6 @@ error[E0744]: `.await` is not allowed in a `const` LL | [1; ().await]; | ^^^^^^ -error[E0277]: `()` is not a future - --> $DIR/issue-70594.rs:4:12 - | -LL | [1; ().await]; - | ^^^^^ `()` is not a future - | - = help: the trait `Future` is not implemented for `()` - = note: () must be a future or must implement `IntoFuture` to be awaited - = note: required because of the requirements on the impl of `IntoFuture` for `()` - error[E0277]: `()` is not a future --> $DIR/issue-70594.rs:4:11 | @@ -36,13 +26,14 @@ LL | [1; ().await]; | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited + = note: required because of the requirements on the impl of `IntoFuture` for `()` help: do not `.await` the expression | LL - [1; ().await]; LL + [1; ()]; | -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0728, E0744. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issues/issue-51719.stderr b/src/test/ui/async-await/issues/issue-51719.stderr index 19cc339ec0a07..f3ce5d1c897c3 100644 --- a/src/test/ui/async-await/issues/issue-51719.stderr +++ b/src/test/ui/async-await/issues/issue-51719.stderr @@ -1,8 +1,8 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-51719.rs:8:25 + --> $DIR/issue-51719.rs:8:24 | LL | let _gen = || foo().await; - | -- ^^^^^ only allowed inside `async` functions and blocks + | -- ^^^^^^ only allowed inside `async` functions and blocks | | | this is not `async` diff --git a/src/test/ui/async-await/issues/issue-51751.stderr b/src/test/ui/async-await/issues/issue-51751.stderr index 6dd3726608ba8..8696a5b798b3c 100644 --- a/src/test/ui/async-await/issues/issue-51751.stderr +++ b/src/test/ui/async-await/issues/issue-51751.stderr @@ -1,11 +1,11 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-51751.rs:9:27 + --> $DIR/issue-51751.rs:9:26 | LL | fn main() { | ---- this is not `async` LL | let result = inc(10000); LL | let finished = result.await; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-62009-1.rs b/src/test/ui/async-await/issues/issue-62009-1.rs index 71108b4e1d856..40ccf25712e2b 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.rs +++ b/src/test/ui/async-await/issues/issue-62009-1.rs @@ -12,5 +12,4 @@ fn main() { (|_| 2333).await; //~^ ERROR `await` is only allowed inside `async` functions and blocks //~| ERROR is not a future - //~| ERROR is not a future } diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index c09903e48c602..3ea5dac76d4c5 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -1,38 +1,28 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-62009-1.rs:6:23 + --> $DIR/issue-62009-1.rs:6:22 | LL | fn main() { | ---- this is not `async` LL | async { let (); }.await; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-62009-1.rs:10:7 + --> $DIR/issue-62009-1.rs:10:6 | LL | fn main() { | ---- this is not `async` ... LL | }.await; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-62009-1.rs:12:16 + --> $DIR/issue-62009-1.rs:12:15 | LL | fn main() { | ---- this is not `async` ... LL | (|_| 2333).await; - | ^^^^^ only allowed inside `async` functions and blocks - -error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future - --> $DIR/issue-62009-1.rs:12:16 - | -LL | (|_| 2333).await; - | ^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future - | - = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` - = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited - = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` + | ^^^^^^ only allowed inside `async` functions and blocks error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future --> $DIR/issue-62009-1.rs:12:15 @@ -42,13 +32,14 @@ LL | (|_| 2333).await; | = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited + = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` help: do not `.await` the expression | LL - (|_| 2333).await; LL + (|_| 2333); | -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0728. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issues/issue-62009-2.stderr b/src/test/ui/async-await/issues/issue-62009-2.stderr index 9c2f20df6576f..92e9a8a69a88b 100644 --- a/src/test/ui/async-await/issues/issue-62009-2.stderr +++ b/src/test/ui/async-await/issues/issue-62009-2.stderr @@ -1,10 +1,10 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/issue-62009-2.rs:8:23 + --> $DIR/issue-62009-2.rs:8:22 | LL | fn main() { | ---- this is not `async` LL | (async || 2333)().await; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr index b6583022c161a..20b827479fa80 100644 --- a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr @@ -1,11 +1,11 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/non-async-enclosing-span.rs:9:28 + --> $DIR/non-async-enclosing-span.rs:9:27 | LL | fn main() { | ---- this is not `async` LL | let x = move || {}; LL | let y = do_the_thing().await; - | ^^^^^ only allowed inside `async` functions and blocks + | ^^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index a812840d40b88..3cca9616a358a 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -39,7 +39,7 @@ LL | dummy(); | + error[E0308]: `if` and `else` have incompatible types - --> $DIR/suggest-missing-await.rs:35:17 + --> $DIR/suggest-missing-await.rs:35:9 | LL | let _x = if true { | ______________- @@ -48,7 +48,7 @@ LL | | dummy() LL | | LL | | } else { LL | | dummy().await - | | ^^^^^ expected opaque type, found `()` + | | ^^^^^^^^^^^^^ expected opaque type, found `()` LL | | LL | | }; | |_____- `if` and `else` have incompatible types @@ -61,7 +61,7 @@ LL | dummy().await | ++++++ error[E0308]: `match` arms have incompatible types - --> $DIR/suggest-missing-await.rs:45:22 + --> $DIR/suggest-missing-await.rs:45:14 | LL | let _x = match 0usize { | ______________- @@ -70,7 +70,7 @@ LL | | 0 => dummy(), LL | | 1 => dummy(), | | ------- this is found to be of type `impl Future` LL | | 2 => dummy().await, - | | ^^^^^ expected opaque type, found `()` + | | ^^^^^^^^^^^^^ expected opaque type, found `()` LL | | LL | | }; | |_____- `match` arms have incompatible types diff --git a/src/test/ui/async-await/unnecessary-await.stderr b/src/test/ui/async-await/unnecessary-await.stderr index 4caa15e67b7c9..fc22ebc5972bc 100644 --- a/src/test/ui/async-await/unnecessary-await.stderr +++ b/src/test/ui/async-await/unnecessary-await.stderr @@ -7,6 +7,8 @@ LL | boo().await; | this call returns `()` | = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + = note: required because of the requirements on the impl of `IntoFuture` for `()` help: do not `.await` the expression | LL - boo().await; diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index 52341517756ca..c6650d60c21e9 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -23,20 +23,6 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: required because of the requirements on the impl of `Iterator` for `Cloned>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned>` -<<<<<<< HEAD error: aborting due to 2 previous errors -======= -error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` - --> $DIR/issue-33941.rs:4:14 - | -LL | for _ in HashMap::new().iter().cloned() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference - | - = note: expected tuple `(&_, &_)` - found reference `&_` - = note: required because of the requirements on the impl of `Iterator` for `Cloned>` - -error: aborting due to 3 previous errors ->>>>>>> 330b90f5fc1 (Remove yet more output from `for`-loop and `?` errors) For more information about this error, try `rustc --explain E0271`. diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index e0522f3fe0b1a..5b098659377c6 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -73,7 +73,7 @@ fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> seen } -#[derive(Debug)] +#[derive(Debug, Clone)] struct LocalAssign { lhs_id: HirId, lhs_span: Span, @@ -154,9 +154,14 @@ fn assignment_suggestions<'tcx>( assignments.push(assign); } - let suggestions = assignments + let suggestions = assignments.clone() .into_iter() - .map(|assignment| Some((assignment.span, snippet_opt(cx, assignment.rhs_span)?))) + .map(|assignment| Some((assignment.span.until(assignment.rhs_span), String::new()))) + .chain( + assignments + .into_iter() + .map(|assignment| Some((assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()), String::new()))) + ) .collect::>>()?; let applicability = if suggestions.len() > 1 { diff --git a/src/tools/clippy/tests/ui/needless_late_init_fixable.fixed b/src/tools/clippy/tests/ui/needless_late_init_fixable.fixed deleted file mode 100644 index 32d5d04fde4d5..0000000000000 --- a/src/tools/clippy/tests/ui/needless_late_init_fixable.fixed +++ /dev/null @@ -1,38 +0,0 @@ -// run-rustfix - -#![allow(unused, clippy::assign_op_pattern)] - -fn main() { - - let a = "zero"; - - - - let b = 1; - let c = 2; - - - let d: usize = 1; - - - let mut e = 1; - e = 2; - - - let f = match 1 { - 1 => "three", - _ => return, - }; // has semi - - - let g: usize = if true { - 5 - } else { - panic!(); - }; - - - let h = format!("{}", e); - - println!("{}", a); -} diff --git a/src/tools/clippy/tests/ui/needless_late_init_fixable.rs b/src/tools/clippy/tests/ui/needless_late_init_fixable.rs index 6bc85f686325d..76099df0e0689 100644 --- a/src/tools/clippy/tests/ui/needless_late_init_fixable.rs +++ b/src/tools/clippy/tests/ui/needless_late_init_fixable.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![allow(unused, clippy::assign_op_pattern)] fn main() { diff --git a/src/tools/clippy/tests/ui/needless_late_init_fixable.stderr b/src/tools/clippy/tests/ui/needless_late_init_fixable.stderr index a0ce4f812f4e5..728e19252ea70 100644 --- a/src/tools/clippy/tests/ui/needless_late_init_fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init_fixable.stderr @@ -1,5 +1,5 @@ error: unneeded late initalization - --> $DIR/needless_late_init_fixable.rs:6:5 + --> $DIR/needless_late_init_fixable.rs:4:5 | LL | let a; | ^^^^^^ @@ -11,7 +11,7 @@ LL | let a = "zero"; | ~~~~~ error: unneeded late initalization - --> $DIR/needless_late_init_fixable.rs:9:5 + --> $DIR/needless_late_init_fixable.rs:7:5 | LL | let b; | ^^^^^^ @@ -22,7 +22,7 @@ LL | let b = 1; | ~~~~~ error: unneeded late initalization - --> $DIR/needless_late_init_fixable.rs:10:5 + --> $DIR/needless_late_init_fixable.rs:8:5 | LL | let c; | ^^^^^^ @@ -33,7 +33,7 @@ LL | let c = 2; | ~~~~~ error: unneeded late initalization - --> $DIR/needless_late_init_fixable.rs:14:5 + --> $DIR/needless_late_init_fixable.rs:12:5 | LL | let d: usize; | ^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let d: usize = 1; | ~~~~~~~~~~~~ error: unneeded late initalization - --> $DIR/needless_late_init_fixable.rs:17:5 + --> $DIR/needless_late_init_fixable.rs:15:5 | LL | let mut e; | ^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | let mut e = 1; | ~~~~~~~~~ error: unneeded late initalization - --> $DIR/needless_late_init_fixable.rs:21:5 + --> $DIR/needless_late_init_fixable.rs:19:5 | LL | let f; | ^^^^^^ @@ -66,11 +66,12 @@ LL | let f = match 1 { | +++++++ help: remove the assignments from the `match` arms | -LL | 1 => "three", - | ~~~~~~~ +LL - 1 => f = "three", +LL + 1 => "three", + | error: unneeded late initalization - --> $DIR/needless_late_init_fixable.rs:27:5 + --> $DIR/needless_late_init_fixable.rs:25:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -81,15 +82,16 @@ LL | let g: usize = if true { | ++++++++++++++ help: remove the assignments from the branches | -LL | 5 - | +LL - g = 5; +LL + 5 + | help: add a semicolon after the `if` expression | LL | }; | + error: unneeded late initalization - --> $DIR/needless_late_init_fixable.rs:34:5 + --> $DIR/needless_late_init_fixable.rs:32:5 | LL | let h; | ^^^^^^ From 4884d8ef45ca035e2b36507d8998785231e7fb8c Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 23:04:15 +0000 Subject: [PATCH 19/38] tidy fix --- src/test/ui/async-await/unnecessary-await.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/async-await/unnecessary-await.rs b/src/test/ui/async-await/unnecessary-await.rs index 70c38aaeb2511..b994dc82e4d54 100644 --- a/src/test/ui/async-await/unnecessary-await.rs +++ b/src/test/ui/async-await/unnecessary-await.rs @@ -11,4 +11,4 @@ async fn baz() -> std::io::Result<()> { std::io::Result::Ok(()) } -fn main() {} \ No newline at end of file +fn main() {} From d94eaa5f40e08dbe91332523b0a9c78304670bd3 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Wed, 17 Nov 2021 17:33:15 +0000 Subject: [PATCH 20/38] Simplify diagnostic logic The spans no longer overlap, so we no longer need to specialize the output depending on whether they would. --- .../src/traits/error_reporting/suggestions.rs | 167 +++++------------- 1 file changed, 44 insertions(+), 123 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 67c0b88d7aad4..f7f8a267130f8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1717,130 +1717,51 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("does not implement `{}`", trait_ref.print_only_trait_path()) }; - let mut explain_yield = - |interior_span: Span, yield_span: Span, scope_span: Option| { - let mut span = MultiSpan::from_span(yield_span); - if let Ok(snippet) = source_map.span_to_snippet(interior_span) { - // #70935: If snippet contains newlines, display "the value" instead - // so that we do not emit complex diagnostics. - let snippet = &format!("`{}`", snippet); - let snippet = if snippet.contains('\n') { "the value" } else { snippet }; - // The multispan can be complex here, like: - // note: future is not `Send` as this value is used across an await - // --> $DIR/issue-70935-complex-spans.rs:13:9 - // | - // LL | baz(|| async{ - // | __________^___- - // | | _________| - // | || - // LL | || foo(tx.clone()); - // LL | || }).await; - // | || - ^- value is later dropped here - // | ||_________|______| - // | |__________| await occurs here, with value maybe used later - // | has type `closure` which is not `Send` - // - // So, detect it and separate into some notes, like: - // - // note: future is not `Send` as this value is used across an await - // --> $DIR/issue-70935-complex-spans.rs:13:9 - // | - // LL | / baz(|| async{ - // LL | | foo(tx.clone()); - // LL | | }).await; - // | |________________^ first, await occurs here, with the value maybe used later... - // note: the value is later dropped here - // --> $DIR/issue-70935-complex-spans.rs:15:17 - // | - // LL | }).await; - // | ^ - // - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { - let scope_span = source_map.end_point(scope_span); - let is_overlapped = - yield_span.overlaps(scope_span) || yield_span.overlaps(interior_span); - if is_overlapped { - span.push_span_label( - yield_span, - format!( - "first, {} occurs here, with {} maybe used later...", - await_or_yield, snippet - ), - ); - err.span_note( - span, - &format!( - "{} {} as this value is used across {}", - future_or_generator, trait_explanation, an_await_or_yield - ), - ); - if source_map.is_multiline(interior_span) { - err.span_note( - scope_span, - &format!("{} is later dropped here", snippet), - ); - err.span_note( - interior_span, - &format!( - "this has type `{}` which {}", - target_ty, trait_explanation - ), - ); - } else { - let mut span = MultiSpan::from_span(scope_span); - span.push_span_label( - interior_span, - format!("has type `{}` which {}", target_ty, trait_explanation), - ); - err.span_note(span, &format!("{} is later dropped here", snippet)); - } - } else { - span.push_span_label( - yield_span, - format!( - "{} occurs here, with {} maybe used later", - await_or_yield, snippet - ), - ); - span.push_span_label( - scope_span, - format!("{} is later dropped here", snippet), - ); - span.push_span_label( - interior_span, - format!("has type `{}` which {}", target_ty, trait_explanation), - ); - err.span_note( - span, - &format!( - "{} {} as this value is used across {}", - future_or_generator, trait_explanation, an_await_or_yield - ), - ); - } - } else { - span.push_span_label( - yield_span, - format!( - "{} occurs here, with {} maybe used later", - await_or_yield, snippet - ), - ); - span.push_span_label( - interior_span, - format!("has type `{}` which {}", target_ty, trait_explanation), - ); - err.span_note( - span, - &format!( - "{} {} as this value is used across {}", - future_or_generator, trait_explanation, an_await_or_yield - ), - ); - } + let mut explain_yield = |interior_span: Span, + yield_span: Span, + scope_span: Option| { + let mut span = MultiSpan::from_span(yield_span); + if let Ok(snippet) = source_map.span_to_snippet(interior_span) { + // #70935: If snippet contains newlines, display "the value" instead + // so that we do not emit complex diagnostics. + let snippet = &format!("`{}`", snippet); + let snippet = if snippet.contains('\n') { "the value" } else { snippet }; + // note: future is not `Send` as this value is used across an await + // --> $DIR/issue-70935-complex-spans.rs:13:9 + // | + // LL | baz(|| async { + // | ______________- + // | | + // | | + // LL | | foo(tx.clone()); + // LL | | }).await; + // | | - ^^^^^^- value is later dropped here + // | | | | + // | |__________| await occurs here, with value maybe used later + // | has type `closure` which is not `Send` + // + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + let scope_span = source_map.end_point(scope_span); + span.push_span_label(scope_span, format!("{} is later dropped here", snippet)); } - }; + span.push_span_label( + yield_span, + format!("{} occurs here, with {} maybe used later", await_or_yield, snippet), + ); + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + } + }; match interior_or_upvar_span { GeneratorInteriorOrUpvar::Interior(interior_span) => { if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { From df5439cf08cc1ce11ec4068dd772cd072870d807 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Thu, 2 Dec 2021 23:41:45 +0000 Subject: [PATCH 21/38] review comments --- .../src/traits/error_reporting/suggestions.rs | 28 +++++++++++++------ .../issue-70935-complex-spans.stderr | 10 +++++-- .../issue-65436-raw-ptr-not-send.stderr | 10 +++++-- src/test/ui/async-await/unnecessary-await.rs | 4 +-- .../ui/async-await/unnecessary-await.stderr | 2 +- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index f7f8a267130f8..1a00b2f3cf713 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1735,16 +1735,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // | | // LL | | foo(tx.clone()); // LL | | }).await; - // | | - ^^^^^^- value is later dropped here - // | | | | - // | |__________| await occurs here, with value maybe used later + // | | - ^^^^^^ await occurs here, with value maybe used later + // | |__________| // | has type `closure` which is not `Send` + // note: value is later dropped here + // LL | | }).await; + // | | ^ // - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { - let scope_span = source_map.end_point(scope_span); - span.push_span_label(scope_span, format!("{} is later dropped here", snippet)); - } span.push_span_label( yield_span, format!("{} occurs here, with {} maybe used later", await_or_yield, snippet), @@ -1753,6 +1750,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { interior_span, format!("has type `{}` which {}", target_ty, trait_explanation), ); + // If available, use the scope span to annotate the drop location. + let mut scope_note = None; + if let Some(scope_span) = scope_span { + let scope_span = source_map.end_point(scope_span); + + let msg = format!("{} is later dropped here", snippet); + if source_map.is_multiline(yield_span.between(scope_span)) { + span.push_span_label(scope_span, msg); + } else { + scope_note = Some((scope_span, msg)); + } + } err.span_note( span, &format!( @@ -1760,6 +1769,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { future_or_generator, trait_explanation, an_await_or_yield ), ); + if let Some((span, msg)) = scope_note { + err.span_note(span, &msg); + } } }; match interior_or_upvar_span { diff --git a/src/test/ui/async-await/issue-70935-complex-spans.stderr b/src/test/ui/async-await/issue-70935-complex-spans.stderr index 4929aa29d0f40..db3099381196b 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.stderr @@ -12,10 +12,14 @@ LL | baz(|| async{ | _____________- LL | | foo(tx.clone()); LL | | }).await; - | | - ^^^^^^- the value is later dropped here - | | | | - | |_________| await occurs here, with the value maybe used later + | | - ^^^^^^ await occurs here, with the value maybe used later + | |_________| | has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send` +note: the value is later dropped here + --> $DIR/issue-70935-complex-spans.rs:15:17 + | +LL | }).await; + | ^ error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr index cac174061a2b5..b4d2006480390 100644 --- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -9,10 +9,14 @@ note: future is not `Send` as this value is used across an await --> $DIR/issue-65436-raw-ptr-not-send.rs:14:35 | LL | bar(Foo(std::ptr::null())).await; - | ---------------- ^^^^^^- `std::ptr::null()` is later dropped here - | | | - | | await occurs here, with `std::ptr::null()` maybe used later + | ---------------- ^^^^^^ await occurs here, with `std::ptr::null()` maybe used later + | | | has type `*const u8` which is not `Send` +note: `std::ptr::null()` is later dropped here + --> $DIR/issue-65436-raw-ptr-not-send.rs:14:41 + | +LL | bar(Foo(std::ptr::null())).await; + | ^ help: consider moving this into a `let` binding to create a shorter lived borrow --> $DIR/issue-65436-raw-ptr-not-send.rs:14:13 | diff --git a/src/test/ui/async-await/unnecessary-await.rs b/src/test/ui/async-await/unnecessary-await.rs index b994dc82e4d54..24673777b8039 100644 --- a/src/test/ui/async-await/unnecessary-await.rs +++ b/src/test/ui/async-await/unnecessary-await.rs @@ -1,8 +1,8 @@ // edition:2018 async fn foo () { } -fn bar () -> impl std::future::Future { async {} } -fn boo () {} +fn bar() -> impl std::future::Future { async {} } +fn boo() {} async fn baz() -> std::io::Result<()> { foo().await; diff --git a/src/test/ui/async-await/unnecessary-await.stderr b/src/test/ui/async-await/unnecessary-await.stderr index fc22ebc5972bc..23dea2d3a0c74 100644 --- a/src/test/ui/async-await/unnecessary-await.stderr +++ b/src/test/ui/async-await/unnecessary-await.stderr @@ -16,7 +16,7 @@ LL + boo(); | help: alternatively, consider making `fn boo` asynchronous | -LL | async fn boo () {} +LL | async fn boo() {} | +++++ error: aborting due to previous error From a310dfb4e304c74456501438dc4f68eb64df583e Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 10 Dec 2021 03:01:37 +0000 Subject: [PATCH 22/38] review comment: change wording of suggestion --- .../src/traits/error_reporting/suggestions.rs | 2 +- src/test/ui/async-await/issue-70594.stderr | 2 +- src/test/ui/async-await/issues/issue-62009-1.stderr | 2 +- src/test/ui/async-await/unnecessary-await.stderr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1a00b2f3cf713..d1b436ceb8542 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -896,7 +896,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // it is from the local crate. err.span_suggestion_verbose( expr.span.shrink_to_hi().with_hi(span.hi()), - "do not `.await` the expression", + "remove the `.await`", String::new(), Applicability::MachineApplicable, ); diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr index 405709286822a..a159edd51187f 100644 --- a/src/test/ui/async-await/issue-70594.stderr +++ b/src/test/ui/async-await/issue-70594.stderr @@ -27,7 +27,7 @@ LL | [1; ().await]; = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required because of the requirements on the impl of `IntoFuture` for `()` -help: do not `.await` the expression +help: remove the `.await` | LL - [1; ().await]; LL + [1; ()]; diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index 3ea5dac76d4c5..3d80c34942c1b 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -33,7 +33,7 @@ LL | (|_| 2333).await; = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` -help: do not `.await` the expression +help: remove the `.await` | LL - (|_| 2333).await; LL + (|_| 2333); diff --git a/src/test/ui/async-await/unnecessary-await.stderr b/src/test/ui/async-await/unnecessary-await.stderr index 23dea2d3a0c74..c3d2a6e7b1e1b 100644 --- a/src/test/ui/async-await/unnecessary-await.stderr +++ b/src/test/ui/async-await/unnecessary-await.stderr @@ -9,7 +9,7 @@ LL | boo().await; = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required because of the requirements on the impl of `IntoFuture` for `()` -help: do not `.await` the expression +help: remove the `.await` | LL - boo().await; LL + boo(); From d10fe26f39983c782f1a37a447f2c10c2ef561ba Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Sun, 10 Oct 2021 10:37:57 +0000 Subject: [PATCH 23/38] Point at capture points for non-`'static` reference crossing a `yield` point ``` error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/issue-72312.rs:10:24 | LL | pub async fn start(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... ... LL | require_static(async move { | -------------- ...is required to live as long as `'static` here... LL | &self; | ----- ...and is captured here | note: `'static` lifetime requirement introduced by this trait bound --> $DIR/issue-72312.rs:2:22 | LL | fn require_static(val: T) -> T { | ^^^^^^^ error: aborting due to previous error For more information about this error, try `rustc --explain E0759`. ``` Fix #72312. --- .../src/diagnostics/bound_region_errors.rs | 1 + .../src/infer/error_reporting/mod.rs | 3 +- .../error_reporting/nice_region_error/mod.rs | 2 +- .../nice_region_error/placeholder_error.rs | 4 ++ .../nice_region_error/static_impl_trait.rs | 69 ++++++++++++++++--- .../trait_impl_difference.rs | 1 + .../src/infer/lexical_region_resolve/mod.rs | 32 +++++++-- .../ui/async-await/issues/issue-62097.stderr | 18 +++-- src/test/ui/async-await/issues/issue-72312.rs | 19 +++++ .../ui/async-await/issues/issue-72312.stderr | 20 ++++++ .../trait-upcasting/type-checking-test-4.rs | 18 +++++ .../type-checking-test-4.stderr | 48 ++++++++++++- 12 files changed, 212 insertions(+), 23 deletions(-) create mode 100644 src/test/ui/async-await/issues/issue-72312.rs create mode 100644 src/test/ui/async-await/issues/issue-72312.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 1bc9f8cf3ccc8..881ebed602946 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( error_region, cause.clone(), placeholder_region, + vec![], ), ), (Some(error_region), _) => NiceRegionError::new( diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 85226e60bdbdb..c3f2213229a01 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -384,6 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sub_r, sup_origin, sup_r, + _, ) => { if sub_r.is_placeholder() { self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit(); @@ -464,7 +465,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { errors.sort_by_key(|u| match *u { RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), - RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(), + RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(), RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), }); errors diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 6a3309770028f..fd295b743420c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -67,7 +67,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { match (&self.error, self.regions) { (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)), - (Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => { + (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { Some((origin.span(), sub, sup)) } (None, Some((span, sub, sup))) => Some((span, sub, sup)), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 4aecc2f40b874..1a4a280382189 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -34,6 +34,7 @@ impl NiceRegionError<'me, 'tcx> { sub_placeholder @ ty::RePlaceholder(_), _, sup_placeholder @ ty::RePlaceholder(_), + _, )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, @@ -49,6 +50,7 @@ impl NiceRegionError<'me, 'tcx> { sub_placeholder @ ty::RePlaceholder(_), _, _, + _, )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, @@ -64,6 +66,7 @@ impl NiceRegionError<'me, 'tcx> { _, _, sup_placeholder @ ty::RePlaceholder(_), + _, )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, @@ -79,6 +82,7 @@ impl NiceRegionError<'me, 'tcx> { _, SubregionOrigin::Subtype(box TypeTrace { cause, values }), sup_placeholder @ ty::RePlaceholder(_), + _, )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 2aaebed28ced7..c7ba5087b8cbc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -23,7 +23,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub(super) fn try_report_static_impl_trait(&self) -> Option { debug!("try_report_static_impl_trait(error={:?})", self.error); let tcx = self.tcx(); - let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? { + let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? { RegionResolutionError::SubSupConflict( _, var_origin, @@ -31,8 +31,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sub_r, sup_origin, sup_r, + spans, ) if **sub_r == RegionKind::ReStatic => { - (var_origin, sub_origin, sub_r, sup_origin, sup_r) + (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) } RegionResolutionError::ConcreteFailure( SubregionOrigin::Subtype(box TypeTrace { cause, .. }), @@ -123,15 +124,31 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { param_name, lifetime, ); - err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); + + let (mention_capture, capture_point) = if sup_origin.span().overlaps(param.param_ty_span) { + // Account for `async fn` like in `async-await/issues/issue-62097.rs`. + // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same + // place (but with different `ctxt`, hence `overlaps` instead of `==` above). + // + // This avoids the following: + // + // LL | pub async fn run_dummy_fn(&self) { + // | ^^^^^ + // | | + // | this data with an anonymous lifetime `'_`... + // | ...is captured here... + (false, sup_origin.span()) + } else { + (true, param.param_ty_span) + }; + err.span_label(capture_point, &format!("this data with {}...", lifetime)); + debug!("try_report_static_impl_trait: param_info={:?}", param); // We try to make the output have fewer overlapping spans if possible. if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) && sup_origin.span() != return_sp { - // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` - // Customize the spans and labels depending on their relative order so // that split sentences flow correctly. if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { @@ -152,11 +169,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // | ---- ^ err.span_label( sup_origin.span(), - "...is captured here, requiring it to live as long as `'static`", + &format!( + "...is captured here, requiring it to live as long as `'static`{}", + if spans.is_empty() { "" } else { "..." }, + ), ); } else { - err.span_label(sup_origin.span(), "...is captured here..."); - if return_sp < sup_origin.span() { + if return_sp < sup_origin.span() && mention_capture { + err.span_label(sup_origin.span(), "...is captured here..."); err.span_note( return_sp, "...and is required to live as long as `'static` here", @@ -164,17 +184,46 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } else { err.span_label( return_sp, - "...and is required to live as long as `'static` here", + &format!( + "...is required to live as long as `'static` here{}", + if spans.is_empty() { "" } else { "..." }, + ), ); + if mention_capture { + let span = sup_origin.span(); + let msg = if spans.iter().any(|sp| *sp > span) { + "...is captured here..." + } else { + "...and is captured here" + }; + err.span_label(span, msg); + } } } } else { err.span_label( return_sp, - "...is captured and required to live as long as `'static` here", + &format!( + "...is captured and required to live as long as `'static` here{}", + if spans.is_empty() { "" } else { "..." }, + ), ); } + for span in spans { + let msg = + format!("...and is captured here{}", if mention_capture { " too" } else { "" }); + if span.overlaps(return_sp) { + err.span_note(*span, &msg); + } else { + err.span_label(*span, &msg); + } + } + + if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { + err.span_note(*bound, "`'static` lifetime requirement introduced by this trait bound"); + } + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); let mut override_error_code = None; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index cfa79213c805c..452ca5eeabd49 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -28,6 +28,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _sub, sup_origin, _sup, + _, ) = error.clone() { if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) { diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 4c9dcab26b14f..14f6c72bb1ce9 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar}; use rustc_middle::ty::{Region, RegionVid}; +use rustc_span::Span; use std::fmt; /// This function performs lexical region resolution given a complete @@ -96,6 +97,7 @@ pub enum RegionResolutionError<'tcx> { Region<'tcx>, SubregionOrigin<'tcx>, Region<'tcx>, + Vec, ), /// Indicates a `'b: 'a` constraint where `'a` is in a universe that @@ -144,8 +146,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let graph = self.construct_graph(); self.expand_givens(&graph); self.expansion(&mut var_data); - self.collect_errors(&mut var_data, errors); - self.collect_var_errors(&var_data, &graph, errors); + let captures = self.collect_errors(&mut var_data, errors); + self.collect_var_errors(&var_data, &graph, errors, captures); var_data } @@ -443,9 +445,16 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { &self, var_data: &mut LexicalRegionResolutions<'tcx>, errors: &mut Vec>, - ) { + ) -> Vec { + let mut captures = vec![]; + for (constraint, origin) in &self.data.constraints { debug!(?constraint, ?origin); + if let (Constraint::VarSubVar(_, _), SubregionOrigin::DataBorrowed(_, sp)) = + (constraint, origin) + { + captures.push(*sp); + } match *constraint { Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => { // Expansion will ensure that these constraints hold. Ignore. @@ -515,6 +524,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { sub, )); } + captures } /// Go over the variables that were declared to be error variables @@ -524,6 +534,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { var_data: &LexicalRegionResolutions<'tcx>, graph: &RegionGraph<'tcx>, errors: &mut Vec>, + captures: Vec, ) { debug!("collect_var_errors, var_data = {:#?}", var_data.values); @@ -567,7 +578,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // if this rule starts to create problems we'll // have to revisit this portion of the code and // think hard about it. =) -- nikomatsakis - self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors); + self.collect_error_for_expanding_node( + graph, + &mut dup_vec, + node_vid, + errors, + &captures, + ); } } } @@ -621,6 +638,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { dup_vec: &mut IndexVec>, node_idx: RegionVid, errors: &mut Vec>, + captures: &[Span], ) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. @@ -667,6 +685,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { sup: {:?}", origin, node_idx, lower_bound.region, upper_bound.region ); + + let mut capture_spans: Vec = captures.iter().cloned().collect(); + // Below, one span expects `&Span` and the other `&mut Span`, hence the dupes. + capture_spans.sort_by_key(|span| (span.lo(), span.hi())); + capture_spans.dedup_by_key(|span| (span.lo(), span.hi())); errors.push(RegionResolutionError::SubSupConflict( node_idx, origin, @@ -674,6 +697,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { lower_bound.region, upper_bound.origin.clone(), upper_bound.region, + capture_spans, )); return; } diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 56a28d904b91d..bb329a4a0c264 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -2,12 +2,20 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `' --> $DIR/issue-62097.rs:12:31 | LL | pub async fn run_dummy_fn(&self) { - | ^^^^^ - | | - | this data with an anonymous lifetime `'_`... - | ...is captured here... + | ^^^^^ this data with an anonymous lifetime `'_`... LL | foo(|| self.bar()).await; - | --- ...and is required to live as long as `'static` here + | --- ...is required to live as long as `'static` here... + | +note: ...and is captured here + --> $DIR/issue-62097.rs:13:9 + | +LL | foo(|| self.bar()).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: `'static` lifetime requirement introduced by this trait bound + --> $DIR/issue-62097.rs:4:19 + | +LL | F: FnOnce() + 'static + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-72312.rs b/src/test/ui/async-await/issues/issue-72312.rs new file mode 100644 index 0000000000000..d33685e02f188 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-72312.rs @@ -0,0 +1,19 @@ +// edition:2018 +fn require_static(val: T) -> T { + //~^ NOTE 'static` lifetime requirement introduced by this trait bound + val +} + +struct Problem; + +impl Problem { + pub async fn start(&self) { //~ ERROR E0759 + //~^ NOTE this data with an anonymous lifetime `'_` + //~| NOTE in this expansion of desugaring of `async` block or function + require_static(async move { //~ NOTE ...is required to live as long as `'static` here + &self; //~ NOTE ...and is captured here + }); + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr new file mode 100644 index 0000000000000..ee5ee6f0f93c3 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-72312.stderr @@ -0,0 +1,20 @@ +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/issue-72312.rs:10:24 + | +LL | pub async fn start(&self) { + | ^^^^^ this data with an anonymous lifetime `'_`... +... +LL | require_static(async move { + | -------------- ...is required to live as long as `'static` here... +LL | &self; + | ----- ...and is captured here + | +note: `'static` lifetime requirement introduced by this trait bound + --> $DIR/issue-72312.rs:2:22 + | +LL | fn require_static(val: T) -> T { + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs index 9b27fd46f7acd..95698fd1e1a80 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs @@ -29,4 +29,22 @@ fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { y.get_b() // ERROR } +fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + <_ as Bar>::get_b(x) // ERROR + //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement +} + +fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + <_ as Bar<'_, '_>>::get_b(x) // ERROR + //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement +} + +fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + let y = x as &dyn Bar<'_, '_>; + //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + y.get_b(); // ERROR + let z = y; + z.get_b() // ERROR +} + fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr index 4967f3dc2c8cf..04560ea4e297a 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -39,9 +39,53 @@ LL | let y = x as &dyn Bar<'_, '_>; | ...is captured here... LL | LL | y.get_b() // ERROR - | --------- ...and is required to live as long as `'static` here + | --------- ...is required to live as long as `'static` here... + | +note: ...and is captured here too + --> $DIR/type-checking-test-4.rs:29:5 + | +LL | y.get_b() // ERROR + | ^ + +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/type-checking-test-4.rs:33:5 + | +LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ------------ this data with lifetime `'a`... +LL | <_ as Bar>::get_b(x) // ERROR + | ^^^^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static` + +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/type-checking-test-4.rs:38:15 + | +LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ------------ this data with lifetime `'a`... +LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR + | ----------^^---------------- ...is captured and required to live as long as `'static` here + +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/type-checking-test-4.rs:43:27 + | +LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ------------ this data with lifetime `'a`... +LL | let y = x as &dyn Bar<'_, '_>; + | - ^^ + | | + | ...is captured here... +LL | +LL | y.get_b(); // ERROR + | - ...and is captured here too +LL | let z = y; +LL | z.get_b() // ERROR + | --------- ...is required to live as long as `'static` here... + | +note: ...and is captured here too + --> $DIR/type-checking-test-4.rs:47:5 + | +LL | z.get_b() // ERROR + | ^ -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0308, E0759. For more information about an error, try `rustc --explain E0308`. From dd81e984660bf4273470d336eaed27f9e062ce1c Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 11 Oct 2021 19:20:13 +0000 Subject: [PATCH 24/38] Clean up visual output logic --- .../nice_region_error/static_impl_trait.rs | 92 +++++-------------- ...ject-fn-ret-contravariant.transmute.stderr | 2 +- .../project-fn-ret-invariant.transmute.stderr | 2 +- .../ui/async-await/issues/issue-62097.stderr | 8 +- src/test/ui/async-await/issues/issue-72312.rs | 6 +- .../ui/async-await/issues/issue-72312.stderr | 11 ++- .../must_outlive_least_region_or_bound.stderr | 10 +- src/test/ui/issues/issue-16922.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 6 +- .../regions-close-object-into-object-2.stderr | 2 +- .../regions-close-object-into-object-4.stderr | 2 +- .../regions/regions-proc-bound-capture.stderr | 2 +- .../type-checking-test-4.stderr | 18 ++-- .../dyn-trait-underscore.stderr | 4 +- 14 files changed, 61 insertions(+), 106 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index c7ba5087b8cbc..3f7aa7773d1c0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -139,89 +139,39 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // | ...is captured here... (false, sup_origin.span()) } else { - (true, param.param_ty_span) + (!sup_origin.span().overlaps(return_sp), param.param_ty_span) }; err.span_label(capture_point, &format!("this data with {}...", lifetime)); debug!("try_report_static_impl_trait: param_info={:?}", param); + let mut spans = spans.clone(); + + if mention_capture { + spans.push(sup_origin.span()); + } + spans.sort(); + spans.dedup(); + // We try to make the output have fewer overlapping spans if possible. - if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) - && sup_origin.span() != return_sp - { - // Customize the spans and labels depending on their relative order so - // that split sentences flow correctly. - if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { - // Avoid the following: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box { Box::new(x) } - // | ---- ---------^- - // - // and instead show: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box { Box::new(x) } - // | ---- ^ - err.span_label( - sup_origin.span(), - &format!( - "...is captured here, requiring it to live as long as `'static`{}", - if spans.is_empty() { "" } else { "..." }, - ), - ); - } else { - if return_sp < sup_origin.span() && mention_capture { - err.span_label(sup_origin.span(), "...is captured here..."); - err.span_note( - return_sp, - "...and is required to live as long as `'static` here", - ); - } else { - err.span_label( - return_sp, - &format!( - "...is required to live as long as `'static` here{}", - if spans.is_empty() { "" } else { "..." }, - ), - ); - if mention_capture { - let span = sup_origin.span(); - let msg = if spans.iter().any(|sp| *sp > span) { - "...is captured here..." - } else { - "...and is captured here" - }; - err.span_label(span, msg); - } - } - } + let (require_msg, require_span) = if sup_origin.span().overlaps(return_sp) { + ("...is captured and required to live as long as `'static` here", sup_origin.span()) } else { - err.span_label( - return_sp, - &format!( - "...is captured and required to live as long as `'static` here{}", - if spans.is_empty() { "" } else { "..." }, - ), - ); + ("...and is required to live as long as `'static` here", return_sp) + }; + + for span in &spans { + err.span_label(*span, "...is captured here..."); } - for span in spans { - let msg = - format!("...and is captured here{}", if mention_capture { " too" } else { "" }); - if span.overlaps(return_sp) { - err.span_note(*span, &msg); - } else { - err.span_label(*span, &msg); - } + if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) { + err.span_note(require_span, require_msg); + } else { + err.span_label(require_span, require_msg); } if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { - err.span_note(*bound, "`'static` lifetime requirement introduced by this trait bound"); + err.span_note(*bound, "`'static` lifetime requirement introduced by this bound"); } let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index 0be9b37263a48..6f63a2c5fc37e 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -4,7 +4,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { | ------- this data with lifetime `'a`... LL | bar(foo, x) - | ----^^^---- ...is captured and required to live as long as `'static` here + | ^^^ - ...is captured and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 0a44864b24955..eb81da7852d99 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -5,7 +5,7 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { | -------- this data with lifetime `'a`... ... LL | bar(foo, x) - | ----^^^---- ...is captured and required to live as long as `'static` here + | ^^^ - ...is captured and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index bb329a4a0c264..7aea147c6cfc2 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -4,14 +4,14 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `' LL | pub async fn run_dummy_fn(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... LL | foo(|| self.bar()).await; - | --- ...is required to live as long as `'static` here... + | ------------------------ ...is captured here... | -note: ...and is captured here +note: ...and is required to live as long as `'static` here --> $DIR/issue-62097.rs:13:9 | LL | foo(|| self.bar()).await; - | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: `'static` lifetime requirement introduced by this trait bound + | ^^^ +note: `'static` lifetime requirement introduced by this bound --> $DIR/issue-62097.rs:4:19 | LL | F: FnOnce() + 'static diff --git a/src/test/ui/async-await/issues/issue-72312.rs b/src/test/ui/async-await/issues/issue-72312.rs index d33685e02f188..eb0cc7e6aeca1 100644 --- a/src/test/ui/async-await/issues/issue-72312.rs +++ b/src/test/ui/async-await/issues/issue-72312.rs @@ -1,6 +1,6 @@ // edition:2018 fn require_static(val: T) -> T { - //~^ NOTE 'static` lifetime requirement introduced by this trait bound + //~^ NOTE 'static` lifetime requirement introduced by this bound val } @@ -10,8 +10,8 @@ impl Problem { pub async fn start(&self) { //~ ERROR E0759 //~^ NOTE this data with an anonymous lifetime `'_` //~| NOTE in this expansion of desugaring of `async` block or function - require_static(async move { //~ NOTE ...is required to live as long as `'static` here - &self; //~ NOTE ...and is captured here + require_static(async move { //~ NOTE ...and is required to live as long as `'static` here + &self; //~ NOTE ...is captured here... }); } } diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr index ee5ee6f0f93c3..7a72edd4e5310 100644 --- a/src/test/ui/async-await/issues/issue-72312.stderr +++ b/src/test/ui/async-await/issues/issue-72312.stderr @@ -4,12 +4,15 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `' LL | pub async fn start(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... ... -LL | require_static(async move { - | -------------- ...is required to live as long as `'static` here... LL | &self; - | ----- ...and is captured here + | ----- ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/issue-72312.rs:13:9 | -note: `'static` lifetime requirement introduced by this trait bound +LL | require_static(async move { + | ^^^^^^^^^^^^^^ +note: `'static` lifetime requirement introduced by this bound --> $DIR/issue-72312.rs:2:22 | LL | fn require_static(val: T) -> T { diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index d65dea7adc90b..e80372766dc3c 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -80,7 +80,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:24:65 | LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } - | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static` + | ---- this data with an anonymous lifetime `'_`... ^ ...is captured and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound | @@ -136,7 +136,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:16:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here, requiring it to live as long as `'static` + | ---- ^ ...is captured and required to live as long as `'static` here | | | this data with an anonymous lifetime `'_`... | @@ -149,7 +149,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:18:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- ^ ...is captured here, requiring it to live as long as `'static` + | ------- ^ ...is captured and required to live as long as `'static` here | | | this data with lifetime `'a`... | @@ -162,7 +162,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:20:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here, requiring it to live as long as `'static` + | ---- ^ ...is captured and required to live as long as `'static` here | | | this data with an anonymous lifetime `'_`... | @@ -179,7 +179,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:22:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static` + | ------- this data with lifetime `'a`... ^ ...is captured and required to live as long as `'static` here | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 8b09b7d59079f..ff7b3b67140c2 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -4,7 +4,7 @@ error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a ` LL | fn foo(value: &T) -> Box { | -- this data with an anonymous lifetime `'_`... LL | Box::new(value) as Box - | ^^^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^^^ ...is captured and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound | diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 04d22e58a1dc5..9eb24c1bd372e 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -4,7 +4,7 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn a(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... LL | let x: Box = Box::new(v); - | ^ ...is captured here, requiring it to live as long as `'static` + | ^ ...is captured and required to live as long as `'static` here | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | @@ -21,7 +21,7 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn b(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... LL | Box::new(v) - | ^ ...is captured here, requiring it to live as long as `'static` + | ^ ...is captured and required to live as long as `'static` here | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | @@ -39,7 +39,7 @@ LL | fn c(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... ... LL | Box::new(v) - | ^ ...is captured here, requiring it to live as long as `'static` + | ^ ...is captured and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound | diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 9a7df8c0188b1..9c803d4e1d417 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -4,7 +4,7 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... LL | Box::new(B(&*v)) as Box - | ^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^ ...is captured and required to live as long as `'static` here | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index a7a9b16b08013..27bb19a89df3b 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -4,7 +4,7 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... LL | Box::new(B(&*v)) as Box - | ^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^ ...is captured and required to live as long as `'static` here | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 50b3748bf40e9..a257576e5d167 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -5,7 +5,7 @@ LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { | ------ this data with an anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) - | ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr index 04560ea4e297a..3d6308a08254c 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -39,13 +39,13 @@ LL | let y = x as &dyn Bar<'_, '_>; | ...is captured here... LL | LL | y.get_b() // ERROR - | --------- ...is required to live as long as `'static` here... + | - ...is captured here... | -note: ...and is captured here too +note: ...and is required to live as long as `'static` here --> $DIR/type-checking-test-4.rs:29:5 | LL | y.get_b() // ERROR - | ^ + | ^^^^^^^^^ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/type-checking-test-4.rs:33:5 @@ -53,7 +53,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | ------------ this data with lifetime `'a`... LL | <_ as Bar>::get_b(x) // ERROR - | ^^^^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/type-checking-test-4.rs:38:15 @@ -61,7 +61,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | ------------ this data with lifetime `'a`... LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR - | ----------^^---------------- ...is captured and required to live as long as `'static` here + | ----------^^------------- ...is captured and required to live as long as `'static` here error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/type-checking-test-4.rs:43:27 @@ -74,16 +74,16 @@ LL | let y = x as &dyn Bar<'_, '_>; | ...is captured here... LL | LL | y.get_b(); // ERROR - | - ...and is captured here too + | - ...is captured here... LL | let z = y; LL | z.get_b() // ERROR - | --------- ...is required to live as long as `'static` here... + | - ...is captured here... | -note: ...and is captured here too +note: ...and is required to live as long as `'static` here --> $DIR/type-checking-test-4.rs:47:5 | LL | z.get_b() // ERROR - | ^ + | ^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index de3a6bbae1795..da0f6d0ecde3d 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -5,7 +5,9 @@ LL | fn a(items: &[T]) -> Box> { | ---- this data with an anonymous lifetime `'_`... LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ---------------^^^^--- ...is captured and required to live as long as `'static` here + | ----- ^^^^ + | | + | ...is captured and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound | From ab45ab83ac0c9b19b6d692ca5d2e9b7b98c3565a Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 12 Oct 2021 08:56:24 +0000 Subject: [PATCH 25/38] review comments * take diagnostic logic out of happy-path * sort/dedup once * add more comments --- .../nice_region_error/static_impl_trait.rs | 10 ++++- .../src/infer/lexical_region_resolve/mod.rs | 40 ++++++++++--------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 3f7aa7773d1c0..e1f2ec4443182 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -150,8 +150,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if mention_capture { spans.push(sup_origin.span()); } - spans.sort(); - spans.dedup(); + // We sort the spans *ignoring* expansion context. Below, the closure logic is repeated + // because one method expects a closure taking `&Span` and the other `&mut Span`. + spans.sort_by_key(|span| (span.lo(), span.hi())); + spans.dedup_by_key(|span| (span.lo(), span.hi())); // We try to make the output have fewer overlapping spans if possible. let (require_msg, require_span) = if sup_origin.span().overlaps(return_sp) { @@ -165,8 +167,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) { + // If any of the "captured here" labels appears on the same line or after + // `require_span`, we put it on a note to ensure the text flows by appearing + // always at the end. err.span_note(require_span, require_msg); } else { + // We don't need a note, it's already at the end, it can be shown as a `span_label`. err.span_label(require_span, require_msg); } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 14f6c72bb1ce9..3d4e96fa0f269 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -146,8 +146,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let graph = self.construct_graph(); self.expand_givens(&graph); self.expansion(&mut var_data); - let captures = self.collect_errors(&mut var_data, errors); - self.collect_var_errors(&var_data, &graph, errors, captures); + self.collect_errors(&mut var_data, errors); + self.collect_var_errors(&var_data, &graph, errors); var_data } @@ -445,16 +445,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { &self, var_data: &mut LexicalRegionResolutions<'tcx>, errors: &mut Vec>, - ) -> Vec { - let mut captures = vec![]; - + ) { for (constraint, origin) in &self.data.constraints { debug!(?constraint, ?origin); - if let (Constraint::VarSubVar(_, _), SubregionOrigin::DataBorrowed(_, sp)) = - (constraint, origin) - { - captures.push(*sp); - } match *constraint { Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => { // Expansion will ensure that these constraints hold. Ignore. @@ -524,7 +517,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { sub, )); } - captures } /// Go over the variables that were declared to be error variables @@ -534,7 +526,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { var_data: &LexicalRegionResolutions<'tcx>, graph: &RegionGraph<'tcx>, errors: &mut Vec>, - captures: Vec, ) { debug!("collect_var_errors, var_data = {:#?}", var_data.values); @@ -578,12 +569,27 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // if this rule starts to create problems we'll // have to revisit this portion of the code and // think hard about it. =) -- nikomatsakis + + // Obtain the spans for all the capture points for + // richer diagnostics in `static_impl_trait`. + let captures: Vec = self + .data + .constraints + .iter() + .filter_map(|(constraint, origin)| match (constraint, origin) { + (Constraint::VarSubVar(_, _), SubregionOrigin::DataBorrowed(_, sp)) => { + Some(*sp) + } + _ => None, + }) + .collect(); + self.collect_error_for_expanding_node( graph, &mut dup_vec, node_vid, errors, - &captures, + captures, ); } } @@ -638,7 +644,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { dup_vec: &mut IndexVec>, node_idx: RegionVid, errors: &mut Vec>, - captures: &[Span], + captures: Vec, ) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. @@ -686,10 +692,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { origin, node_idx, lower_bound.region, upper_bound.region ); - let mut capture_spans: Vec = captures.iter().cloned().collect(); - // Below, one span expects `&Span` and the other `&mut Span`, hence the dupes. - capture_spans.sort_by_key(|span| (span.lo(), span.hi())); - capture_spans.dedup_by_key(|span| (span.lo(), span.hi())); errors.push(RegionResolutionError::SubSupConflict( node_idx, origin, @@ -697,7 +699,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { lower_bound.region, upper_bound.origin.clone(), upper_bound.region, - capture_spans, + captures, )); return; } From 09dbf37213a5462c08e5e62e931aabc2fb3b92e4 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 12 Oct 2021 09:19:14 +0000 Subject: [PATCH 26/38] Add filtering based on involved required lifetime More accurate filtering still needed. --- .../nice_region_error/static_impl_trait.rs | 8 +++-- .../src/infer/lexical_region_resolve/mod.rs | 29 ++++++++++--------- .../ui/async-await/issues/issue-62097.stderr | 7 +---- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index e1f2ec4443182..daeb406a83983 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -156,11 +156,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { spans.dedup_by_key(|span| (span.lo(), span.hi())); // We try to make the output have fewer overlapping spans if possible. - let (require_msg, require_span) = if sup_origin.span().overlaps(return_sp) { - ("...is captured and required to live as long as `'static` here", sup_origin.span()) + let require_msg = if spans.is_empty() { + "...is captured and required to live as long as `'static` here" } else { - ("...and is required to live as long as `'static` here", return_sp) + "...and is required to live as long as `'static` here" }; + let require_span = + if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp }; for span in &spans { err.span_label(*span, "...is captured here..."); diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 3d4e96fa0f269..b6c1e1f5922fc 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -48,7 +48,7 @@ pub fn resolve<'tcx>( values.values.iter_mut().for_each(|v| match *v { VarValue::Value(ref mut r) => *r = re_erased, - VarValue::ErrorValue => {} + VarValue::ErrorValue(_) => {} }); (values, errors) } @@ -69,7 +69,7 @@ pub struct LexicalRegionResolutions<'tcx> { #[derive(Copy, Clone, Debug)] enum VarValue<'tcx> { Value(Region<'tcx>), - ErrorValue, + ErrorValue(RegionVid), } #[derive(Clone, Debug)] @@ -233,7 +233,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { (None, a_region, b_vid, b_data) } Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) { - VarValue::ErrorValue => continue, + VarValue::ErrorValue(_) => continue, VarValue::Value(a_region) => { let b_data = var_values.value_mut(b_vid); (Some(a_vid), a_region, b_vid, b_data) @@ -250,7 +250,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } if let Some(a_vid) = a_vid { match *b_data { - VarValue::Value(ReStatic) | VarValue::ErrorValue => (), + VarValue::Value(ReStatic) | VarValue::ErrorValue(_) => (), _ => { constraints[a_vid].push((a_vid, b_vid)); constraints[b_vid].push((a_vid, b_vid)); @@ -262,14 +262,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { while let Some(vid) = changes.pop() { constraints[vid].retain(|&(a_vid, b_vid)| { let a_region = match *var_values.value(a_vid) { - VarValue::ErrorValue => return false, + VarValue::ErrorValue(_) => return false, VarValue::Value(a_region) => a_region, }; let b_data = var_values.value_mut(b_vid); if self.expand_node(a_region, b_vid, b_data) { changes.push(b_vid); } - !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue) + !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue(_)) }); } } @@ -332,7 +332,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { true } - VarValue::ErrorValue => false, + VarValue::ErrorValue(_) => false, } } @@ -476,7 +476,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region); let a_region = match *a_data { - VarValue::ErrorValue => continue, + VarValue::ErrorValue(_) => continue, VarValue::Value(a_region) => a_region, }; @@ -489,7 +489,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { cannot verify that {:?}={:?} <= {:?}", origin, a_vid, a_region, b_region ); - *a_data = VarValue::ErrorValue; + *a_data = VarValue::ErrorValue(a_vid); } } } @@ -545,7 +545,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { for (node_vid, value) in var_data.values.iter_enumerated() { match *value { VarValue::Value(_) => { /* Inference successful */ } - VarValue::ErrorValue => { + VarValue::ErrorValue(reg) => { // Inference impossible: this value contains // inconsistent constraints. // @@ -577,9 +577,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { .constraints .iter() .filter_map(|(constraint, origin)| match (constraint, origin) { - (Constraint::VarSubVar(_, _), SubregionOrigin::DataBorrowed(_, sp)) => { - Some(*sp) - } + ( + Constraint::VarSubVar(_, sup), + SubregionOrigin::DataBorrowed(_, sp), + ) if sup == ® => Some(*sp), _ => None, }) .collect(); @@ -898,7 +899,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> { let result = match self.values[rid] { VarValue::Value(r) => r, - VarValue::ErrorValue => self.error_region, + VarValue::ErrorValue(_) => self.error_region, }; debug!("resolve_var({:?}) = {:?}", rid, result); result diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 7aea147c6cfc2..11fb7c86c3bdd 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -4,13 +4,8 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `' LL | pub async fn run_dummy_fn(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... LL | foo(|| self.bar()).await; - | ------------------------ ...is captured here... + | --- ...is captured and required to live as long as `'static` here | -note: ...and is required to live as long as `'static` here - --> $DIR/issue-62097.rs:13:9 - | -LL | foo(|| self.bar()).await; - | ^^^ note: `'static` lifetime requirement introduced by this bound --> $DIR/issue-62097.rs:4:19 | From ee0fd105d86f4998a341b9a819735f1087423492 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 12 Oct 2021 09:52:32 +0000 Subject: [PATCH 27/38] Point at return type when it introduces `'static` obligation --- .../nice_region_error/static_impl_trait.rs | 20 ++++++++++++ .../project-fn-ret-invariant.transmute.stderr | 9 ++++++ .../must_outlive_least_region_or_bound.stderr | 28 ++++++++++++++++ ...ect-lifetime-default-from-box-error.stderr | 8 +++++ .../region-object-lifetime-in-coercion.stderr | 15 +++++++++ .../regions-close-object-into-object-2.stderr | 7 ++++ .../regions-close-object-into-object-4.stderr | 7 ++++ .../regions/regions-proc-bound-capture.stderr | 8 +++++ .../type-checking-test-4.stderr | 32 +++++++++++++++++++ .../dyn-trait-underscore.stderr | 8 +++++ 10 files changed, 142 insertions(+) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index daeb406a83983..34015b97e3c40 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -181,6 +181,26 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { err.span_note(*bound, "`'static` lifetime requirement introduced by this bound"); } + if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { + if let ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code { + let parent_id = tcx.hir().get_parent_item(*hir_id); + if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) { + let mut span: MultiSpan = fn_decl.output.span().into(); + span.push_span_label( + fn_decl.output.span(), + "requirement introduced by this return type".to_string(), + ); + span.push_span_label( + cause.span, + "because of this returned expression".to_string(), + ); + err.span_note( + span, + "`'static` lifetime requirement introduced by the return type", + ); + } + } + } let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index eb81da7852d99..49264ae2505b9 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -6,6 +6,15 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { ... LL | bar(foo, x) | ^^^ - ...is captured and required to live as long as `'static` here + | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/project-fn-ret-invariant.rs:45:32 + | +LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { + | ^^^^^^^^^^^^^ requirement introduced by this return type +... +LL | bar(foo, x) + | ----------- because of this returned expression error: aborting due to previous error diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index e80372766dc3c..d0d9ed8923d55 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -140,6 +140,13 @@ LL | fn elided3(x: &i32) -> Box { Box::new(x) } | | | this data with an anonymous lifetime `'_`... | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/must_outlive_least_region_or_bound.rs:14:24 + | +LL | fn elided3(x: &i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^^^^ ----------- because of this returned expression + | | + | requirement introduced by this return type help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound | LL | fn elided3(x: &i32) -> Box { Box::new(x) } @@ -153,6 +160,13 @@ LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | | | this data with lifetime `'a`... | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/must_outlive_least_region_or_bound.rs:16:33 + | +LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^^^^ ----------- because of this returned expression + | | + | requirement introduced by this return type help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } @@ -166,6 +180,13 @@ LL | fn elided4(x: &i32) -> Box { Box::new(x) } | | | this data with an anonymous lifetime `'_`... | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/must_outlive_least_region_or_bound.rs:18:24 + | +LL | fn elided4(x: &i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- because of this returned expression + | | + | requirement introduced by this return type help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } @@ -181,6 +202,13 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ------- this data with lifetime `'a`... ^ ...is captured and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/must_outlive_least_region_or_bound.rs:20:33 + | +LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- because of this returned expression + | | + | requirement introduced by this return type help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index e0a8534cd28fa..c882e3c9d0693 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -7,6 +7,14 @@ LL | fn load(ss: &mut SomeStruct) -> Box { LL | ss.r | ^^^^ ...is captured and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/object-lifetime-default-from-box-error.rs:14:33 + | +LL | fn load(ss: &mut SomeStruct) -> Box { + | ^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +... +LL | ss.r + | ---- because of this returned expression help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound | LL | fn load(ss: &mut SomeStruct) -> Box { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 9eb24c1bd372e..45a3c801a3889 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -23,6 +23,13 @@ LL | fn b(v: &[u8]) -> Box { LL | Box::new(v) | ^ ...is captured and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/region-object-lifetime-in-coercion.rs:12:19 + | +LL | fn b(v: &[u8]) -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +LL | Box::new(v) + | ----------- because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn b(v: &[u8]) -> Box { @@ -41,6 +48,14 @@ LL | fn c(v: &[u8]) -> Box { LL | Box::new(v) | ^ ...is captured and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/region-object-lifetime-in-coercion.rs:16:19 + | +LL | fn c(v: &[u8]) -> Box { + | ^^^^^^^^^^^^ requirement introduced by this return type +... +LL | Box::new(v) + | ----------- because of this returned expression help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound | LL | fn c(v: &[u8]) -> Box { diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 9c803d4e1d417..a924fbc5bf7fe 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -6,6 +6,13 @@ LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { LL | Box::new(B(&*v)) as Box | ^^^ ...is captured and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/regions-close-object-into-object-2.rs:8:48 + | +LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { + | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +LL | Box::new(B(&*v)) as Box + | ------------------------------ because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 27bb19a89df3b..969222068eeab 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -6,6 +6,13 @@ LL | fn i<'a, T, U>(v: Box+'a>) -> Box { LL | Box::new(B(&*v)) as Box | ^^^ ...is captured and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/regions-close-object-into-object-4.rs:8:40 + | +LL | fn i<'a, T, U>(v: Box+'a>) -> Box { + | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +LL | Box::new(B(&*v)) as Box + | ------------------------------ because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index a257576e5d167..3bbbf00d5e732 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -7,6 +7,14 @@ LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) | ^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/regions-proc-bound-capture.rs:7:30 + | +LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +LL | // This is illegal, because the region bound on `proc` is 'static. +LL | Box::new(move || { *x }) + | ------------------------ because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn static_proc(x: &isize) -> Box (isize) + '_> { diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr index 3d6308a08254c..c06943c087453 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -46,6 +46,14 @@ note: ...and is required to live as long as `'static` here | LL | y.get_b() // ERROR | ^^^^^^^^^ +note: `'static` lifetime requirement introduced by the return type + --> $DIR/type-checking-test-4.rs:26:40 + | +LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +... +LL | y.get_b() // ERROR + | --------- because of this returned expression error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/type-checking-test-4.rs:33:5 @@ -54,6 +62,14 @@ LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | ------------ this data with lifetime `'a`... LL | <_ as Bar>::get_b(x) // ERROR | ^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here + | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/type-checking-test-4.rs:32:40 + | +LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +LL | <_ as Bar>::get_b(x) // ERROR + | -------------------- because of this returned expression error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/type-checking-test-4.rs:38:15 @@ -62,6 +78,14 @@ LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | ------------ this data with lifetime `'a`... LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR | ----------^^------------- ...is captured and required to live as long as `'static` here + | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/type-checking-test-4.rs:37:40 + | +LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR + | ---------------------------- because of this returned expression error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/type-checking-test-4.rs:43:27 @@ -84,6 +108,14 @@ note: ...and is required to live as long as `'static` here | LL | z.get_b() // ERROR | ^^^^^^^^^ +note: `'static` lifetime requirement introduced by the return type + --> $DIR/type-checking-test-4.rs:42:40 + | +LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +... +LL | z.get_b() // ERROR + | --------- because of this returned expression error: aborting due to 6 previous errors diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index da0f6d0ecde3d..3fed7ba6c495b 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -9,6 +9,14 @@ LL | Box::new(items.iter()) | | | ...is captured and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/dyn-trait-underscore.rs:6:25 + | +LL | fn a(items: &[T]) -> Box> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type +LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` +LL | Box::new(items.iter()) + | ---------------------- because of this returned expression help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound | LL | fn a(items: &[T]) -> Box + '_> { From 10a74ac2e0f57f3aaf67991bf4c5be994f240236 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 12 Oct 2021 13:14:11 +0000 Subject: [PATCH 28/38] Use a more accurate `Span` for `'static` obligation from return type --- .../nice_region_error/static_impl_trait.rs | 28 ++++++++++++--- compiler/rustc_middle/src/ty/context.rs | 36 ++----------------- compiler/rustc_middle/src/ty/diagnostics.rs | 20 +++++++++++ .../project-fn-ret-invariant.transmute.stderr | 4 +-- .../must_outlive_least_region_or_bound.stderr | 32 ++++++++--------- ...ect-lifetime-default-from-box-error.stderr | 4 +-- .../region-object-lifetime-in-coercion.stderr | 8 ++--- .../regions-close-object-into-object-2.stderr | 4 +-- .../regions-close-object-into-object-4.stderr | 4 +-- .../regions/regions-proc-bound-capture.stderr | 4 +-- .../type-checking-test-4.stderr | 16 ++++----- .../dyn-trait-underscore.stderr | 4 +-- 12 files changed, 85 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 34015b97e3c40..80bdccd4f2cf1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -10,7 +10,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; use rustc_middle::ty::{ - self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor, + self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable, + TypeVisitor, }; use rustc_span::symbol::Ident; use rustc_span::{MultiSpan, Span}; @@ -186,10 +187,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let parent_id = tcx.hir().get_parent_item(*hir_id); if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) { let mut span: MultiSpan = fn_decl.output.span().into(); - span.push_span_label( - fn_decl.output.span(), - "requirement introduced by this return type".to_string(), - ); + let mut add_label = true; + if let hir::FnRetTy::Return(ty) = fn_decl.output { + let mut v = StaticLifetimeVisitor(vec![], tcx.hir()); + v.visit_ty(ty); + if !v.0.is_empty() { + span = v.0.clone().into(); + for sp in v.0 { + span.push_span_label( + sp, + "`'static` requirement introduced here".to_string(), + ); + } + add_label = false; + } + } + if add_label { + span.push_span_label( + fn_decl.output.span(), + "requirement introduced by this return type".to_string(), + ); + } span.push_span_label( cause.span, "because of this returned expression".to_string(), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 275a2128c4556..0bf457ca8a824 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1481,40 +1481,8 @@ impl<'tcx> TyCtxt<'tcx> { scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); - let hir_output = match self.hir().get(hir_id) { - Node::Item(hir::Item { - kind: - ItemKind::Fn( - hir::FnSig { - decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, - .. - }, - .., - ), - .. - }) - | Node::ImplItem(hir::ImplItem { - kind: - hir::ImplItemKind::Fn( - hir::FnSig { - decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, - .. - }, - _, - ), - .. - }) - | Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn( - hir::FnSig { - decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, - .. - }, - _, - ), - .. - }) => ty, + let hir_output = match self.hir().fn_decl_by_hir_id(hir_id) { + Some(hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }) => ty, _ => return vec![], }; diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8803370251b38..1acb3ec57dea6 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -6,6 +6,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; +use rustc_span::Span; impl<'tcx> TyS<'tcx> { /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. @@ -432,3 +433,22 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { hir::intravisit::walk_ty(self, ty); } } + +/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. +pub struct StaticLifetimeVisitor<'tcx>(pub Vec, pub crate::hir::map::Map<'tcx>); + +impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { + type Map = rustc_hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) { + if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = + lt.name + { + self.0.push(lt.span); + } + } +} diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 49264ae2505b9..628023ad4710d 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -8,10 +8,10 @@ LL | bar(foo, x) | ^^^ - ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/project-fn-ret-invariant.rs:45:32 + --> $DIR/project-fn-ret-invariant.rs:45:37 | LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { - | ^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here ... LL | bar(foo, x) | ----------- because of this returned expression diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index d0d9ed8923d55..bf1f93aebd55a 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -141,12 +141,12 @@ LL | fn elided3(x: &i32) -> Box { Box::new(x) } | this data with an anonymous lifetime `'_`... | note: `'static` lifetime requirement introduced by the return type - --> $DIR/must_outlive_least_region_or_bound.rs:14:24 + --> $DIR/must_outlive_least_region_or_bound.rs:14:28 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^^^^ ----------- because of this returned expression - | | - | requirement introduced by this return type + | ^^^^^^^^^ ----------- because of this returned expression + | | + | `'static` requirement introduced here help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound | LL | fn elided3(x: &i32) -> Box { Box::new(x) } @@ -161,12 +161,12 @@ LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | this data with lifetime `'a`... | note: `'static` lifetime requirement introduced by the return type - --> $DIR/must_outlive_least_region_or_bound.rs:16:33 + --> $DIR/must_outlive_least_region_or_bound.rs:16:37 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^^^^ ----------- because of this returned expression - | | - | requirement introduced by this return type + | ^^^^^^^^^ ----------- because of this returned expression + | | + | `'static` requirement introduced here help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } @@ -181,12 +181,12 @@ LL | fn elided4(x: &i32) -> Box { Box::new(x) } | this data with an anonymous lifetime `'_`... | note: `'static` lifetime requirement introduced by the return type - --> $DIR/must_outlive_least_region_or_bound.rs:18:24 + --> $DIR/must_outlive_least_region_or_bound.rs:18:40 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- because of this returned expression - | | - | requirement introduced by this return type + | ^^^^^^^ ----------- because of this returned expression + | | + | `'static` requirement introduced here help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } @@ -203,12 +203,12 @@ LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ------- this data with lifetime `'a`... ^ ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/must_outlive_least_region_or_bound.rs:20:33 + --> $DIR/must_outlive_least_region_or_bound.rs:20:49 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- because of this returned expression - | | - | requirement introduced by this return type + | ^^^^^^^ ----------- because of this returned expression + | | + | `'static` requirement introduced here help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index c882e3c9d0693..0308ecf8f64fb 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -8,10 +8,10 @@ LL | ss.r | ^^^^ ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/object-lifetime-default-from-box-error.rs:14:33 + --> $DIR/object-lifetime-default-from-box-error.rs:14:37 | LL | fn load(ss: &mut SomeStruct) -> Box { - | ^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^^^^^^^ `'static` requirement introduced here ... LL | ss.r | ---- because of this returned expression diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 45a3c801a3889..74683f1439ae8 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -24,10 +24,10 @@ LL | Box::new(v) | ^ ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/region-object-lifetime-in-coercion.rs:12:19 + --> $DIR/region-object-lifetime-in-coercion.rs:12:33 | LL | fn b(v: &[u8]) -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here LL | Box::new(v) | ----------- because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` @@ -49,10 +49,10 @@ LL | Box::new(v) | ^ ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/region-object-lifetime-in-coercion.rs:16:19 + --> $DIR/region-object-lifetime-in-coercion.rs:16:23 | LL | fn c(v: &[u8]) -> Box { - | ^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here ... LL | Box::new(v) | ----------- because of this returned expression diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index a924fbc5bf7fe..c914d91306c58 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -7,10 +7,10 @@ LL | Box::new(B(&*v)) as Box | ^^^ ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/regions-close-object-into-object-2.rs:8:48 + --> $DIR/regions-close-object-into-object-2.rs:8:60 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { - | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here LL | Box::new(B(&*v)) as Box | ------------------------------ because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 969222068eeab..1f68db023a96b 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -7,10 +7,10 @@ LL | Box::new(B(&*v)) as Box | ^^^ ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/regions-close-object-into-object-4.rs:8:40 + --> $DIR/regions-close-object-into-object-4.rs:8:52 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { - | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here LL | Box::new(B(&*v)) as Box | ------------------------------ because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 3bbbf00d5e732..9965763203555 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -8,10 +8,10 @@ LL | Box::new(move || { *x }) | ^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/regions-proc-bound-capture.rs:7:30 + --> $DIR/regions-proc-bound-capture.rs:7:59 | LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) | ------------------------ because of this returned expression diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr index c06943c087453..42230ddd6955b 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -47,10 +47,10 @@ note: ...and is required to live as long as `'static` here LL | y.get_b() // ERROR | ^^^^^^^^^ note: `'static` lifetime requirement introduced by the return type - --> $DIR/type-checking-test-4.rs:26:40 + --> $DIR/type-checking-test-4.rs:26:48 | LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { - | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here ... LL | y.get_b() // ERROR | --------- because of this returned expression @@ -64,10 +64,10 @@ LL | <_ as Bar>::get_b(x) // ERROR | ^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/type-checking-test-4.rs:32:40 + --> $DIR/type-checking-test-4.rs:32:48 | LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { - | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here LL | <_ as Bar>::get_b(x) // ERROR | -------------------- because of this returned expression @@ -80,10 +80,10 @@ LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR | ----------^^------------- ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/type-checking-test-4.rs:37:40 + --> $DIR/type-checking-test-4.rs:37:48 | LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { - | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR | ---------------------------- because of this returned expression @@ -109,10 +109,10 @@ note: ...and is required to live as long as `'static` here LL | z.get_b() // ERROR | ^^^^^^^^^ note: `'static` lifetime requirement introduced by the return type - --> $DIR/type-checking-test-4.rs:42:40 + --> $DIR/type-checking-test-4.rs:42:48 | LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { - | ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^ `'static` requirement introduced here ... LL | z.get_b() // ERROR | --------- because of this returned expression diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 3fed7ba6c495b..b8552c872c11a 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -10,10 +10,10 @@ LL | Box::new(items.iter()) | ...is captured and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/dyn-trait-underscore.rs:6:25 + --> $DIR/dyn-trait-underscore.rs:6:29 | LL | fn a(items: &[T]) -> Box> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type + | ^^^^^^^^^^^^^^^^^^^^^ `'static` requirement introduced here LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) | ---------------------- because of this returned expression From 0ee723edb54031afdd6e5f07a6daf19dcc34e665 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 12 Oct 2021 13:16:36 +0000 Subject: [PATCH 29/38] Update nll test --- .../ui/async-await/issues/issue-72312.nll.stderr | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/ui/async-await/issues/issue-72312.nll.stderr diff --git a/src/test/ui/async-await/issues/issue-72312.nll.stderr b/src/test/ui/async-await/issues/issue-72312.nll.stderr new file mode 100644 index 0000000000000..cf7723ada563d --- /dev/null +++ b/src/test/ui/async-await/issues/issue-72312.nll.stderr @@ -0,0 +1,15 @@ +error[E0521]: borrowed data escapes outside of associated function + --> $DIR/issue-72312.rs:13:24 + | +LL | pub async fn start(&self) { + | ----- `self` is a reference that is only valid in the associated function body +... +LL | require_static(async move { + | ________________________^ +LL | | &self; +LL | | }); + | |_________^ `self` escapes the associated function body here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. From ff13ad710f7332079d4ea494f5b0bced68d41429 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 12 Oct 2021 13:28:02 +0000 Subject: [PATCH 30/38] rebase and update nll test --- src/test/ui/async-await/issues/issue-72312.nll.stderr | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/ui/async-await/issues/issue-72312.nll.stderr b/src/test/ui/async-await/issues/issue-72312.nll.stderr index cf7723ada563d..068d8c64d6898 100644 --- a/src/test/ui/async-await/issues/issue-72312.nll.stderr +++ b/src/test/ui/async-await/issues/issue-72312.nll.stderr @@ -2,13 +2,19 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-72312.rs:13:24 | LL | pub async fn start(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` ... LL | require_static(async move { | ________________________^ LL | | &self; LL | | }); - | |_________^ `self` escapes the associated function body here + | | ^ + | | | + | |_________`self` escapes the associated function body here + | argument requires that `'1` must outlive `'static` error: aborting due to previous error From 83ce1aad428d79ac455fa43b40e0e01b07fcf7cf Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 15 Oct 2021 15:13:21 +0000 Subject: [PATCH 31/38] Tweak wording --- .../nice_region_error/static_impl_trait.rs | 6 ++--- ...ject-fn-ret-contravariant.transmute.stderr | 2 +- .../project-fn-ret-invariant.transmute.stderr | 2 +- .../ui/async-await/issues/issue-62097.stderr | 2 +- src/test/ui/async-await/issues/issue-72312.rs | 2 +- .../ui/async-await/issues/issue-72312.stderr | 2 +- .../dyn-trait.stderr | 2 +- .../must_outlive_least_region_or_bound.stderr | 24 +++++++++---------- src/test/ui/issues/issue-16922.stderr | 2 +- .../constant-in-expr-inherent-1.stderr | 2 +- ...ect-lifetime-default-from-box-error.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 6 ++--- .../ui/regions/regions-addr-of-self.stderr | 2 +- .../regions-close-object-into-object-2.stderr | 2 +- .../regions-close-object-into-object-4.stderr | 2 +- .../regions/regions-proc-bound-capture.stderr | 2 +- ...atic-bound-needing-more-suggestions.stderr | 2 +- ...yn-trait-with-implicit-static-bound.stderr | 12 +++++----- .../trait-object-nested-in-impl-trait.stderr | 8 +++---- .../type-checking-test-4.stderr | 14 +++++------ .../dyn-trait-underscore.stderr | 2 +- 21 files changed, 50 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 80bdccd4f2cf1..1176f131107e6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -76,7 +76,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_label( cause.span, &format!( - "...is captured and required to live as long as `'static` here \ + "...is used and required to live as long as `'static` here \ because of an implicit lifetime bound on the {}", match ctxt.assoc_item.container { AssocItemContainer::TraitContainer(id) => @@ -158,7 +158,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // We try to make the output have fewer overlapping spans if possible. let require_msg = if spans.is_empty() { - "...is captured and required to live as long as `'static` here" + "...is used and required to live as long as `'static` here" } else { "...and is required to live as long as `'static` here" }; @@ -166,7 +166,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp }; for span in &spans { - err.span_label(*span, "...is captured here..."); + err.span_label(*span, "...is used here..."); } if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) { diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index 6f63a2c5fc37e..33f1e0f05b252 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -4,7 +4,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { | ------- this data with lifetime `'a`... LL | bar(foo, x) - | ^^^ - ...is captured and required to live as long as `'static` here + | ^^^ - ...is used and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 628023ad4710d..609627aaa9ef0 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -5,7 +5,7 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { | -------- this data with lifetime `'a`... ... LL | bar(foo, x) - | ^^^ - ...is captured and required to live as long as `'static` here + | ^^^ - ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/project-fn-ret-invariant.rs:45:37 diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 11fb7c86c3bdd..e23277543c66f 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -4,7 +4,7 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `' LL | pub async fn run_dummy_fn(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... LL | foo(|| self.bar()).await; - | --- ...is captured and required to live as long as `'static` here + | --- ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by this bound --> $DIR/issue-62097.rs:4:19 diff --git a/src/test/ui/async-await/issues/issue-72312.rs b/src/test/ui/async-await/issues/issue-72312.rs index eb0cc7e6aeca1..eb7d12e290cb6 100644 --- a/src/test/ui/async-await/issues/issue-72312.rs +++ b/src/test/ui/async-await/issues/issue-72312.rs @@ -11,7 +11,7 @@ impl Problem { //~^ NOTE this data with an anonymous lifetime `'_` //~| NOTE in this expansion of desugaring of `async` block or function require_static(async move { //~ NOTE ...and is required to live as long as `'static` here - &self; //~ NOTE ...is captured here... + &self; //~ NOTE ...is used here... }); } } diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr index 7a72edd4e5310..798f755765cc1 100644 --- a/src/test/ui/async-await/issues/issue-72312.stderr +++ b/src/test/ui/async-await/issues/issue-72312.stderr @@ -5,7 +5,7 @@ LL | pub async fn start(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... ... LL | &self; - | ----- ...is captured here... + | ----- ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/issue-72312.rs:13:9 diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index b3bef677d19c1..2307572cc3f24 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -4,7 +4,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn with_dyn_debug_static<'a>(x: Box) { | ------------------- this data with lifetime `'a`... LL | static_val(x); - | ^ ...is captured here... + | ^ ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/dyn-trait.rs:20:5 diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index bf1f93aebd55a..de5d3b612c9c2 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -28,7 +28,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:9:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } - | ---- ^ ...is captured here... + | ---- ^ ...is used here... | | | this data with an anonymous lifetime `'_`... | @@ -50,7 +50,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:11:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } - | ------- ^ ...is captured here... + | ------- ^ ...is used here... | | | this data with lifetime `'a`... | @@ -80,7 +80,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:24:65 | LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } - | ---- this data with an anonymous lifetime `'_`... ^ ...is captured and required to live as long as `'static` here + | ---- this data with an anonymous lifetime `'_`... ^ ...is used and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound | @@ -95,7 +95,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:29:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } - | ------- this data with lifetime `'a`... ^ ...is captured here... + | ------- this data with lifetime `'a`... ^ ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/must_outlive_least_region_or_bound.rs:29:34 @@ -136,12 +136,12 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:16:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured and required to live as long as `'static` here + | ---- ^ ...is used and required to live as long as `'static` here | | | this data with an anonymous lifetime `'_`... | note: `'static` lifetime requirement introduced by the return type - --> $DIR/must_outlive_least_region_or_bound.rs:14:28 + --> $DIR/must_outlive_least_region_or_bound.rs:16:28 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } | ^^^^^^^^^ ----------- because of this returned expression @@ -156,12 +156,12 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:18:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- ^ ...is captured and required to live as long as `'static` here + | ------- ^ ...is used and required to live as long as `'static` here | | | this data with lifetime `'a`... | note: `'static` lifetime requirement introduced by the return type - --> $DIR/must_outlive_least_region_or_bound.rs:16:37 + --> $DIR/must_outlive_least_region_or_bound.rs:18:37 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^^^^^^^^ ----------- because of this returned expression @@ -176,12 +176,12 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:20:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured and required to live as long as `'static` here + | ---- ^ ...is used and required to live as long as `'static` here | | | this data with an anonymous lifetime `'_`... | note: `'static` lifetime requirement introduced by the return type - --> $DIR/must_outlive_least_region_or_bound.rs:18:40 + --> $DIR/must_outlive_least_region_or_bound.rs:20:40 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } | ^^^^^^^ ----------- because of this returned expression @@ -200,10 +200,10 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:22:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- this data with lifetime `'a`... ^ ...is captured and required to live as long as `'static` here + | ------- this data with lifetime `'a`... ^ ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type - --> $DIR/must_outlive_least_region_or_bound.rs:20:49 + --> $DIR/must_outlive_least_region_or_bound.rs:22:49 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } | ^^^^^^^ ----------- because of this returned expression diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index ff7b3b67140c2..53405a660f861 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -4,7 +4,7 @@ error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a ` LL | fn foo(value: &T) -> Box { | -- this data with an anonymous lifetime `'_`... LL | Box::new(value) as Box - | ^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^ ...is used and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound | diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index 1931934a2112a..4a6378b84f1e6 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -4,7 +4,7 @@ error[E0759]: `fn` parameter has lifetime `'a` but it needs to satisfy a `'stati LL | fn foo<'a>(_: &'a u32) -> &'static u32 { | ------- this data with lifetime `'a`... LL | >::C - | ^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^^^^^ ...is used and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 0308ecf8f64fb..1708700f77aaa 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -5,7 +5,7 @@ LL | fn load(ss: &mut SomeStruct) -> Box { | --------------- this data with an anonymous lifetime `'_`... ... LL | ss.r - | ^^^^ ...is captured and required to live as long as `'static` here + | ^^^^ ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/object-lifetime-default-from-box-error.rs:14:37 diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 74683f1439ae8..d8932c067acd8 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -4,7 +4,7 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn a(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... LL | let x: Box = Box::new(v); - | ^ ...is captured and required to live as long as `'static` here + | ^ ...is used and required to live as long as `'static` here | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | @@ -21,7 +21,7 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn b(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... LL | Box::new(v) - | ^ ...is captured and required to live as long as `'static` here + | ^ ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/region-object-lifetime-in-coercion.rs:12:33 @@ -46,7 +46,7 @@ LL | fn c(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... ... LL | Box::new(v) - | ^ ...is captured and required to live as long as `'static` here + | ^ ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/region-object-lifetime-in-coercion.rs:16:23 diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr index 738691fd695eb..3453c6458f1da 100644 --- a/src/test/ui/regions/regions-addr-of-self.stderr +++ b/src/test/ui/regions/regions-addr-of-self.stderr @@ -4,7 +4,7 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `' LL | pub fn chase_cat(&mut self) { | --------- this data with an anonymous lifetime `'_`... LL | let p: &'static mut usize = &mut self.cats_chased; - | ^^^^^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index c914d91306c58..4153f4f29bc28 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -4,7 +4,7 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... LL | Box::new(B(&*v)) as Box - | ^^^ ...is captured and required to live as long as `'static` here + | ^^^ ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/regions-close-object-into-object-2.rs:8:60 diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 1f68db023a96b..2ea4b431b38da 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -4,7 +4,7 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... LL | Box::new(B(&*v)) as Box - | ^^^ ...is captured and required to live as long as `'static` here + | ^^^ ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/regions-close-object-into-object-4.rs:8:52 diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 9965763203555..2ebe874da9350 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -5,7 +5,7 @@ LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { | ------ this data with an anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) - | ^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/regions-proc-bound-capture.rs:7:59 diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr index 2961d8d7eacc9..63d291ed7cdb9 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -22,7 +22,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: Box + 'a>) -> &'a () { | -------------------------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:60:30 diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 6d9f0811b2735..55a1bbf18ab9f 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -4,7 +4,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ---------------------- this data with lifetime `'a`... LL | val.use_self::() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32 @@ -24,7 +24,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl` + | ^^^^^^^^ ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl` | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14 @@ -44,7 +44,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:85:26 @@ -69,7 +69,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ------------------- this data with lifetime `'a`... LL | MyTrait::use_self(val) - | ^^^ ...is captured here... + | ^^^ ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 @@ -95,7 +95,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26 @@ -115,7 +115,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: &'a Box) -> &'a () { | ----------------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30 diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr index 1ca22ebeef479..a5b50634c71ea 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr @@ -7,7 +7,7 @@ LL | fn iter(&self) -> impl Iterator> { LL | remaining: self.0.iter(), | ------ ^^^^ | | - | ...is captured here... + | ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/trait-object-nested-in-impl-trait.rs:27:23 @@ -32,7 +32,7 @@ LL | fn iter(&self) -> impl Iterator> + '_ { LL | remaining: self.0.iter(), | ------ ^^^^ | | - | ...is captured here... + | ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/trait-object-nested-in-impl-trait.rs:38:23 @@ -53,7 +53,7 @@ LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { LL | remaining: self.0.iter(), | ------ ^^^^ | | - | ...is captured here... + | ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/trait-object-nested-in-impl-trait.rs:49:30 @@ -74,7 +74,7 @@ LL | fn iter<'a>(&'a self) -> impl Iterator> { LL | remaining: self.0.iter(), | ------ ^^^^ | | - | ...is captured here... + | ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/trait-object-nested-in-impl-trait.rs:60:30 diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr index 42230ddd6955b..d4bb9350b0b4e 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -36,10 +36,10 @@ LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { LL | let y = x as &dyn Bar<'_, '_>; | - ^^ | | - | ...is captured here... + | ...is used here... LL | LL | y.get_b() // ERROR - | - ...is captured here... + | - ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/type-checking-test-4.rs:29:5 @@ -61,7 +61,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | ------------ this data with lifetime `'a`... LL | <_ as Bar>::get_b(x) // ERROR - | ^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/type-checking-test-4.rs:32:48 @@ -77,7 +77,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | ------------ this data with lifetime `'a`... LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR - | ----------^^------------- ...is captured and required to live as long as `'static` here + | ----------^^------------- ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/type-checking-test-4.rs:37:48 @@ -95,13 +95,13 @@ LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { LL | let y = x as &dyn Bar<'_, '_>; | - ^^ | | - | ...is captured here... + | ...is used here... LL | LL | y.get_b(); // ERROR - | - ...is captured here... + | - ...is used here... LL | let z = y; LL | z.get_b() // ERROR - | - ...is captured here... + | - ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/type-checking-test-4.rs:47:5 diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index b8552c872c11a..f4285a0f98e7c 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -7,7 +7,7 @@ LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to LL | Box::new(items.iter()) | ----- ^^^^ | | - | ...is captured and required to live as long as `'static` here + | ...is used and required to live as long as `'static` here | note: `'static` lifetime requirement introduced by the return type --> $DIR/dyn-trait-underscore.rs:6:29 From 9cc7bd769208a9db9670649d6fdede04f1a886fc Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 22:23:41 +0000 Subject: [PATCH 32/38] Review comments --- .../nice_region_error/static_impl_trait.rs | 9 +++++---- .../src/infer/lexical_region_resolve/mod.rs | 13 +++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 1176f131107e6..dab0b87f7ae4a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -151,9 +151,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if mention_capture { spans.push(sup_origin.span()); } - // We sort the spans *ignoring* expansion context. Below, the closure logic is repeated - // because one method expects a closure taking `&Span` and the other `&mut Span`. - spans.sort_by_key(|span| (span.lo(), span.hi())); + // We dedup the spans *ignoring* expansion context. + spans.sort(); spans.dedup_by_key(|span| (span.lo(), span.hi())); // We try to make the output have fewer overlapping spans if possible. @@ -183,7 +182,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_note(*bound, "`'static` lifetime requirement introduced by this bound"); } if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { - if let ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code { + if let ObligationCauseCode::ReturnValue(hir_id) + | ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code + { let parent_id = tcx.hir().get_parent_item(*hir_id); if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) { let mut span: MultiSpan = fn_decl.output.span().into(); diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index b6c1e1f5922fc..08a58fa67e0c3 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -97,7 +97,7 @@ pub enum RegionResolutionError<'tcx> { Region<'tcx>, SubregionOrigin<'tcx>, Region<'tcx>, - Vec, + Vec, // All the influences on a given value that didn't meet its constraints. ), /// Indicates a `'b: 'a` constraint where `'a` is in a universe that @@ -570,9 +570,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // have to revisit this portion of the code and // think hard about it. =) -- nikomatsakis - // Obtain the spans for all the capture points for + // Obtain the spans for all the places that can + // influence the constraints on this value for // richer diagnostics in `static_impl_trait`. - let captures: Vec = self + let influences: Vec = self .data .constraints .iter() @@ -590,7 +591,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { &mut dup_vec, node_vid, errors, - captures, + influences, ); } } @@ -645,7 +646,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { dup_vec: &mut IndexVec>, node_idx: RegionVid, errors: &mut Vec>, - captures: Vec, + influences: Vec, ) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. @@ -700,7 +701,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { lower_bound.region, upper_bound.origin.clone(), upper_bound.region, - captures, + influences, )); return; } From d33fa135fe1c03ee51a84f7c6bb03a53eb3e3eed Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 16 Nov 2021 22:58:54 +0000 Subject: [PATCH 33/38] Remove field from `ErrorValue` --- .../src/infer/lexical_region_resolve/mod.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 08a58fa67e0c3..85ee6d2cdc282 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -48,7 +48,7 @@ pub fn resolve<'tcx>( values.values.iter_mut().for_each(|v| match *v { VarValue::Value(ref mut r) => *r = re_erased, - VarValue::ErrorValue(_) => {} + VarValue::ErrorValue => {} }); (values, errors) } @@ -69,7 +69,7 @@ pub struct LexicalRegionResolutions<'tcx> { #[derive(Copy, Clone, Debug)] enum VarValue<'tcx> { Value(Region<'tcx>), - ErrorValue(RegionVid), + ErrorValue, } #[derive(Clone, Debug)] @@ -233,7 +233,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { (None, a_region, b_vid, b_data) } Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) { - VarValue::ErrorValue(_) => continue, + VarValue::ErrorValue => continue, VarValue::Value(a_region) => { let b_data = var_values.value_mut(b_vid); (Some(a_vid), a_region, b_vid, b_data) @@ -250,7 +250,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } if let Some(a_vid) = a_vid { match *b_data { - VarValue::Value(ReStatic) | VarValue::ErrorValue(_) => (), + VarValue::Value(ReStatic) | VarValue::ErrorValue => (), _ => { constraints[a_vid].push((a_vid, b_vid)); constraints[b_vid].push((a_vid, b_vid)); @@ -262,14 +262,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { while let Some(vid) = changes.pop() { constraints[vid].retain(|&(a_vid, b_vid)| { let a_region = match *var_values.value(a_vid) { - VarValue::ErrorValue(_) => return false, + VarValue::ErrorValue => return false, VarValue::Value(a_region) => a_region, }; let b_data = var_values.value_mut(b_vid); if self.expand_node(a_region, b_vid, b_data) { changes.push(b_vid); } - !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue(_)) + !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue) }); } } @@ -332,7 +332,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { true } - VarValue::ErrorValue(_) => false, + VarValue::ErrorValue => false, } } @@ -476,7 +476,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region); let a_region = match *a_data { - VarValue::ErrorValue(_) => continue, + VarValue::ErrorValue => continue, VarValue::Value(a_region) => a_region, }; @@ -489,7 +489,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { cannot verify that {:?}={:?} <= {:?}", origin, a_vid, a_region, b_region ); - *a_data = VarValue::ErrorValue(a_vid); + *a_data = VarValue::ErrorValue; } } } @@ -545,7 +545,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { for (node_vid, value) in var_data.values.iter_enumerated() { match *value { VarValue::Value(_) => { /* Inference successful */ } - VarValue::ErrorValue(reg) => { + VarValue::ErrorValue => { // Inference impossible: this value contains // inconsistent constraints. // @@ -581,7 +581,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ( Constraint::VarSubVar(_, sup), SubregionOrigin::DataBorrowed(_, sp), - ) if sup == ® => Some(*sp), + ) if sup == &node_vid => Some(*sp), _ => None, }) .collect(); @@ -900,7 +900,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> { let result = match self.values[rid] { VarValue::Value(r) => r, - VarValue::ErrorValue(_) => self.error_region, + VarValue::ErrorValue => self.error_region, }; debug!("resolve_var({:?}) = {:?}", rid, result); result From da5b0cc851535e1f4af667ab15254b2e8f85f3a3 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 10 Dec 2021 03:18:03 +0000 Subject: [PATCH 34/38] review comment --- .../error_reporting/nice_region_error/static_impl_trait.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index dab0b87f7ae4a..36d880292525c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -126,7 +126,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { lifetime, ); - let (mention_capture, capture_point) = if sup_origin.span().overlaps(param.param_ty_span) { + let (mention_influencer, influencer_point) = if sup_origin.span().overlaps(param.param_ty_span) { // Account for `async fn` like in `async-await/issues/issue-62097.rs`. // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same // place (but with different `ctxt`, hence `overlaps` instead of `==` above). @@ -142,13 +142,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } else { (!sup_origin.span().overlaps(return_sp), param.param_ty_span) }; - err.span_label(capture_point, &format!("this data with {}...", lifetime)); + err.span_label(influencer_point, &format!("this data with {}...", lifetime)); debug!("try_report_static_impl_trait: param_info={:?}", param); let mut spans = spans.clone(); - if mention_capture { + if mention_influencer { spans.push(sup_origin.span()); } // We dedup the spans *ignoring* expansion context. From 40f161aeb0981030d3959acd239cb0bb2e600597 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 10 Dec 2021 03:18:29 +0000 Subject: [PATCH 35/38] fix tests after rebase --- ...losure-bounds-static-cant-capture-borrowed.stderr | 7 ++++++- .../generator/generator-region-requirements.stderr | 2 +- .../projection-type-lifetime-mismatch.stderr | 12 +++++++++--- src/test/ui/issues/issue-46983.stderr | 2 +- ...ssue-90600-expected-return-static-indirect.stderr | 2 +- src/test/ui/regions/regions-static-bound.stderr | 4 ++-- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr index d761abdfc6a34..af1f908a80852 100644 --- a/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr +++ b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr @@ -8,13 +8,18 @@ LL | bar(|| { LL | | LL | | let _ = x; LL | | }) - | |_____^ ...is captured here... + | |_____^ ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5 | LL | bar(|| { | ^^^ +note: `'static` lifetime requirement introduced by this bound + --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:1:39 + | +LL | fn bar(blk: F) where F: FnOnce() + 'static { + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/generator/generator-region-requirements.stderr b/src/test/ui/generator/generator-region-requirements.stderr index b6b9db22426eb..30d67050b904c 100644 --- a/src/test/ui/generator/generator-region-requirements.stderr +++ b/src/test/ui/generator/generator-region-requirements.stderr @@ -5,7 +5,7 @@ LL | fn dangle(x: &mut i32) -> &'static mut i32 { | -------- this data with an anonymous lifetime `'_`... ... LL | x - | ^ ...is captured here... + | ^ ...is used here... ... LL | GeneratorState::Complete(c) => return c, | - ...and is required to live as long as `'static` here diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr index 1ffd205652f66..32c5ccf164874 100644 --- a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr @@ -4,7 +4,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn f(x: &impl for<'a> X = &'a ()>) -> &'static () { | ------------------------------- this data with an anonymous lifetime `'_`... LL | x.m() - | --^-- ...is captured and required to live as long as `'static` here + | - ^ + | | + | ...is used and required to live as long as `'static` here error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/projection-type-lifetime-mismatch.rs:22:7 @@ -12,7 +14,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn g X = &'a ()>>(x: &T) -> &'static () { | -- this data with an anonymous lifetime `'_`... LL | x.m() - | --^-- ...is captured and required to live as long as `'static` here + | - ^ + | | + | ...is used and required to live as long as `'static` here error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/projection-type-lifetime-mismatch.rs:27:7 @@ -20,7 +24,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn h(x: &()) -> &'static () { | --- this data with an anonymous lifetime `'_`... LL | x.m() - | --^-- ...is captured and required to live as long as `'static` here + | - ^ + | | + | ...is used and required to live as long as `'static` here error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-46983.stderr b/src/test/ui/issues/issue-46983.stderr index 77fb130f5192e..ed9f1884c42fb 100644 --- a/src/test/ui/issues/issue-46983.stderr +++ b/src/test/ui/issues/issue-46983.stderr @@ -4,7 +4,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn foo(x: &u32) -> &'static u32 { | ---- this data with an anonymous lifetime `'_`... LL | &*x - | ^^^ ...is captured and required to live as long as `'static` here + | ^^^ ...is used and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr index 3f65d3af725cf..e06255e4ea3ff 100644 --- a/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr +++ b/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr @@ -4,7 +4,7 @@ error[E0759]: `foo` has an anonymous lifetime `'_` but it needs to satisfy a `'s LL | fn inner(mut foo: &[u8]) { | ----- this data with an anonymous lifetime `'_`... LL | let refcell = RefCell::new(&mut foo); - | ^^^^^^^^ ...is captured here... + | ^^^^^^^^ ...is used here... ... LL | read_thing(read); | ---- ...and is required to live as long as `'static` here diff --git a/src/test/ui/regions/regions-static-bound.stderr b/src/test/ui/regions/regions-static-bound.stderr index 51fe16ca9da03..b8e69e02609d6 100644 --- a/src/test/ui/regions/regions-static-bound.stderr +++ b/src/test/ui/regions/regions-static-bound.stderr @@ -17,7 +17,7 @@ error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn error(u: &(), v: &()) { | --- this data with an anonymous lifetime `'_`... LL | static_id(&u); - | ^^^^^^^^^ -- ...is captured here... + | ^^^^^^^^^ -- ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/regions-static-bound.rs:10:5 @@ -32,7 +32,7 @@ LL | fn error(u: &(), v: &()) { | --- this data with an anonymous lifetime `'_`... LL | static_id(&u); LL | static_id_indirect(&v); - | ^^^^^^^^^^^^^^^^^^ -- ...is captured here... + | ^^^^^^^^^^^^^^^^^^ -- ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/regions-static-bound.rs:11:5 From 99789d0168b6f769f4a9a4d13f9ba6b4ff4c2998 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 10 Dec 2021 17:20:57 +0000 Subject: [PATCH 36/38] fix clippy tests --- .../clippy/tests/ui/future_not_send.stderr | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr index 3cc05e2fdbec6..a9f2ad36d0aba 100644 --- a/src/tools/clippy/tests/ui/future_not_send.stderr +++ b/src/tools/clippy/tests/ui/future_not_send.stderr @@ -6,22 +6,22 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | = note: `-D clippy::future-not-send` implied by `-D warnings` note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:8:5 + --> $DIR/future_not_send.rs:8:19 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | -- has type `std::rc::Rc<[u8]>` which is not `Send` LL | async { true }.await - | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later + | ^^^^^^ await occurs here, with `rc` maybe used later LL | } | - `rc` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:8:5 + --> $DIR/future_not_send.rs:8:19 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ---- has type `&std::cell::Cell` which is not `Send` LL | async { true }.await - | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `cell` maybe used later + | ^^^^^^ await occurs here, with `cell` maybe used later LL | } | - `cell` is later dropped here = note: `std::cell::Cell` doesn't implement `std::marker::Sync` @@ -33,12 +33,12 @@ LL | pub async fn public_future(rc: Rc<[u8]>) { | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:12:5 + --> $DIR/future_not_send.rs:12:19 | LL | pub async fn public_future(rc: Rc<[u8]>) { | -- has type `std::rc::Rc<[u8]>` which is not `Send` LL | async { true }.await; - | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later + | ^^^^^^ await occurs here, with `rc` maybe used later LL | } | - `rc` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` @@ -82,12 +82,12 @@ LL | async fn private_future(&self) -> usize { | ^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:35:9 + --> $DIR/future_not_send.rs:35:23 | LL | async fn private_future(&self) -> usize { | ----- has type `&Dummy` which is not `Send` LL | async { true }.await; - | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later + | ^^^^^^ await occurs here, with `&self` maybe used later LL | self.rc.len() LL | } | - `&self` is later dropped here @@ -100,12 +100,12 @@ LL | pub async fn public_future(&self) { | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:40:9 + --> $DIR/future_not_send.rs:40:30 | LL | pub async fn public_future(&self) { | ----- has type `&Dummy` which is not `Send` LL | self.private_future().await; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later + | ^^^^^^ await occurs here, with `&self` maybe used later LL | } | - `&self` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` @@ -117,12 +117,12 @@ LL | async fn generic_future(t: T) -> T | ^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:54:5 + --> $DIR/future_not_send.rs:54:19 | LL | let rt = &t; | -- has type `&T` which is not `Send` LL | async { true }.await; - | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rt` maybe used later + | ^^^^^^ await occurs here, with `rt` maybe used later LL | t LL | } | - `rt` is later dropped here From d2d9eb3715e61d16eafb55b4b8cb03fdc6bfc871 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 10 Dec 2021 17:22:33 +0000 Subject: [PATCH 37/38] fmt --- .../nice_region_error/static_impl_trait.rs | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 36d880292525c..80d4a2e57da4a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -126,22 +126,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { lifetime, ); - let (mention_influencer, influencer_point) = if sup_origin.span().overlaps(param.param_ty_span) { - // Account for `async fn` like in `async-await/issues/issue-62097.rs`. - // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same - // place (but with different `ctxt`, hence `overlaps` instead of `==` above). - // - // This avoids the following: - // - // LL | pub async fn run_dummy_fn(&self) { - // | ^^^^^ - // | | - // | this data with an anonymous lifetime `'_`... - // | ...is captured here... - (false, sup_origin.span()) - } else { - (!sup_origin.span().overlaps(return_sp), param.param_ty_span) - }; + let (mention_influencer, influencer_point) = + if sup_origin.span().overlaps(param.param_ty_span) { + // Account for `async fn` like in `async-await/issues/issue-62097.rs`. + // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same + // place (but with different `ctxt`, hence `overlaps` instead of `==` above). + // + // This avoids the following: + // + // LL | pub async fn run_dummy_fn(&self) { + // | ^^^^^ + // | | + // | this data with an anonymous lifetime `'_`... + // | ...is captured here... + (false, sup_origin.span()) + } else { + (!sup_origin.span().overlaps(return_sp), param.param_ty_span) + }; err.span_label(influencer_point, &format!("this data with {}...", lifetime)); debug!("try_report_static_impl_trait: param_info={:?}", param); From e27315268b10c9ef2f4c3d815dfc79f513327def Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 15 Mar 2021 15:09:06 -0700 Subject: [PATCH 38/38] Suggest using a temporary variable to fix borrowck errors In Rust, nesting method calls with both require `&mut` access to `self` produces a borrow-check error: error[E0499]: cannot borrow `*self` as mutable more than once at a time --> src/lib.rs:7:14 | 7 | self.foo(self.bar()); | ---------^^^^^^^^^^- | | | | | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here That's because Rust has a left-to-right evaluation order, and the method receiver is passed first. Thus, the argument to the method cannot then mutate `self`. There's an easy solution to this error: just extract a local variable for the inner argument: let tmp = self.bar(); self.foo(tmp); However, the error doesn't give any suggestion of how to solve the problem. As a result, new users may assume that it's impossible to express their code correctly and get stuck. This commit adds a (non-structured) suggestion to extract a local variable for the inner argument to solve the error. The suggestion uses heuristics that eliminate most false positives, though there are a few false negatives (cases where the suggestion should be emitted but is not). Those other cases can be implemented in a future change. --- .../src/diagnostics/conflict_errors.rs | 89 ++++++++++++++++++- .../src/diagnostics/find_all_local_uses.rs | 26 ++++++ .../rustc_borrowck/src/diagnostics/mod.rs | 1 + compiler/rustc_middle/src/mir/mod.rs | 14 +++ .../borrowck/suggest-local-var-double-mut.rs | 27 ++++++ .../suggest-local-var-double-mut.stderr | 44 +++++++++ .../suggest-local-var-imm-and-mut.nll.stderr | 33 +++++++ .../borrowck/suggest-local-var-imm-and-mut.rs | 27 ++++++ .../suggest-local-var-imm-and-mut.stderr | 22 +++++ ...wo-phase-cannot-nest-mut-self-calls.stderr | 17 ++++ src/test/ui/codemap_tests/one_line.stderr | 11 +++ 11 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs create mode 100644 src/test/ui/borrowck/suggest-local-var-double-mut.rs create mode 100644 src/test/ui/borrowck/suggest-local-var-double-mut.stderr create mode 100644 src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr create mode 100644 src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs create mode 100644 src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8c4508ed18882..98c619cdd291c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -15,16 +15,18 @@ use rustc_span::symbol::sym; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; +use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; +use crate::diagnostics::find_all_local_uses; use crate::{ borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, }; use super::{ - explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName, - RegionNameSource, UseSpans, + explain_borrow::{BorrowExplanation, LaterUseKind}, + FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans, }; #[derive(Debug)] @@ -768,9 +770,92 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some((issued_span, span)), ); + self.suggest_using_local_if_applicable( + &mut err, + location, + (place, span), + gen_borrow_kind, + issued_borrow, + explanation, + ); + err } + #[instrument(level = "debug", skip(self, err))] + fn suggest_using_local_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + location: Location, + (place, span): (Place<'tcx>, Span), + gen_borrow_kind: BorrowKind, + issued_borrow: &BorrowData<'tcx>, + explanation: BorrowExplanation, + ) { + let used_in_call = + matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _)); + if !used_in_call { + debug!("not later used in call"); + return; + } + + let outer_call_loc = + if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { + loc + } else { + issued_borrow.reserve_location + }; + let outer_call_stmt = self.body.stmt_at(outer_call_loc); + + let inner_param_location = location; + let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else { + debug!("`inner_param_location` {:?} is not for a statement", inner_param_location); + return; + }; + let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else { + debug!( + "`inner_param_location` {:?} is not for an assignment: {:?}", + inner_param_location, inner_param_stmt + ); + return; + }; + let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local); + let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| { + let Either::Right(term) = self.body.stmt_at(loc) else { + debug!("{:?} is a statement, so it can't be a call", loc); + return None; + }; + let TerminatorKind::Call { args, .. } = &term.kind else { + debug!("not a call: {:?}", term); + return None; + }; + debug!("checking call args for uses of inner_param: {:?}", args); + if args.contains(&Operand::Move(inner_param)) { + Some((loc,term)) + } else { + None + } + }) else { + debug!("no uses of inner_param found as a by-move call arg"); + return; + }; + debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc); + + let inner_call_span = inner_call_term.source_info.span; + let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span; + if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) { + // FIXME: This stops the suggestion in some cases where it should be emitted. + // Fix the spans for those cases so it's emitted correctly. + debug!( + "outer span {:?} does not strictly contain inner span {:?}", + outer_call_span, inner_call_span + ); + return; + } + err.span_help(inner_call_span, "try adding a local storing this argument..."); + err.span_help(outer_call_span, "...and then using that local as the argument to this call"); + } + fn suggest_split_at_mut_if_applicable( &self, err: &mut DiagnosticBuilder<'_>, diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs new file mode 100644 index 0000000000000..49d9caae71144 --- /dev/null +++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs @@ -0,0 +1,26 @@ +use std::collections::BTreeSet; + +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location}; + +/// Find all uses of (including assignments to) a [`Local`]. +/// +/// Uses `BTreeSet` so output is deterministic. +pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet { + let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() }; + visitor.visit_body(body); + visitor.uses +} + +struct AllLocalUsesVisitor { + for_local: Local, + uses: BTreeSet, +} + +impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor { + fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) { + if *local == self.for_local { + self.uses.insert(location); + } + } +} diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 42f5d55754208..dec1940ace881 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -19,6 +19,7 @@ use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; +mod find_all_local_uses; mod find_use; mod outlives_suggestion; mod region_name; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d4530883b6a10..afd8083dfe46a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -12,6 +12,7 @@ use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; + use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{self, GeneratorKind}; @@ -30,6 +31,9 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; + +use either::Either; + use std::borrow::Cow; use std::convert::TryInto; use std::fmt::{self, Debug, Display, Formatter, Write}; @@ -503,6 +507,16 @@ impl<'tcx> Body<'tcx> { Location { block: bb, statement_index: self[bb].statements.len() } } + pub fn stmt_at(&self, location: Location) -> Either<&Statement<'tcx>, &Terminator<'tcx>> { + let Location { block, statement_index } = location; + let block_data = &self.basic_blocks[block]; + block_data + .statements + .get(statement_index) + .map(Either::Left) + .unwrap_or_else(|| Either::Right(block_data.terminator())) + } + #[inline] pub fn predecessors(&self) -> &Predecessors { self.predecessor_cache.compute(&self.basic_blocks) diff --git a/src/test/ui/borrowck/suggest-local-var-double-mut.rs b/src/test/ui/borrowck/suggest-local-var-double-mut.rs new file mode 100644 index 0000000000000..d5996ba68be53 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-double-mut.rs @@ -0,0 +1,27 @@ +// See issue #77834. + +#![crate_type = "lib"] + +mod method_syntax { + struct Foo; + + impl Foo { + fn foo(&mut self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + self.foo(self.bar()); //~ ERROR + } + } +} + +mod fully_qualified_syntax { + struct Foo; + + impl Foo { + fn foo(&mut self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + Self::foo(self, Self::bar(self)); //~ ERROR + } + } +} diff --git a/src/test/ui/borrowck/suggest-local-var-double-mut.stderr b/src/test/ui/borrowck/suggest-local-var-double-mut.stderr new file mode 100644 index 0000000000000..3a43c18a7ed52 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-double-mut.stderr @@ -0,0 +1,44 @@ +error[E0499]: cannot borrow `*self` as mutable more than once at a time + --> $DIR/suggest-local-var-double-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ---------^^^^^^^^^^- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/suggest-local-var-double-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/suggest-local-var-double-mut.rs:12:13 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0499]: cannot borrow `*self` as mutable more than once at a time + --> $DIR/suggest-local-var-double-mut.rs:24:39 + | +LL | Self::foo(self, Self::bar(self)); + | --------- ---- ^^^^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call + | +help: try adding a local storing this argument... + --> $DIR/suggest-local-var-double-mut.rs:24:29 + | +LL | Self::foo(self, Self::bar(self)); + | ^^^^^^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/suggest-local-var-double-mut.rs:24:13 + | +LL | Self::foo(self, Self::bar(self)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr new file mode 100644 index 0000000000000..2ba0b6b28aaaa --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr @@ -0,0 +1,33 @@ +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ---------^^^^^^^^^^- + | | | | + | | | mutable borrow occurs here + | | immutable borrow later used by call + | immutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/suggest-local-var-imm-and-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/suggest-local-var-imm-and-mut.rs:12:13 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:24:39 + | +LL | Self::foo(self, Self::bar(self)); + | --------- ---- ^^^^ mutable borrow occurs here + | | | + | | immutable borrow occurs here + | immutable borrow later used by call + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs new file mode 100644 index 0000000000000..bf167ba79f311 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs @@ -0,0 +1,27 @@ +// See issue #77834. + +#![crate_type = "lib"] + +mod method_syntax { + struct Foo; + + impl Foo { + fn foo(&self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + self.foo(self.bar()); //~ ERROR + } + } +} + +mod fully_qualified_syntax { + struct Foo; + + impl Foo { + fn foo(&self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + Self::foo(self, Self::bar(self)); //~ ERROR + } + } +} diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr new file mode 100644 index 0000000000000..eb934e7b72b08 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr @@ -0,0 +1,22 @@ +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ---------^^^^^^^^^^- + | | | | + | | | mutable borrow occurs here + | | immutable borrow later used by call + | immutable borrow occurs here + +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:24:29 + | +LL | Self::foo(self, Self::bar(self)); + | --------- ---- ^^^^^^^^^^^^^^^ mutable borrow occurs here + | | | + | | immutable borrow occurs here + | immutable borrow later used by call + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr index a89bb941532b6..85c7159952ffa 100644 --- a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr +++ b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr @@ -13,6 +13,23 @@ LL | | LL | | 0 LL | | }); | |______- immutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:16:9 + | +LL | vec.push(2); + | ^^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:14:5 + | +LL | / vec.get({ +LL | | +LL | | vec.push(2); +LL | | +LL | | +LL | | 0 +LL | | }); + | |______^ error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/one_line.stderr b/src/test/ui/codemap_tests/one_line.stderr index 1ee612184def2..6fe6e26135b92 100644 --- a/src/test/ui/codemap_tests/one_line.stderr +++ b/src/test/ui/codemap_tests/one_line.stderr @@ -7,6 +7,17 @@ LL | v.push(v.pop().unwrap()); | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/one_line.rs:3:12 + | +LL | v.push(v.pop().unwrap()); + | ^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/one_line.rs:3:5 + | +LL | v.push(v.pop().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error