From 54daf496e2e957a9f69aa88bf6c42520a2dbfa02 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 25 Apr 2022 15:19:50 +0200 Subject: [PATCH 01/17] std: directly use pthread in UNIX parker implementation Mutex and Condvar are being replaced by more efficient implementations, which need thread parking themselves (see #93740). Therefore use the pthread synchronization primitives directly. Also, avoid allocating because the Parker struct is being placed in an Arc anyways. --- library/std/src/sys/unix/mod.rs | 1 + library/std/src/sys/unix/thread_parker.rs | 303 ++++++++++++++++++ library/std/src/sys/windows/thread_parker.rs | 20 +- .../std/src/sys_common/thread_parker/futex.rs | 18 +- .../src/sys_common/thread_parker/generic.rs | 24 +- .../std/src/sys_common/thread_parker/mod.rs | 2 + library/std/src/thread/mod.rs | 32 +- 7 files changed, 372 insertions(+), 28 deletions(-) create mode 100644 library/std/src/sys/unix/thread_parker.rs diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index aedeb02e656d6..8e909aab7f0ca 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -39,6 +39,7 @@ pub mod stdio; pub mod thread; pub mod thread_local_dtor; pub mod thread_local_key; +pub mod thread_parker; pub mod time; #[cfg(target_os = "espidf")] diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker.rs new file mode 100644 index 0000000000000..90bdb46c4b075 --- /dev/null +++ b/library/std/src/sys/unix/thread_parker.rs @@ -0,0 +1,303 @@ +//! Thread parking without `futex` using the `pthread` synchronization primitives. + +#![cfg(not(any( + target_os = "linux", + target_os = "android", + all(target_os = "emscripten", target_feature = "atomics") +)))] + +use crate::cell::UnsafeCell; +use crate::marker::PhantomPinned; +use crate::pin::Pin; +use crate::ptr::addr_of_mut; +use crate::sync::atomic::AtomicUsize; +use crate::sync::atomic::Ordering::SeqCst; +use crate::time::Duration; + +const EMPTY: usize = 0; +const PARKED: usize = 1; +const NOTIFIED: usize = 2; + +unsafe fn lock(lock: *mut libc::pthread_mutex_t) { + let r = libc::pthread_mutex_lock(lock); + debug_assert_eq!(r, 0); +} + +unsafe fn unlock(lock: *mut libc::pthread_mutex_t) { + let r = libc::pthread_mutex_unlock(lock); + debug_assert_eq!(r, 0); +} + +unsafe fn notify_one(cond: *mut libc::pthread_cond_t) { + let r = libc::pthread_cond_signal(cond); + debug_assert_eq!(r, 0); +} + +unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) { + let r = libc::pthread_cond_wait(cond, lock); + debug_assert_eq!(r, 0); +} + +const TIMESPEC_MAX: libc::timespec = + libc::timespec { tv_sec: ::MAX, tv_nsec: 1_000_000_000 - 1 }; + +fn saturating_cast_to_time_t(value: u64) -> libc::time_t { + if value > ::MAX as u64 { ::MAX } else { value as libc::time_t } +} + +// This implementation is used on systems that support pthread_condattr_setclock +// where we configure the condition variable to use the monotonic clock (instead of +// the default system clock). This approach avoids all problems that result +// from changes made to the system time. +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "espidf")))] +unsafe fn wait_timeout( + cond: *mut libc::pthread_cond_t, + lock: *mut libc::pthread_mutex_t, + dur: Duration, +) { + use crate::mem; + + let mut now: libc::timespec = mem::zeroed(); + let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now); + assert_eq!(r, 0); + // Nanosecond calculations can't overflow because both values are below 1e9. + let nsec = dur.subsec_nanos() + now.tv_nsec as u32; + let sec = saturating_cast_to_time_t(dur.as_secs()) + .checked_add((nsec / 1_000_000_000) as libc::time_t) + .and_then(|s| s.checked_add(now.tv_sec)); + let nsec = nsec % 1_000_000_000; + let timeout = + sec.map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec as _ }).unwrap_or(TIMESPEC_MAX); + let r = libc::pthread_cond_timedwait(cond, lock, &timeout); + assert!(r == libc::ETIMEDOUT || r == 0); +} + +// This implementation is modeled after libcxx's condition_variable +// https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 +// https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "espidf"))] +unsafe fn wait_timeout( + cond: *mut libc::pthread_cond_t, + lock: *mut libc::pthread_mutex_t, + mut dur: Duration, +) { + use crate::ptr; + + // 1000 years + let max_dur = Duration::from_secs(1000 * 365 * 86400); + + if dur > max_dur { + // OSX implementation of `pthread_cond_timedwait` is buggy + // with super long durations. When duration is greater than + // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` + // in macOS Sierra return error 316. + // + // This program demonstrates the issue: + // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c + // + // To work around this issue, and possible bugs of other OSes, timeout + // is clamped to 1000 years, which is allowable per the API of `park_timeout` + // because of spurious wakeups. + dur = max_dur; + } + + let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 }; + let r = libc::gettimeofday(&mut sys_now, ptr::null_mut()); + debug_assert_eq!(r, 0); + let nsec = dur.subsec_nanos() as libc::c_long + (sys_now.tv_usec * 1000) as libc::c_long; + let extra = (nsec / 1_000_000_000) as libc::time_t; + let nsec = nsec % 1_000_000_000; + let seconds = saturating_cast_to_time_t(dur.as_secs()); + let timeout = sys_now + .tv_sec + .checked_add(extra) + .and_then(|s| s.checked_add(seconds)) + .map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec }) + .unwrap_or(TIMESPEC_MAX); + // And wait! + let r = libc::pthread_cond_timedwait(cond, lock, &timeout); + debug_assert!(r == libc::ETIMEDOUT || r == 0); +} + +pub struct Parker { + state: AtomicUsize, + lock: UnsafeCell, + cvar: UnsafeCell, + // The `pthread` primitives require a stable address, so make this struct `!Unpin`. + _pinned: PhantomPinned, +} + +impl Parker { + /// Construct the UNIX parker in-place. + /// + /// # Safety + /// The constructed parker must never be moved. + pub unsafe fn new(parker: *mut Parker) { + // Use the default mutex implementation to allow for simpler initialization. + // This could lead to undefined behaviour when deadlocking. This is avoided + // by not deadlocking. Note in particular the unlocking operation before any + // panic, as code after the panic could try to park again. + addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY)); + addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); + + cfg_if::cfg_if! { + if #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "l4re", + target_os = "android", + target_os = "redox" + ))] { + addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); + } else if #[cfg(target_os = "espidf")] { + let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null()); + assert_eq!(r, 0); + } else { + use crate::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + let r = libc::pthread_condattr_init(attr.as_mut_ptr()); + assert_eq!(r, 0); + let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); + assert_eq!(r, 0); + let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr()); + assert_eq!(r, 0); + let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); + assert_eq!(r, 0); + } + } + } + + // This implementation doesn't require `unsafe`, but other implementations + // may assume this is only called by the thread that owns the Parker. + pub unsafe fn park(self: Pin<&Self>) { + // If we were previously notified then we consume this notification and + // return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + + // Otherwise we need to coordinate going to sleep + lock(self.lock.get()); + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + Err(NOTIFIED) => { + // We must read here, even though we know it will be `NOTIFIED`. + // This is because `unpark` may have been called again since we read + // `NOTIFIED` in the `compare_exchange` above. We must perform an + // acquire operation that synchronizes with that `unpark` to observe + // any writes it made before the call to unpark. To do that we must + // read from the write it made to `state`. + let old = self.state.swap(EMPTY, SeqCst); + + unlock(self.lock.get()); + + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => { + unlock(self.lock.get()); + + panic!("inconsistent park state") + } + } + + loop { + wait(self.cvar.get(), self.lock.get()); + + match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { + Ok(_) => break, // got a notification + Err(_) => {} // spurious wakeup, go back to sleep + } + } + + unlock(self.lock.get()); + } + + // This implementation doesn't require `unsafe`, but other implementations + // may assume this is only called by the thread that owns the Parker. Use + // `Pin` to guarantee a stable address for the mutex and condition variable. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + // Like `park` above we have a fast path for an already-notified thread, and + // afterwards we start coordinating for a sleep. + // return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + + lock(self.lock.get()); + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + Err(NOTIFIED) => { + // We must read again here, see `park`. + let old = self.state.swap(EMPTY, SeqCst); + unlock(self.lock.get()); + + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => { + unlock(self.lock.get()); + panic!("inconsistent park_timeout state") + } + } + + // Wait with a timeout, and if we spuriously wake up or otherwise wake up + // from a notification we just want to unconditionally set the state back to + // empty, either consuming a notification or un-flagging ourselves as + // parked. + wait_timeout(self.cvar.get(), self.lock.get(), dur); + + match self.state.swap(EMPTY, SeqCst) { + NOTIFIED => unlock(self.lock.get()), // got a notification, hurray! + PARKED => unlock(self.lock.get()), // no notification, alas + n => { + unlock(self.lock.get()); + panic!("inconsistent park_timeout state: {n}") + } + } + } + + pub fn unpark(self: Pin<&Self>) { + // To ensure the unparked thread will observe any writes we made + // before this call, we must perform a release operation that `park` + // can synchronize with. To do that we must write `NOTIFIED` even if + // `state` is already `NOTIFIED`. That is why this must be a swap + // rather than a compare-and-swap that returns if it reads `NOTIFIED` + // on failure. + match self.state.swap(NOTIFIED, SeqCst) { + EMPTY => return, // no one was waiting + NOTIFIED => return, // already unparked + PARKED => {} // gotta go wake someone up + _ => panic!("inconsistent state in unpark"), + } + + // There is a period between when the parked thread sets `state` to + // `PARKED` (or last checked `state` in the case of a spurious wake + // up) and when it actually waits on `cvar`. If we were to notify + // during this period it would be ignored and then when the parked + // thread went to sleep it would never wake up. Fortunately, it has + // `lock` locked at this stage so we can acquire `lock` to wait until + // it is ready to receive the notification. + // + // Releasing `lock` before the call to `notify_one` means that when the + // parked thread wakes it doesn't get woken only to have to wait for us + // to release `lock`. + unsafe { + lock(self.lock.get()); + unlock(self.lock.get()); + notify_one(self.cvar.get()); + } + } +} + +impl Drop for Parker { + fn drop(&mut self) { + unsafe { + libc::pthread_cond_destroy(self.cvar.get_mut()); + libc::pthread_mutex_destroy(self.lock.get_mut()); + } + } +} + +unsafe impl Sync for Parker {} +unsafe impl Send for Parker {} diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index 3497da51deeda..5144834447503 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -58,6 +58,7 @@ // [4]: Windows Internals, Part 1, ISBN 9780735671300 use crate::convert::TryFrom; +use crate::pin::Pin; use crate::ptr; use crate::sync::atomic::{ AtomicI8, AtomicPtr, @@ -95,13 +96,16 @@ const NOTIFIED: i8 = 1; // Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using // Ordering::Acquire when reading this state in park() after waking up. impl Parker { - pub fn new() -> Self { - Self { state: AtomicI8::new(EMPTY) } + /// Construct the Windows parker. The UNIX parker implementation + /// requires this to happen in-place. + pub unsafe fn new(parker: *mut Parker) { + parker.write(Self { state: AtomicI8::new(EMPTY) }); } // Assumes this is only called by the thread that owns the Parker, - // which means that `self.state != PARKED`. - pub unsafe fn park(&self) { + // which means that `self.state != PARKED`. This implementation doesn't require `Pin`, + // but other implementations do. + pub unsafe fn park(self: Pin<&Self>) { // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the // first case. if self.state.fetch_sub(1, Acquire) == NOTIFIED { @@ -132,8 +136,9 @@ impl Parker { } // Assumes this is only called by the thread that owns the Parker, - // which means that `self.state != PARKED`. - pub unsafe fn park_timeout(&self, timeout: Duration) { + // which means that `self.state != PARKED`. This implementation doesn't require `Pin`, + // but other implementations do. + pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) { // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the // first case. if self.state.fetch_sub(1, Acquire) == NOTIFIED { @@ -184,7 +189,8 @@ impl Parker { } } - pub fn unpark(&self) { + // This implementation doesn't require `Pin`, but other implementations do. + pub fn unpark(self: Pin<&Self>) { // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and // wake the thread in the first case. // diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parker/futex.rs index fbf6231ff4ab3..d9e2f39e34518 100644 --- a/library/std/src/sys_common/thread_parker/futex.rs +++ b/library/std/src/sys_common/thread_parker/futex.rs @@ -1,3 +1,4 @@ +use crate::pin::Pin; use crate::sync::atomic::AtomicU32; use crate::sync::atomic::Ordering::{Acquire, Release}; use crate::sys::futex::{futex_wait, futex_wake}; @@ -32,14 +33,15 @@ pub struct Parker { // Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using // Ordering::Acquire when checking for this state in park(). impl Parker { - #[inline] - pub const fn new() -> Self { - Parker { state: AtomicU32::new(EMPTY) } + /// Construct the futex parker. The UNIX parker implementation + /// requires this to happen in-place. + pub unsafe fn new(parker: *mut Parker) { + parker.write(Self { state: AtomicU32::new(EMPTY) }); } // Assumes this is only called by the thread that owns the Parker, // which means that `self.state != PARKED`. - pub unsafe fn park(&self) { + pub unsafe fn park(self: Pin<&Self>) { // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the // first case. if self.state.fetch_sub(1, Acquire) == NOTIFIED { @@ -58,8 +60,9 @@ impl Parker { } // Assumes this is only called by the thread that owns the Parker, - // which means that `self.state != PARKED`. - pub unsafe fn park_timeout(&self, timeout: Duration) { + // which means that `self.state != PARKED`. This implementation doesn't + // require `Pin`, but other implementations do. + pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) { // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the // first case. if self.state.fetch_sub(1, Acquire) == NOTIFIED { @@ -78,8 +81,9 @@ impl Parker { } } + // This implementation doesn't require `Pin`, but other implementations do. #[inline] - pub fn unpark(&self) { + pub fn unpark(self: Pin<&Self>) { // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and // wake the thread in the first case. // diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs index ffb61200e15f9..f3d8b34d3fd39 100644 --- a/library/std/src/sys_common/thread_parker/generic.rs +++ b/library/std/src/sys_common/thread_parker/generic.rs @@ -1,5 +1,6 @@ //! Parker implementation based on a Mutex and Condvar. +use crate::pin::Pin; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::SeqCst; use crate::sync::{Condvar, Mutex}; @@ -16,13 +17,18 @@ pub struct Parker { } impl Parker { - pub fn new() -> Self { - Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() } + /// Construct the generic parker. The UNIX parker implementation + /// requires this to happen in-place. + pub unsafe fn new(parker: *mut Parker) { + parker.write(Parker { + state: AtomicUsize::new(EMPTY), + lock: Mutex::new(()), + cvar: Condvar::new(), + }); } - // This implementation doesn't require `unsafe`, but other implementations - // may assume this is only called by the thread that owns the Parker. - pub unsafe fn park(&self) { + // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. + pub unsafe fn park(self: Pin<&Self>) { // If we were previously notified then we consume this notification and // return quickly. if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { @@ -55,9 +61,8 @@ impl Parker { } } - // This implementation doesn't require `unsafe`, but other implementations - // may assume this is only called by the thread that owns the Parker. - pub unsafe fn park_timeout(&self, dur: Duration) { + // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { // Like `park` above we have a fast path for an already-notified thread, and // afterwards we start coordinating for a sleep. // return quickly. @@ -88,7 +93,8 @@ impl Parker { } } - pub fn unpark(&self) { + // This implementation doesn't require `Pin`, but other implementations do. + pub fn unpark(self: Pin<&Self>) { // To ensure the unparked thread will observe any writes we made // before this call, we must perform a release operation that `park` // can synchronize with. To do that we must write `NOTIFIED` even if diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index ba896bd676b67..ea0204cd357ba 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -8,6 +8,8 @@ cfg_if::cfg_if! { pub use futex::Parker; } else if #[cfg(windows)] { pub use crate::sys::thread_parker::Parker; + } else if #[cfg(target_family = "unix")] { + pub use crate::sys::thread_parker::Parker; } else { mod generic; pub use generic::Parker; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 5309dc47ac4e7..99da5f7a87e15 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -163,6 +163,8 @@ use crate::num::NonZeroU64; use crate::num::NonZeroUsize; use crate::panic; use crate::panicking; +use crate::pin::Pin; +use crate::ptr::addr_of_mut; use crate::str; use crate::sync::Arc; use crate::sys::thread as imp; @@ -923,7 +925,7 @@ pub fn sleep(dur: Duration) { pub fn park() { // SAFETY: park_timeout is called on the parker owned by this thread. unsafe { - current().inner.parker.park(); + current().inner.as_ref().parker().park(); } } @@ -987,7 +989,7 @@ pub fn park_timeout_ms(ms: u32) { pub fn park_timeout(dur: Duration) { // SAFETY: park_timeout is called on the parker owned by this thread. unsafe { - current().inner.parker.park_timeout(dur); + current().inner.as_ref().parker().park_timeout(dur); } } @@ -1073,6 +1075,12 @@ struct Inner { parker: Parker, } +impl Inner { + fn parker(self: Pin<&Self>) -> Pin<&Parker> { + unsafe { Pin::map_unchecked(self, |inner| &inner.parker) } + } +} + #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] /// A handle to a thread. @@ -1094,14 +1102,28 @@ struct Inner { /// /// [`thread::current`]: current pub struct Thread { - inner: Arc, + inner: Pin>, } impl Thread { // Used only internally to construct a thread object without spawning // Panics if the name contains nuls. pub(crate) fn new(name: Option) -> Thread { - Thread { inner: Arc::new(Inner { name, id: ThreadId::new(), parker: Parker::new() }) } + // We have to use `unsafe` here to constuct the `Parker` in-place, + // which is required for the UNIX implementation. + // + // SAFETY: We pin the Arc immediately after creation, so its address never + // changes. + let inner = unsafe { + let mut arc = Arc::::new_uninit(); + let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr(); + addr_of_mut!((*ptr).name).write(name); + addr_of_mut!((*ptr).id).write(ThreadId::new()); + Parker::new(addr_of_mut!((*ptr).parker)); + Pin::new_unchecked(arc.assume_init()) + }; + + Thread { inner } } /// Atomically makes the handle's token available if it is not already. @@ -1137,7 +1159,7 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn unpark(&self) { - self.inner.parker.unpark(); + self.inner.as_ref().parker().unpark(); } /// Gets the thread's unique identifier. From eb55cdce4bc1c03e1ce805af633dac611a948d43 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 25 Apr 2022 22:53:09 +0200 Subject: [PATCH 02/17] use `ParseSess` instead of `Session` in `into_diagnostic` --- .../rustc_macros/src/session_diagnostic.rs | 6 ++++-- compiler/rustc_session/src/parse.rs | 18 +++++++++++++++++- compiler/rustc_session/src/session.rs | 14 +++++++++----- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index ff7506979fc34..5661451f52071 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -119,7 +119,9 @@ fn span_err(span: impl proc_macro::MultiSpan, msg: &str) -> proc_macro::Diagnost /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`. macro_rules! throw_span_err { - ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }}; + ($span:expr, $msg:expr) => {{ + throw_span_err!($span, $msg, |diag| diag) + }}; ($span:expr, $msg:expr, $f:expr) => {{ return Err(_throw_span_err($span, $msg, $f)); }}; @@ -308,7 +310,7 @@ impl<'a> SessionDiagnosticDerive<'a> { { fn into_diagnostic( self, - #sess: &'__session_diagnostic_sess rustc_session::Session + #sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, #param_ty> { use rustc_errors::IntoDiagnosticArg; #implementation diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 6a36ae63c6834..dd7682ebacef5 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -3,13 +3,14 @@ use crate::config::CheckCfg; use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId}; +use crate::SessionDiagnostic; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, + DiagnosticMessage, ErrorGuaranteed, MultiSpan, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -287,4 +288,19 @@ impl ParseSess { pub fn proc_macro_quoted_spans(&self) -> Vec { self.proc_macro_quoted_spans.lock().clone() } + + pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { + err.into_diagnostic(self).emit() + } + + pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { + warning.into_diagnostic(self).emit() + } + + pub fn struct_err( + &self, + msg: impl Into, + ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + self.span_diagnostic.struct_err(msg) + } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index b4548129689b1..2bc0c5f1228e0 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -212,7 +212,7 @@ pub struct PerfStats { pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `sess`. #[must_use] - fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, T>; + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, T>; } impl Session { @@ -334,7 +334,7 @@ impl Session { &self, msg: impl Into, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - self.diagnostic().struct_err(msg) + self.parse_sess.struct_err(msg) } pub fn struct_err_with_code( &self, @@ -414,10 +414,10 @@ impl Session { self.diagnostic().err(msg) } pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { - err.into_diagnostic(self).emit() + self.parse_sess.emit_err(err) } pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { - warning.into_diagnostic(self).emit() + self.parse_sess.emit_warning(warning) } #[inline] pub fn err_count(&self) -> usize { @@ -783,7 +783,11 @@ impl Session { Path::new(&rustlib_path), Path::new("bin"), ]); - if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] } + if self_contained { + vec![p.clone(), p.join("self-contained")] + } else { + vec![p] + } } pub fn init_incr_comp_session( From 519dd8e9de1a85e18b3033a007a3bf01c6e79560 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 25 Apr 2022 22:55:15 +0200 Subject: [PATCH 03/17] migrate ambiguous plus diagnostic --- .../locales/en-US/parser.ftl | 3 ++ compiler/rustc_parse/Cargo.toml | 1 + .../rustc_parse/src/parser/diagnostics.rs | 32 +++++++++++++------ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 24e59a93cea6c..fd7daadb1ab42 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -1,3 +1,6 @@ parser-struct-literal-body-without-path = struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block +parser-maybe-report-ambiguous-plus = + ambiguous `+` in a type + .suggestion = use parentheses to disambiguate diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index a823607ab0ec2..c6ca260e9831e 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -13,6 +13,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_feature = { path = "../rustc_feature" } rustc_lexer = { path = "../rustc_lexer" } +rustc_macros = { path = "../rustc_macros" } rustc_errors = { path = "../rustc_errors" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ed2640451705b..d270f3606d760 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -21,6 +21,7 @@ use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, Er use rustc_errors::{ Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, }; +use rustc_macros::SessionDiagnostic; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; @@ -1170,16 +1171,29 @@ impl<'a> Parser<'a> { impl_dyn_multi: bool, ty: &Ty, ) { + #[derive(SessionDiagnostic)] + #[error(slug = "parser-maybe-report-ambiguous-plus")] + struct AmbiguousPlus { + pub sum_with_parens: String, + #[primary_span] + #[suggestion(code = "{sum_with_parens}")] + pub span: Span, + } + if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi { - let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); - self.struct_span_err(ty.span, "ambiguous `+` in a type") - .span_suggestion( - ty.span, - "use parentheses to disambiguate", - sum_with_parens, - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(AmbiguousPlus { + sum_with_parens: format!("({})", pprust::ty_to_string(&ty)), + span: ty.span, + }); + // let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); + // self.struct_span_err(ty.span, "ambiguous `+` in a type") + // .span_suggestion( + // ty.span, + // "use parentheses to disambiguate", + // sum_with_parens, + // Applicability::MachineApplicable, + // ) + // .emit(); } } From d6da5fb3532bd44f3baa6eff0011bd20c6323e6b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 25 Apr 2022 22:55:24 +0200 Subject: [PATCH 04/17] update lockfile --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 30175ae3561ab..567cef4c51eba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4181,6 +4181,7 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_lexer", + "rustc_macros", "rustc_session", "rustc_span", "tracing", From 5874b09806e40e4791ab8d50d956fedcca9df91d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 25 Apr 2022 23:17:32 +0200 Subject: [PATCH 05/17] fix formatting --- compiler/rustc_macros/src/session_diagnostic.rs | 4 +--- compiler/rustc_session/src/session.rs | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index 5661451f52071..9466d0f34bc07 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -119,9 +119,7 @@ fn span_err(span: impl proc_macro::MultiSpan, msg: &str) -> proc_macro::Diagnost /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`. macro_rules! throw_span_err { - ($span:expr, $msg:expr) => {{ - throw_span_err!($span, $msg, |diag| diag) - }}; + ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }}; ($span:expr, $msg:expr, $f:expr) => {{ return Err(_throw_span_err($span, $msg, $f)); }}; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 2bc0c5f1228e0..e8279f6fed24f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -783,11 +783,7 @@ impl Session { Path::new(&rustlib_path), Path::new("bin"), ]); - if self_contained { - vec![p.clone(), p.join("self-contained")] - } else { - vec![p] - } + if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] } } pub fn init_incr_comp_session( From 530f4dce291371e0b1d567b47a1888aa8c806410 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 25 Apr 2022 23:26:52 +0200 Subject: [PATCH 06/17] remove old code --- compiler/rustc_parse/src/parser/diagnostics.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index d270f3606d760..23c4d67ebd797 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1185,15 +1185,6 @@ impl<'a> Parser<'a> { sum_with_parens: format!("({})", pprust::ty_to_string(&ty)), span: ty.span, }); - // let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); - // self.struct_span_err(ty.span, "ambiguous `+` in a type") - // .span_suggestion( - // ty.span, - // "use parentheses to disambiguate", - // sum_with_parens, - // Applicability::MachineApplicable, - // ) - // .emit(); } } From 2e261a82f3ba99e6d11a35ead9da95007530187a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 25 Apr 2022 23:49:53 +0200 Subject: [PATCH 07/17] add `struct_warn` method --- compiler/rustc_session/src/parse.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index dd7682ebacef5..e933fe1cb2412 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -303,4 +303,8 @@ impl ParseSess { ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { self.span_diagnostic.struct_err(msg) } + + pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { + self.span_diagnostic.struct_warn(msg) + } } From 35b42cb9ecc61bb36a23e53ff4913865d3ab1e80 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 26 Apr 2022 11:11:23 +0200 Subject: [PATCH 08/17] avoid `format!` --- compiler/rustc_parse/src/parser/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 23c4d67ebd797..f0a053d88b5db 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1176,13 +1176,13 @@ impl<'a> Parser<'a> { struct AmbiguousPlus { pub sum_with_parens: String, #[primary_span] - #[suggestion(code = "{sum_with_parens}")] + #[suggestion(code = "({sum_with_parens})")] pub span: Span, } if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi { self.sess.emit_err(AmbiguousPlus { - sum_with_parens: format!("({})", pprust::ty_to_string(&ty)), + sum_with_parens: pprust::ty_to_string(&ty), span: ty.span, }); } From 6c3e793fb3303878790a6e872e8fa8bc1e4ef4e9 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 26 Apr 2022 11:12:48 +0200 Subject: [PATCH 09/17] move `AmbigousPlus` outside --- .../rustc_parse/src/parser/diagnostics.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f0a053d88b5db..e8dc0b3a68436 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -242,6 +242,16 @@ impl MultiSugg { err.multipart_suggestions(msg, suggestions.map(|s| s.patches), applicability); } } + +#[derive(SessionDiagnostic)] +#[error(slug = "parser-maybe-report-ambiguous-plus")] +struct AmbiguousPlus { + pub sum_with_parens: String, + #[primary_span] + #[suggestion(code = "({sum_with_parens})")] + pub span: Span, +} + // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. @@ -1171,15 +1181,6 @@ impl<'a> Parser<'a> { impl_dyn_multi: bool, ty: &Ty, ) { - #[derive(SessionDiagnostic)] - #[error(slug = "parser-maybe-report-ambiguous-plus")] - struct AmbiguousPlus { - pub sum_with_parens: String, - #[primary_span] - #[suggestion(code = "({sum_with_parens})")] - pub span: Span, - } - if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi { self.sess.emit_err(AmbiguousPlus { sum_with_parens: pprust::ty_to_string(&ty), From 1e35bab1047a9969e363d55159c466f965e7c726 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 26 Apr 2022 11:13:23 +0200 Subject: [PATCH 10/17] separate messages by a newline --- compiler/rustc_error_messages/locales/en-US/parser.ftl | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index fd7daadb1ab42..3143b81b6098f 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -1,6 +1,7 @@ parser-struct-literal-body-without-path = struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block + parser-maybe-report-ambiguous-plus = ambiguous `+` in a type .suggestion = use parentheses to disambiguate From 2a6a370065537dd2fffa179d1e5db721fee451f2 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Tue, 26 Apr 2022 19:58:19 -0400 Subject: [PATCH 11/17] Add more diagnostic items --- library/core/src/fmt/mod.rs | 2 ++ library/core/src/sync/atomic.rs | 15 +++++++++++++++ library/std/src/error.rs | 1 + 3 files changed, 18 insertions(+) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index fac959ac7347d..7f56fa810b245 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -19,6 +19,7 @@ mod nofloat; mod num; #[stable(feature = "fmt_flags_align", since = "1.28.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Alignment")] /// Possible alignments returned by `Formatter::align` #[derive(Debug)] pub enum Alignment { @@ -462,6 +463,7 @@ impl<'a> Arguments<'a> { /// /// [`format()`]: ../../std/fmt/fn.format.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Arguments")] #[derive(Copy, Clone)] pub struct Arguments<'a> { // Format string pieces to print. diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 6285d1c1cbb56..406c363dd2455 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -162,6 +162,7 @@ unsafe impl Sync for AtomicBool {} /// loads and stores of pointers. Its size depends on the target pointer's size. #[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "AtomicPtr")] #[cfg_attr(target_pointer_width = "16", repr(C, align(2)))] #[cfg_attr(target_pointer_width = "32", repr(C, align(4)))] #[cfg_attr(target_pointer_width = "64", repr(C, align(8)))] @@ -1458,6 +1459,7 @@ macro_rules! atomic_int { $stable_nand:meta, $const_stable:meta, $stable_init_const:meta, + $diagnostic_item:meta, $s_int_type:literal, $extra_feature:expr, $min_fn:ident, $max_fn:ident, @@ -1480,6 +1482,7 @@ macro_rules! atomic_int { /// /// [module-level documentation]: crate::sync::atomic #[$stable] + #[$diagnostic_item] #[repr(C, align($align))] pub struct $atomic_type { v: UnsafeCell<$int_type>, @@ -2306,6 +2309,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"), "i8", "", atomic_min, atomic_max, @@ -2325,6 +2329,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"), "u8", "", atomic_umin, atomic_umax, @@ -2344,6 +2349,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"), "i16", "", atomic_min, atomic_max, @@ -2363,6 +2369,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"), "u16", "", atomic_umin, atomic_umax, @@ -2382,6 +2389,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"), "i32", "", atomic_min, atomic_max, @@ -2401,6 +2409,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"), "u32", "", atomic_umin, atomic_umax, @@ -2420,6 +2429,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"), "i64", "", atomic_min, atomic_max, @@ -2439,6 +2449,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"), "u64", "", atomic_umin, atomic_umax, @@ -2458,6 +2469,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), "i128", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -2477,6 +2489,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), "u128", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -2500,6 +2513,7 @@ macro_rules! atomic_int_ptr_sized { stable(feature = "atomic_nand", since = "1.27.0"), rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"), stable(feature = "rust1", since = "1.0.0"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"), "isize", "", atomic_min, atomic_max, @@ -2520,6 +2534,7 @@ macro_rules! atomic_int_ptr_sized { stable(feature = "atomic_nand", since = "1.27.0"), rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"), stable(feature = "rust1", since = "1.0.0"), + cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"), "usize", "", atomic_umin, atomic_umax, diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 3f85c2095cbd4..fdeb280d24078 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -53,6 +53,7 @@ use crate::time; /// high-level module to provide its own errors while also revealing some of the /// implementation for debugging via `source` chains. #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Error")] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. /// From a1e0cfaac3fdd0aa443f0c1590a84bd2dcb6ce95 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Tue, 26 Apr 2022 20:23:11 -0400 Subject: [PATCH 12/17] Update ui test --- ...ce-issue-49593-box-never.nofallback.stderr | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr index 1b1ce67cb0c1f..fbaa874792a01 100644 --- a/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr @@ -4,16 +4,6 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = help: the following other types implement trait `std::error::Error`: - ! - &'a T - AccessError - AddrParseError - Arc - BorrowError - BorrowMutError - Box - and 43 others = note: required for the cast to the object type `dyn std::error::Error` error[E0277]: the trait bound `(): std::error::Error` is not satisfied @@ -22,16 +12,6 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = help: the following other types implement trait `std::error::Error`: - ! - &'a T - AccessError - AddrParseError - Arc - BorrowError - BorrowMutError - Box - and 43 others = note: required for the cast to the object type `(dyn std::error::Error + 'static)` error: aborting due to 2 previous errors From e7ae9eb3f272a96c2c73363539ca31986e5d5e88 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 27 Apr 2022 12:03:16 +0200 Subject: [PATCH 13/17] rename `sum_with_parens` --- compiler/rustc_parse/src/parser/diagnostics.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e8dc0b3a68436..4edc9b39efcc7 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -246,9 +246,9 @@ impl MultiSugg { #[derive(SessionDiagnostic)] #[error(slug = "parser-maybe-report-ambiguous-plus")] struct AmbiguousPlus { - pub sum_with_parens: String, + pub sum_ty: String, #[primary_span] - #[suggestion(code = "({sum_with_parens})")] + #[suggestion(code = "({sum_ty})")] pub span: Span, } @@ -1182,10 +1182,7 @@ impl<'a> Parser<'a> { ty: &Ty, ) { if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi { - self.sess.emit_err(AmbiguousPlus { - sum_with_parens: pprust::ty_to_string(&ty), - span: ty.span, - }); + self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(&ty), span: ty.span }); } } From 332f326334b256477d252c1927524cbdb1eb6048 Mon Sep 17 00:00:00 2001 From: Simon <48656638+user-simon@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:27:02 +0200 Subject: [PATCH 14/17] Fixed grammatical error in example comment --- library/core/src/iter/sources/repeat_with.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/sources/repeat_with.rs b/library/core/src/iter/sources/repeat_with.rs index 44bc6890c55b5..6f62662d88066 100644 --- a/library/core/src/iter/sources/repeat_with.rs +++ b/library/core/src/iter/sources/repeat_with.rs @@ -27,7 +27,7 @@ use crate::iter::{FusedIterator, TrustedLen}; /// use std::iter; /// /// // let's assume we have some value of a type that is not `Clone` -/// // or which don't want to have in memory just yet because it is expensive: +/// // or which we don't want to have in memory just yet because it is expensive: /// #[derive(PartialEq, Debug)] /// struct Expensive; /// From 2b71201518faa73cf6084e3c4a5455ef66dd2a93 Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 27 Apr 2022 19:28:27 +0200 Subject: [PATCH 15/17] std: simplify UNIX parker timeouts --- library/std/src/sys/unix/thread_parker.rs | 76 ++++++----------------- library/std/src/sys/unix/time.rs | 4 +- 2 files changed, 21 insertions(+), 59 deletions(-) diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker.rs index 90bdb46c4b075..f942302235f6d 100644 --- a/library/std/src/sys/unix/thread_parker.rs +++ b/library/std/src/sys/unix/thread_parker.rs @@ -41,52 +41,18 @@ unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t const TIMESPEC_MAX: libc::timespec = libc::timespec { tv_sec: ::MAX, tv_nsec: 1_000_000_000 - 1 }; -fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > ::MAX as u64 { ::MAX } else { value as libc::time_t } -} - -// This implementation is used on systems that support pthread_condattr_setclock -// where we configure the condition variable to use the monotonic clock (instead of -// the default system clock). This approach avoids all problems that result -// from changes made to the system time. -#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "espidf")))] unsafe fn wait_timeout( cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t, dur: Duration, ) { - use crate::mem; - - let mut now: libc::timespec = mem::zeroed(); - let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now); - assert_eq!(r, 0); - // Nanosecond calculations can't overflow because both values are below 1e9. - let nsec = dur.subsec_nanos() + now.tv_nsec as u32; - let sec = saturating_cast_to_time_t(dur.as_secs()) - .checked_add((nsec / 1_000_000_000) as libc::time_t) - .and_then(|s| s.checked_add(now.tv_sec)); - let nsec = nsec % 1_000_000_000; - let timeout = - sec.map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec as _ }).unwrap_or(TIMESPEC_MAX); - let r = libc::pthread_cond_timedwait(cond, lock, &timeout); - assert!(r == libc::ETIMEDOUT || r == 0); -} + // Use the system clock on systems that do not support pthread_condattr_setclock. + // This unfortunately results in problems when the system time changes. + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "espidf"))] + let (now, dur) = { + use super::time::SystemTime; + use crate::cmp::min; -// This implementation is modeled after libcxx's condition_variable -// https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 -// https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "espidf"))] -unsafe fn wait_timeout( - cond: *mut libc::pthread_cond_t, - lock: *mut libc::pthread_mutex_t, - mut dur: Duration, -) { - use crate::ptr; - - // 1000 years - let max_dur = Duration::from_secs(1000 * 365 * 86400); - - if dur > max_dur { // OSX implementation of `pthread_cond_timedwait` is buggy // with super long durations. When duration is greater than // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` @@ -98,23 +64,19 @@ unsafe fn wait_timeout( // To work around this issue, and possible bugs of other OSes, timeout // is clamped to 1000 years, which is allowable per the API of `park_timeout` // because of spurious wakeups. - dur = max_dur; - } - - let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 }; - let r = libc::gettimeofday(&mut sys_now, ptr::null_mut()); - debug_assert_eq!(r, 0); - let nsec = dur.subsec_nanos() as libc::c_long + (sys_now.tv_usec * 1000) as libc::c_long; - let extra = (nsec / 1_000_000_000) as libc::time_t; - let nsec = nsec % 1_000_000_000; - let seconds = saturating_cast_to_time_t(dur.as_secs()); - let timeout = sys_now - .tv_sec - .checked_add(extra) - .and_then(|s| s.checked_add(seconds)) - .map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec }) - .unwrap_or(TIMESPEC_MAX); - // And wait! + let dur = min(dur, Duration::from_secs(1000 * 365 * 86400)); + let now = SystemTime::now().t; + (now, dur) + }; + /// Use the monotonic clock on other systems. + #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "espidf")))] + let (now, dur) = { + use super::time::Timespec; + + (Timespec::now(libc::CLOCK_MONOTONIC).t, dur) + }; + + let timeout = now.checked_add_duration(&dur).map(|t| t.t).unwrap_or(TIMESPEC_MAX); let r = libc::pthread_cond_timedwait(cond, lock, &timeout); debug_assert!(r == libc::ETIMEDOUT || r == 0); } diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 498c94d0cdcba..d43ceec9c8a59 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -132,7 +132,7 @@ mod inner { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SystemTime { - t: Timespec, + pub(in crate::sys::unix) t: Timespec, } pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; @@ -279,7 +279,7 @@ mod inner { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SystemTime { - t: Timespec, + pub(in crate::sys::unix) t: Timespec, } pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; From 2c9421823815cd6ce91afef0b4c7580483863416 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Tue, 26 Apr 2022 00:17:25 +0200 Subject: [PATCH 16/17] Recover suggestions to introduce named lifetime under NLL --- .../src/diagnostics/region_errors.rs | 35 ++++- .../nice_region_error/different_lifetimes.rs | 148 +++++++++--------- .../nice_region_error/find_anon_type.rs | 2 +- .../error_reporting/nice_region_error/mod.rs | 2 + .../issue-90170-elision-mismatch.nll.stderr | 15 ++ .../ex3-both-anon-regions-2.nll.stderr | 5 + .../ex3-both-anon-regions-3.nll.stderr | 10 ++ ...non-regions-return-type-is-anon.nll.stderr | 5 + ...-both-anon-regions-self-is-anon.nll.stderr | 5 + ...oth-anon-regions-using-fn-items.nll.stderr | 5 + ...h-anon-regions-using-impl-items.nll.stderr | 5 + ...non-regions-using-trait-objects.nll.stderr | 5 + .../ex3-both-anon-regions.nll.stderr | 5 + ...elf_types_pin_lifetime_mismatch.nll.stderr | 10 ++ .../ui/self/elision/lt-ref-self.nll.stderr | 30 ++++ .../ui/self/elision/ref-mut-self.nll.stderr | 30 ++++ .../ui/self/elision/ref-mut-struct.nll.stderr | 25 +++ src/test/ui/self/elision/ref-self.nll.stderr | 35 +++++ .../ui/self/elision/ref-struct.nll.stderr | 25 +++ ...rscore-lifetime-elison-mismatch.nll.stderr | 5 + 20 files changed, 331 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b5ee4a5edce7d..30fe4ea8662eb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -2,7 +2,10 @@ use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_infer::infer::{ - error_reporting::nice_region_error::{self, find_param_with_region, NiceRegionError}, + error_reporting::nice_region_error::{ + self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, + NiceRegionError, + }, error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, RelateParamBound, }; @@ -630,6 +633,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); + self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); diag } @@ -694,4 +698,33 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); } } + + fn suggest_adding_lifetime_params( + &self, + diag: &mut Diagnostic, + sub: RegionVid, + sup: RegionVid, + ) { + let (Some(sub), Some(sup)) = (self.to_error_region(sub), self.to_error_region(sup)) else { + return + }; + + let Some((ty_sub, _)) = self + .infcx + .tcx + .is_suitable_region(sub) + .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.boundregion)) else { + return + }; + + let Some((ty_sup, _)) = self + .infcx + .tcx + .is_suitable_region(sup) + .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.boundregion)) else { + return + }; + + suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag); + } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 7721e00c141d7..be9db6aa25b75 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -6,6 +6,7 @@ use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::SubregionOrigin; +use crate::infer::TyCtxt; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; @@ -145,84 +146,83 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err); + if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) { + err.note("each elided lifetime in input position becomes a distinct lifetime"); + } let reported = err.emit(); Some(reported) } +} - fn suggest_adding_lifetime_params( - &self, - sub: Region<'tcx>, - ty_sup: &Ty<'_>, - ty_sub: &Ty<'_>, - err: &mut Diagnostic, - ) { - if let ( - hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, - hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }, - ) = (ty_sub, ty_sup) - { - if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() { - if let Some(anon_reg) = self.tcx().is_suitable_region(sub) { - let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id); - - let node = self.tcx().hir().get(hir_id); - let is_impl = matches!(&node, hir::Node::ImplItem(_)); - let generics = match node { - hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Fn(_, ref generics, ..), - .. - }) - | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) - | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics, - _ => return, - }; - - let (suggestion_param_name, introduce_new) = generics - .params - .iter() - .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) - .and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok()) - .map(|name| (name, false)) - .unwrap_or_else(|| ("'a".to_string(), true)); - - let mut suggestions = vec![ - if let hir::LifetimeName::Underscore = lifetime_sub.name { - (lifetime_sub.span, suggestion_param_name.clone()) - } else { - (lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ") - }, - if let hir::LifetimeName::Underscore = lifetime_sup.name { - (lifetime_sup.span, suggestion_param_name.clone()) - } else { - (lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ") - }, - ]; - - if introduce_new { - let new_param_suggestion = match &generics.params { - [] => (generics.span, format!("<{}>", suggestion_param_name)), - [first, ..] => { - (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)) - } - }; - - suggestions.push(new_param_suggestion); - } - - let mut sugg = String::from("consider introducing a named lifetime parameter"); - if is_impl { - sugg.push_str(" and update trait if needed"); - } - err.multipart_suggestion( - sugg.as_str(), - suggestions, - Applicability::MaybeIncorrect, - ); - err.note("each elided lifetime in input position becomes a distinct lifetime"); - } - } - } +pub fn suggest_adding_lifetime_params<'tcx>( + tcx: TyCtxt<'tcx>, + sub: Region<'tcx>, + ty_sup: &Ty<'_>, + ty_sub: &Ty<'_>, + err: &mut Diagnostic, +) -> bool { + let ( + hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, + hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }, + ) = (ty_sub, ty_sup) else { + return false; + }; + + if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() { + return false; + }; + + let Some(anon_reg) = tcx.is_suitable_region(sub) else { + return false; + }; + + let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id); + + let node = tcx.hir().get(hir_id); + let is_impl = matches!(&node, hir::Node::ImplItem(_)); + let generics = match node { + hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. }) + | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) + | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics, + _ => return false, + }; + + let (suggestion_param_name, introduce_new) = generics + .params + .iter() + .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .and_then(|p| tcx.sess.source_map().span_to_snippet(p.span).ok()) + .map(|name| (name, false)) + .unwrap_or_else(|| ("'a".to_string(), true)); + + let mut suggestions = vec![ + if let hir::LifetimeName::Underscore = lifetime_sub.name { + (lifetime_sub.span, suggestion_param_name.clone()) + } else { + (lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ") + }, + if let hir::LifetimeName::Underscore = lifetime_sup.name { + (lifetime_sup.span, suggestion_param_name.clone()) + } else { + (lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ") + }, + ]; + + if introduce_new { + let new_param_suggestion = match &generics.params { + [] => (generics.span, format!("<{}>", suggestion_param_name)), + [first, ..] => (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)), + }; + + suggestions.push(new_param_suggestion); } + + let mut sugg = String::from("consider introducing a named lifetime parameter"); + if is_impl { + sugg.push_str(" and update trait if needed"); + } + err.multipart_suggestion(sugg.as_str(), suggestions, Applicability::MaybeIncorrect); + + true } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index 135714af2a6c1..da4c2b41f09c3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Region, TyCtxt}; /// ``` /// The function returns the nested type corresponding to the anonymous region /// for e.g., `&u8` and `Vec<&u8>`. -pub(crate) fn find_anon_type<'tcx>( +pub fn find_anon_type<'tcx>( tcx: TyCtxt<'tcx>, region: Region<'tcx>, br: &ty::BoundRegionKind, 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 79f852d8a95e7..9948d15c43115 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 @@ -14,6 +14,8 @@ mod static_impl_trait; mod trait_impl_difference; mod util; +pub use different_lifetimes::suggest_adding_lifetime_params; +pub use find_anon_type::find_anon_type; pub use static_impl_trait::suggest_new_region_bound; pub use util::find_param_with_region; diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr b/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr index a5bc7450bbff0..48fb3fb4a2293 100644 --- a/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr +++ b/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr @@ -6,6 +6,11 @@ LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` + | +help: consider introducing a named lifetime parameter + | +LL | pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/issue-90170-elision-mismatch.rs:5:44 @@ -15,6 +20,11 @@ LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` + | +help: consider introducing a named lifetime parameter + | +LL | pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } + | ++++ ~~ ++ error: lifetime may not live long enough --> $DIR/issue-90170-elision-mismatch.rs:7:63 @@ -24,6 +34,11 @@ LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` + | +help: consider introducing a named lifetime parameter + | +LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } + | ++ ++ error: aborting due to 3 previous errors diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr index a94f9a799061a..5a23f1e0e9d99 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr @@ -7,6 +7,11 @@ LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { | let's call the lifetime of this reference `'2` LL | *v = x; | ^^^^^^ assignment requires that `'1` must outlive `'2` + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) { + | ++++ ++ ++ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr index 2ed4d6d4401aa..6ba130308a33a 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr @@ -7,6 +7,11 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { | let's call the lifetime of this reference `'2` LL | z.push((x,y)); | ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(z: &mut Vec<(&'a u8,&u8)>, (x, y): (&'a u8, &u8)) { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-3.rs:2:5 @@ -17,6 +22,11 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { | let's call the lifetime of this reference `'4` LL | z.push((x,y)); | ^^^^^^^^^^^^^ argument requires that `'3` must outlive `'4` + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(z: &mut Vec<(&u8,&'a u8)>, (x, y): (&u8, &'a u8)) { + | ++++ ++ ++ error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr index 1a19e81f235ba..5601335d275c3 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr @@ -7,6 +7,11 @@ LL | fn foo<'a>(&self, x: &i32) -> &i32 { | let's call the lifetime of this reference `'2` LL | x | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn foo<'a>(&'a self, x: &'a i32) -> &i32 { + | ++ ++ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr index 87b13dc15914b..e221902c4a907 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr @@ -7,6 +7,11 @@ LL | fn foo<'a>(&self, x: &Foo) -> &Foo { | let's call the lifetime of this reference `'2` LL | if true { x } else { self } | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn foo<'a>(&'a self, x: &'a Foo) -> &Foo { + | ++ ++ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr index 825c45b243441..a909c5fa82351 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr @@ -7,6 +7,11 @@ LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { | let's call the lifetime of this reference `'2` LL | y.push(z); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) { + | ++++ ++ ++ error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr index f3502674849ef..9661f1e5144b4 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr @@ -7,6 +7,11 @@ LL | fn foo(x: &mut Vec<&u8>, y: &u8) { | let's call the lifetime of this reference `'2` LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { + | ++++ ++ ++ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr index 78a828dde866f..cce0a31bfbbf1 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr @@ -7,6 +7,11 @@ LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { | let's call the lifetime of this reference `'2` LL | y.push(z); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x:Box , y: Vec<&u8>, z: &u8) { + | ++++ ++ ++ error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr index 6989acfa1963b..ec9fac0c288e0 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr @@ -7,6 +7,11 @@ LL | fn foo(x: &mut Vec<&u8>, y: &u8) { | let's call the lifetime of this reference `'2` LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { + | ++++ ++ ++ error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr index b06ebf7047737..057146e7cb0ad 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr @@ -6,6 +6,11 @@ LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f } + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:69 @@ -15,6 +20,11 @@ LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:58 diff --git a/src/test/ui/self/elision/lt-ref-self.nll.stderr b/src/test/ui/self/elision/lt-ref-self.nll.stderr index 1934207527b9c..2e26c703b6573 100644 --- a/src/test/ui/self/elision/lt-ref-self.nll.stderr +++ b/src/test/ui/self/elision/lt-ref-self.nll.stderr @@ -7,6 +7,11 @@ LL | fn ref_self(&self, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:23:9 @@ -17,6 +22,11 @@ LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:29:9 @@ -27,6 +37,11 @@ LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:35:9 @@ -37,6 +52,11 @@ LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:41:9 @@ -47,6 +67,11 @@ LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_box_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:47:9 @@ -57,6 +82,11 @@ LL | fn box_pin_Self(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_pin_Self<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: aborting due to 6 previous errors diff --git a/src/test/ui/self/elision/ref-mut-self.nll.stderr b/src/test/ui/self/elision/ref-mut-self.nll.stderr index f1f4d341b2bd8..fd4ecae3cfe32 100644 --- a/src/test/ui/self/elision/ref-mut-self.nll.stderr +++ b/src/test/ui/self/elision/ref-mut-self.nll.stderr @@ -7,6 +7,11 @@ LL | fn ref_self(&mut self, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:23:9 @@ -17,6 +22,11 @@ LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:29:9 @@ -27,6 +37,11 @@ LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:35:9 @@ -37,6 +52,11 @@ LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:41:9 @@ -47,6 +67,11 @@ LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_box_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:47:9 @@ -57,6 +82,11 @@ LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_pin_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: aborting due to 6 previous errors diff --git a/src/test/ui/self/elision/ref-mut-struct.nll.stderr b/src/test/ui/self/elision/ref-mut-struct.nll.stderr index de7eb02d7a7fe..ede790c061143 100644 --- a/src/test/ui/self/elision/ref-mut-struct.nll.stderr +++ b/src/test/ui/self/elision/ref-mut-struct.nll.stderr @@ -7,6 +7,11 @@ LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct.rs:21:9 @@ -17,6 +22,11 @@ LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct.rs:27:9 @@ -27,6 +37,11 @@ LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct.rs:33:9 @@ -37,6 +52,11 @@ LL | fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_box_ref_Struct<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct.rs:39:9 @@ -47,6 +67,11 @@ LL | fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_pin_ref_Struct<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: aborting due to 5 previous errors diff --git a/src/test/ui/self/elision/ref-self.nll.stderr b/src/test/ui/self/elision/ref-self.nll.stderr index f2b7b0ad01957..c0efc35fa6c8e 100644 --- a/src/test/ui/self/elision/ref-self.nll.stderr +++ b/src/test/ui/self/elision/ref-self.nll.stderr @@ -7,6 +7,11 @@ LL | fn ref_self(&self, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self.rs:33:9 @@ -17,6 +22,11 @@ LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self.rs:39:9 @@ -27,6 +37,11 @@ LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self.rs:45:9 @@ -37,6 +52,11 @@ LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self.rs:51:9 @@ -47,6 +67,11 @@ LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_box_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self.rs:57:9 @@ -57,6 +82,11 @@ LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_pin_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self.rs:63:9 @@ -67,6 +97,11 @@ LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 { + | ++++ ++ ++ error: aborting due to 7 previous errors diff --git a/src/test/ui/self/elision/ref-struct.nll.stderr b/src/test/ui/self/elision/ref-struct.nll.stderr index 70453b0ddfc71..226923f59ff37 100644 --- a/src/test/ui/self/elision/ref-struct.nll.stderr +++ b/src/test/ui/self/elision/ref-struct.nll.stderr @@ -7,6 +7,11 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct.rs:21:9 @@ -17,6 +22,11 @@ LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct.rs:27:9 @@ -27,6 +37,11 @@ LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct.rs:33:9 @@ -37,6 +52,11 @@ LL | fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_box_ref_Struct<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct.rs:39:9 @@ -47,6 +67,11 @@ LL | fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { | let's call the lifetime of this reference `'2` LL | f | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_pin_Struct<'a>(self: Box>, f: &'a u32) -> &u32 { + | ++++ ++ ++ error: aborting due to 5 previous errors diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr index 8e10242cb1331..a4dece320ec26 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr @@ -6,6 +6,11 @@ LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } + | ++++ ~~ ~~ error: aborting due to previous error From d9240d72ea2f050c45b1772e6de005a1ee4aed47 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Fri, 25 Mar 2022 18:26:55 +0100 Subject: [PATCH 17/17] Ensure that `'_` and GAT yields errors --- .../generic-associated-types/issue-95305.rs | 17 +++++++++++++ .../issue-95305.stderr | 25 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/test/ui/generic-associated-types/issue-95305.rs create mode 100644 src/test/ui/generic-associated-types/issue-95305.stderr diff --git a/src/test/ui/generic-associated-types/issue-95305.rs b/src/test/ui/generic-associated-types/issue-95305.rs new file mode 100644 index 0000000000000..9ead347984b0c --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-95305.rs @@ -0,0 +1,17 @@ +// It's not yet clear how '_ and GATs should interact. +// Forbid it for now but proper support might be added +// at some point in the future. + +#![feature(generic_associated_types)] + +trait Foo { + type Item<'a>; +} + +fn foo(x: &impl Foo = u32>) { } + //~^ ERROR missing lifetime specifier + +fn bar(x: &impl for<'a> Foo = &'_ u32>) { } + //~^ ERROR missing lifetime specifier + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-95305.stderr b/src/test/ui/generic-associated-types/issue-95305.stderr new file mode 100644 index 0000000000000..2b48378dc4350 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-95305.stderr @@ -0,0 +1,25 @@ +error[E0106]: missing lifetime specifier + --> $DIR/issue-95305.rs:11:26 + | +LL | fn foo(x: &impl Foo = u32>) { } + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | fn foo<'a>(x: &impl Foo = u32>) { } + | ++++ ~~ + +error[E0106]: missing lifetime specifier + --> $DIR/issue-95305.rs:14:41 + | +LL | fn bar(x: &impl for<'a> Foo = &'_ u32>) { } + | ^^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | fn bar(x: &impl for<'a> Foo = &'a u32>) { } + | ~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`.