From 7cd081ed8e02f063aebeda5949f6d6e4a5eef371 Mon Sep 17 00:00:00 2001 From: Yilin Chen <1479826151@qq.com> Date: Tue, 13 Oct 2026 12:59:45 +0800 Subject: [PATCH 01/31] make the safety documentation consistent in Ptr module --- library/core/src/ptr/const_ptr.rs | 45 +++++++++++++++++----- library/core/src/ptr/mut_ptr.rs | 63 ++++++++++++++++++++++++++----- library/core/src/ptr/non_null.rs | 63 ++++++++++++++++++++++++++----- 3 files changed, 144 insertions(+), 27 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 455eed6f3f6a9..87ba0067b9ba4 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -393,11 +393,14 @@ impl *const T { /// `count` is in units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [offset][pointer::offset] on it. See that method for documentation - /// and safety requirements. + /// using [offset][pointer::offset] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [offset][pointer::offset] for documentation and safety requirements. #[must_use] #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] @@ -626,11 +629,14 @@ impl *const T { /// units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [`offset_from`][pointer::offset_from] on it. See that method for - /// documentation and safety requirements. + /// using [`offset_from`][pointer::offset_from] on it. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. + /// + /// # Safety + /// + /// See [`offset_from`][pointer::offset_from] for documentation and safety requirements. #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] @@ -738,10 +744,13 @@ impl *const T { /// /// This is purely a convenience for casting to a `u8` pointer and /// using [`offset_from_unsigned`][pointer::offset_from_unsigned] on it. - /// See that method for documentation and safety requirements. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. + /// + /// # Safety + /// + /// See [`offset_from_unsigned`][pointer::offset_from_unsigned] for documentation and safety requirements. #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] @@ -875,11 +884,14 @@ impl *const T { /// `count` is in units of bytes. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [add][pointer::add] on it. See that method for documentation - /// and safety requirements. + /// using [add][pointer::add] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [add][pointer::add] for documentation and safety requirements. #[must_use] #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] @@ -960,11 +972,14 @@ impl *const T { /// `count` is in units of bytes. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [sub][pointer::sub] on it. See that method for documentation - /// and safety requirements. + /// using [sub][pointer::sub] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [sub][pointer::sub] for documentation and safety requirements. #[must_use] #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] @@ -1137,6 +1152,8 @@ impl *const T { /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// + /// # Safety + /// /// See [`ptr::read`] for safety concerns and examples. /// /// [`ptr::read`]: crate::ptr::read() @@ -1159,6 +1176,8 @@ impl *const T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// + /// # Safety + /// /// See [`ptr::read_volatile`] for safety concerns and examples. /// /// [`ptr::read_volatile`]: crate::ptr::read_volatile() @@ -1179,6 +1198,8 @@ impl *const T { /// /// Unlike `read`, the pointer may be unaligned. /// + /// # Safety + /// /// See [`ptr::read_unaligned`] for safety concerns and examples. /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() @@ -1199,6 +1220,8 @@ impl *const T { /// /// NOTE: this has the *same* argument order as [`ptr::copy`]. /// + /// # Safety + /// /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() @@ -1219,6 +1242,8 @@ impl *const T { /// /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. /// + /// # Safety + /// /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() @@ -1497,6 +1522,8 @@ impl *const [T] { /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// + /// # Safety + /// /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable /// is *[undefined behavior]* even if the resulting pointer is not used. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index ca37c79bc1b04..e778f307f99b7 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -397,11 +397,14 @@ impl *mut T { /// `count` is in units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [offset][pointer::offset] on it. See that method for documentation - /// and safety requirements. + /// using [offset][pointer::offset] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [offset][pointer::offset] for documentation and safety requirements. #[must_use] #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] @@ -806,11 +809,14 @@ impl *mut T { /// units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [`offset_from`][pointer::offset_from] on it. See that method for - /// documentation and safety requirements. + /// using [`offset_from`][pointer::offset_from] on it. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. + /// + /// # Safety + /// + /// See [`offset_from`][pointer::offset_from] for documentation and safety requirements. #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] @@ -897,10 +903,13 @@ impl *mut T { /// /// This is purely a convenience for casting to a `u8` pointer and /// using [`offset_from_unsigned`][pointer::offset_from_unsigned] on it. - /// See that method for documentation and safety requirements. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. + /// + /// # Safety + /// + /// See [`offset_from_unsigned`][pointer::offset_from_unsigned] for documentation and safety requirements. #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] @@ -974,11 +983,14 @@ impl *mut T { /// `count` is in units of bytes. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [add][pointer::add] on it. See that method for documentation - /// and safety requirements. + /// using [add][pointer::add] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [`add`][pointer::add] for documentation and safety requirements. #[must_use] #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] @@ -1059,11 +1071,14 @@ impl *mut T { /// `count` is in units of bytes. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [sub][pointer::sub] on it. See that method for documentation - /// and safety requirements. + /// using [sub][pointer::sub] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [`sub`][pointer::sub] for documentation and safety requirements. #[must_use] #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] @@ -1230,6 +1245,8 @@ impl *mut T { /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// + /// # Safety + /// /// See [`ptr::read`] for safety concerns and examples. /// /// [`ptr::read`]: crate::ptr::read() @@ -1252,6 +1269,8 @@ impl *mut T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// + /// # Safety + /// /// See [`ptr::read_volatile`] for safety concerns and examples. /// /// [`ptr::read_volatile`]: crate::ptr::read_volatile() @@ -1272,6 +1291,8 @@ impl *mut T { /// /// Unlike `read`, the pointer may be unaligned. /// + /// # Safety + /// /// See [`ptr::read_unaligned`] for safety concerns and examples. /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() @@ -1292,6 +1313,8 @@ impl *mut T { /// /// NOTE: this has the *same* argument order as [`ptr::copy`]. /// + /// # Safety + /// /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() @@ -1312,6 +1335,8 @@ impl *mut T { /// /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. /// + /// # Safety + /// /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() @@ -1332,6 +1357,8 @@ impl *mut T { /// /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. /// + /// # Safety + /// /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() @@ -1352,6 +1379,8 @@ impl *mut T { /// /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. /// + /// # Safety + /// /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() @@ -1369,6 +1398,8 @@ impl *mut T { /// Executes the destructor (if any) of the pointed-to value. /// + /// # Safety + /// /// See [`ptr::drop_in_place`] for safety concerns and examples. /// /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place() @@ -1387,6 +1418,8 @@ impl *mut T { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// + /// # Safety + /// /// See [`ptr::write`] for safety concerns and examples. /// /// [`ptr::write`]: crate::ptr::write() @@ -1405,6 +1438,8 @@ impl *mut T { /// Invokes memset on the specified pointer, setting `count * size_of::()` /// bytes of memory starting at `self` to `val`. /// + /// # Safety + /// /// See [`ptr::write_bytes`] for safety concerns and examples. /// /// [`ptr::write_bytes`]: crate::ptr::write_bytes() @@ -1428,6 +1463,8 @@ impl *mut T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// + /// # Safety + /// /// See [`ptr::write_volatile`] for safety concerns and examples. /// /// [`ptr::write_volatile`]: crate::ptr::write_volatile() @@ -1448,6 +1485,8 @@ impl *mut T { /// /// Unlike `write`, the pointer may be unaligned. /// + /// # Safety + /// /// See [`ptr::write_unaligned`] for safety concerns and examples. /// /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() @@ -1466,6 +1505,8 @@ impl *mut T { /// Replaces the value at `self` with `src`, returning the old /// value, without dropping either. /// + /// # Safety + /// /// See [`ptr::replace`] for safety concerns and examples. /// /// [`ptr::replace`]: crate::ptr::replace() @@ -1484,6 +1525,8 @@ impl *mut T { /// deinitializing either. They may overlap, unlike `mem::swap` which is /// otherwise equivalent. /// + /// # Safety + /// /// See [`ptr::swap`] for safety concerns and examples. /// /// [`ptr::swap`]: crate::ptr::swap() @@ -1876,6 +1919,8 @@ impl *mut [T] { /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// + /// # Safety + /// /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable /// is *[undefined behavior]* even if the resulting pointer is not used. /// diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 3cec204fd54cc..8762a077584b5 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -575,11 +575,14 @@ impl NonNull { /// `count` is in units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [offset][pointer::offset] on it. See that method for documentation - /// and safety requirements. + /// using [offset][pointer::offset] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [offset][pointer::offset] for documentation and safety requirements. #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -630,11 +633,14 @@ impl NonNull { /// `count` is in units of bytes. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [`add`][NonNull::add] on it. See that method for documentation - /// and safety requirements. + /// using [`add`][NonNull::add] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [`add`][NonNull::add] for documentation and safety requirements. #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -690,11 +696,14 @@ impl NonNull { /// `count` is in units of bytes. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [`sub`][NonNull::sub] on it. See that method for documentation - /// and safety requirements. + /// using [`sub`][NonNull::sub] on it. /// /// For non-`Sized` pointees this operation changes only the data pointer, /// leaving the metadata untouched. + /// + /// # Safety + /// + /// See [`sub`][NonNull::sub] for documentation and safety requirements. #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -809,11 +818,14 @@ impl NonNull { /// units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [`offset_from`][NonNull::offset_from] on it. See that method for - /// documentation and safety requirements. + /// using [`offset_from`][NonNull::offset_from] on it. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. + /// + /// # Safety + /// + /// See [`offset_from`][NonNull::offset_from] for documentation and safety requirements. #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] @@ -902,10 +914,13 @@ impl NonNull { /// /// This is purely a convenience for casting to a `u8` pointer and /// using [`offset_from_unsigned`][NonNull::offset_from_unsigned] on it. - /// See that method for documentation and safety requirements. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. + /// + /// # Safety + /// + /// See [`offset_from_unsigned`][NonNull::offset_from_unsigned] for documentation and safety requirements. #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] @@ -918,6 +933,8 @@ impl NonNull { /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// + /// # Safety + /// /// See [`ptr::read`] for safety concerns and examples. /// /// [`ptr::read`]: crate::ptr::read() @@ -940,6 +957,8 @@ impl NonNull { /// to not be elided or reordered by the compiler across other volatile /// operations. /// + /// # Safety + /// /// See [`ptr::read_volatile`] for safety concerns and examples. /// /// [`ptr::read_volatile`]: crate::ptr::read_volatile() @@ -960,6 +979,8 @@ impl NonNull { /// /// Unlike `read`, the pointer may be unaligned. /// + /// # Safety + /// /// See [`ptr::read_unaligned`] for safety concerns and examples. /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() @@ -980,6 +1001,8 @@ impl NonNull { /// /// NOTE: this has the *same* argument order as [`ptr::copy`]. /// + /// # Safety + /// /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() @@ -1000,6 +1023,8 @@ impl NonNull { /// /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. /// + /// # Safety + /// /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() @@ -1020,6 +1045,8 @@ impl NonNull { /// /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. /// + /// # Safety + /// /// See [`ptr::copy`] for safety concerns and examples. /// /// [`ptr::copy`]: crate::ptr::copy() @@ -1040,6 +1067,8 @@ impl NonNull { /// /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. /// + /// # Safety + /// /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() @@ -1057,6 +1086,8 @@ impl NonNull { /// Executes the destructor (if any) of the pointed-to value. /// + /// # Safety + /// /// See [`ptr::drop_in_place`] for safety concerns and examples. /// /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place() @@ -1074,6 +1105,8 @@ impl NonNull { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// + /// # Safety + /// /// See [`ptr::write`] for safety concerns and examples. /// /// [`ptr::write`]: crate::ptr::write() @@ -1092,6 +1125,8 @@ impl NonNull { /// Invokes memset on the specified pointer, setting `count * size_of::()` /// bytes of memory starting at `self` to `val`. /// + /// # Safety + /// /// See [`ptr::write_bytes`] for safety concerns and examples. /// /// [`ptr::write_bytes`]: crate::ptr::write_bytes() @@ -1115,6 +1150,8 @@ impl NonNull { /// to not be elided or reordered by the compiler across other volatile /// operations. /// + /// # Safety + /// /// See [`ptr::write_volatile`] for safety concerns and examples. /// /// [`ptr::write_volatile`]: crate::ptr::write_volatile() @@ -1135,6 +1172,8 @@ impl NonNull { /// /// Unlike `write`, the pointer may be unaligned. /// + /// # Safety + /// /// See [`ptr::write_unaligned`] for safety concerns and examples. /// /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() @@ -1153,6 +1192,8 @@ impl NonNull { /// Replaces the value at `self` with `src`, returning the old /// value, without dropping either. /// + /// # Safety + /// /// See [`ptr::replace`] for safety concerns and examples. /// /// [`ptr::replace`]: crate::ptr::replace() @@ -1171,6 +1212,8 @@ impl NonNull { /// deinitializing either. They may overlap, unlike `mem::swap` which is /// otherwise equivalent. /// + /// # Safety + /// /// See [`ptr::swap`] for safety concerns and examples. /// /// [`ptr::swap`]: crate::ptr::swap() @@ -1585,6 +1628,8 @@ impl NonNull<[T]> { /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// + /// # Safety + /// /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable /// is *[undefined behavior]* even if the resulting pointer is not used. /// From 5fbbf4763a780f7512c4949360311e634b6a3a86 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 15 Oct 2026 07:11:17 -0400 Subject: [PATCH 02/31] std: Use getexecpath() for current_exe() on OpenBSD OpenBSD added getexecpath(3) to libc, which returns an already-canonicalized executable path directly. Replace the sysctl(KERN_PROC_ARGV)-based implementation. This was the last user of div_exact in std, so drop the exact_div feature gate. --- library/std/src/lib.rs | 1 - library/std/src/sys/paths/unix.rs | 35 ++++++------------------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0d0d9e0759d82..aa51e9e6b06be 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -287,7 +287,6 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] -#![feature(exact_div)] #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] diff --git a/library/std/src/sys/paths/unix.rs b/library/std/src/sys/paths/unix.rs index cee799c36c79b..756c5ec26f127 100644 --- a/library/std/src/sys/paths/unix.rs +++ b/library/std/src/sys/paths/unix.rs @@ -253,37 +253,14 @@ pub fn current_exe() -> io::Result { #[cfg(target_os = "openbsd")] pub fn current_exe() -> io::Result { + let mut path = vec![0u8; libc::PATH_MAX as usize]; unsafe { - let mut mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, libc::getpid(), libc::KERN_PROC_ARGV]; - let mib = mib.as_mut_ptr(); - - // Determine the required size (in bytes) for the argument array ... - let mut argv_size = 0; - cvt(libc::sysctl(mib, 4, ptr::null_mut(), &mut argv_size, ptr::null_mut(), 0))?; - - // ... allocate a buffer for it ... - let argc = argv_size.div_exact(size_of::<*const libc::c_char>()).unwrap(); - let mut argv = Vec::<*const libc::c_char>::with_capacity(argc); - - // ... and retrieve the argument array. - cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_size, ptr::null_mut(), 0))?; - let argc = argv_size.div_exact(size_of::<*const libc::c_char>()).unwrap(); - argv.set_len(argc); - - if argv[0].is_null() { - return Err(io::const_error!(io::ErrorKind::Uncategorized, "no current exe available")); - } - let argv0 = CStr::from_ptr(argv[0]).to_bytes(); - if argv0.iter().any(|b| *b == b'/') { - // The program name is path-like, so try to canonicalize it. - crate::fs::canonicalize(OsStr::from_bytes(argv0)) - } else { - // The program was probably found in the PATH. Instead of trying to - // find it again (which might not succeed if PATH has changed), just - // return the program name – this function is best-effort anyway. - Ok(PathBuf::from(OsStr::from_bytes(argv0))) - } + cvt(libc::getexecpath(path.as_mut_ptr().cast(), path.len()))?; + // SAFETY: getexecpath(3) NUL-terminates the buffer on success. + let len = CStr::from_ptr(path.as_ptr().cast()).count_bytes(); + path.truncate(len); } + Ok(PathBuf::from(OsString::from_vec(path))) } #[cfg(any( From 09026e0fcc8e3c31697db6ce158d8ff8b7df52d0 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 29 Oct 2026 09:49:00 +0900 Subject: [PATCH 03/31] avoid building a region map when erasing bound regions --- compiler/rustc_middle/src/ty/fold.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 3d560a9f18815..398633cb3311c 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -141,7 +141,7 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable>, { - self.instantiate_bound_regions(value, |_| self.lifetimes.re_erased).0 + self.instantiate_bound_regions_uncached(value, |_| self.lifetimes.re_erased) } /// Anonymize all bound variables in `value`, this is mostly used to improve caching. From f7755c870ae0d9eaf5605ccbeaf143fd7fbe536c Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Thu, 29 Oct 2026 11:40:58 +0300 Subject: [PATCH 04/31] Parallelize AST -> HIR lowering --- compiler/rustc_interface/src/passes.rs | 36 +++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 73bebb22bc508..fd2f7ae48d214 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -14,7 +14,8 @@ use rustc_crate_store::Untracked; use rustc_data_structures::indexmap::IndexMap; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{ - AppendOnlyIndexVec, DynSend, DynSync, FreezeLock, WorkerLocal, par_fns, + AppendOnlyIndexVec, DynSend, DynSync, FreezeLock, WorkerLocal, is_dyn_thread_safe, par_fns, + par_range, }; use rustc_data_structures::thousands; use rustc_errors::timings::TimingSection; @@ -22,7 +23,8 @@ use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; -use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; +use rustc_hir::OwnerId; +use rustc_hir::def_id::{DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store}; @@ -1103,9 +1105,35 @@ pub fn emit_delayed_lints(tcx: TyCtxt<'_>) { /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. /// This function never fails. fn run_required_analyses(tcx: TyCtxt<'_>) { + let is_parallel = is_dyn_thread_safe(); + + // There is no point in prefetching hir owners when parallel compiler is + // disabled, `print_hir_stats`, `check_crate` or `hir_crate_items` below will do it. + if is_parallel { + // Prefetch this as it is invoked in each `lower_to_hir`. + tcx.ensure_done().resolve_type_relative_delegations(()); + + let index = tcx.index_ast(()); + + // Invoke right before the parallel loop starts. + tcx.untracked().definitions.write().commit_end_of_determinism(); + par_range(0..index.len(), |idx| { + let id = LocalDefId { local_def_index: DefIndex::from_usize(idx) }; + + // FIXME: one can try to eliminate this filter in future, + // but it didn't lead to significant improvements at the moment + // of writing. + if index[id].is_some() { + tcx.ensure_done().hir_owner(id); + tcx.ensure_done().hir_attr_map(OwnerId { def_id: id }); + } + }); + } + if tcx.sess.opts.unstable_opts.input_stats { rustc_passes::input_stats::print_hir_stats(tcx); } + // When using rustdoc's "jump to def" feature, it enters this code and `check_crate` // is not defined. So we need to cfg it out. #[cfg(all(not(doc), debug_assertions))] @@ -1116,7 +1144,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // to use `hir_crate_items`. tcx.ensure_done().hir_crate_items(()); - tcx.untracked().definitions.write().commit_end_of_determinism(); + if !is_parallel { + tcx.untracked().definitions.write().commit_end_of_determinism(); + } rustc_passes::delegation::check_glob_and_list_delegations_target_expr(tcx); From 5aabd6ef0b16b387de64cbbfda61d22410ceea62 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Sun, 1 Nov 2026 12:15:22 -0800 Subject: [PATCH 05/31] unstable-book: update default-visibility.md to link to tracking issue Instead of just showing the bare URL --- src/doc/unstable-book/src/compiler-flags/default-visibility.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/compiler-flags/default-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-visibility.md index c401fd1d2d4dd..6a7c82767015e 100644 --- a/src/doc/unstable-book/src/compiler-flags/default-visibility.md +++ b/src/doc/unstable-book/src/compiler-flags/default-visibility.md @@ -1,6 +1,6 @@ # `default-visibility` -The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131090 +The tracking issue for this feature is: [#131090](https://github.com/rust-lang/rust/issues/131090). ------------------------ From 380fd0dd7e58315b01b93ace5aa6f6288560c441 Mon Sep 17 00:00:00 2001 From: Evgenii Zheltonozhskii Date: Mon, 2 Nov 2026 12:31:29 +0200 Subject: [PATCH 06/31] Reuse CanonicalVarKinds if no new variables were added --- .../src/canonical/canonicalizer.rs | 77 ++++++++++++------- compiler/rustc_type_ir/src/canonical.rs | 2 +- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 569fbd41e1b22..6b159074493f9 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -26,13 +26,15 @@ const NEEDS_CANONICAL: TypeFlags = TypeFlags::from_bits( .unwrap(); #[derive(Debug, Clone, Copy)] -enum CanonicalizeInputKind { +enum CanonicalizeInputKind { /// When canonicalizing the `param_env`, we keep `'static` as merging /// trait candidates relies on it when deciding whether a where-bound /// is trivial. ParamEnv, /// When canonicalizing predicates, we don't keep `'static`. - Predicate, + /// `param_env_var_kinds` caches the interned variable kinds to be + /// reused if there are no new vars. + Predicate { param_env_var_kinds: Option }, } /// Whether we're canonicalizing a query input or the query response. @@ -41,8 +43,8 @@ enum CanonicalizeInputKind { /// while canonicalizing the response happens in the context of the /// query. #[derive(Debug, Clone, Copy)] -enum CanonicalizeMode { - Input(CanonicalizeInputKind), +enum CanonicalizeMode { + Input(CanonicalizeInputKind), /// FIXME: We currently return region constraints referring to /// placeholders and inference variables from a binder instantiated /// inside of the query. @@ -68,14 +70,14 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate, I: Interner delegate: &'a D, // Immutable field. - canonicalize_mode: CanonicalizeMode, + canonicalize_mode: CanonicalizeMode, // Mutable fields. state: Box>, } impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { - fn new(delegate: &'a D, canonicalize_mode: CanonicalizeMode) -> Self { + fn new(delegate: &'a D, canonicalize_mode: CanonicalizeMode) -> Self { Canonicalizer { delegate, canonicalize_mode, state: delegate.obtain_canonicalizer_state() } } @@ -105,15 +107,18 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { if !param_env.has_type_flags(NEEDS_CANONICAL) { let rest_canonicalizer = Canonicalizer::new( delegate, - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate), + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + param_env_var_kinds: None, + }), ); return (param_env, rest_canonicalizer); } // Do the `env` canonicalization, and then convert the canonicalizer to `rest` form for - // subsequent use. - let do_env_and_make_rest = || { + // subsequent use, also returning the optionally interned (i.e., uniquely identified) + // canonicalized variable kind list in case cache is used, so it can also be cached. + let do_env_and_make_rest = |intern_var_kinds: bool| { let mut env_canonicalizer = Canonicalizer::new( delegate, CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), @@ -133,12 +138,17 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // // We clear the cache rather than deleting it or replacing it with an empty cache. This // lets the allocated capacity be reused later. - let mut rest_canonicalizer = env_canonicalizer; - rest_canonicalizer.canonicalize_mode = - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate); + let param_env_var_kinds = intern_var_kinds + .then(|| delegate.cx().mk_canonical_var_kinds(&env_canonicalizer.state.var_kinds)); + let mut rest_canonicalizer = Canonicalizer { + canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + param_env_var_kinds, + }), + ..env_canonicalizer + }; rest_canonicalizer.state.cache.clear(); - (param_env, rest_canonicalizer) + (param_env, rest_canonicalizer, param_env_var_kinds) }; // Check whether we can use the global cache for this param_env. As we only use @@ -153,11 +163,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Entry::Vacant(e) => { // Cache miss. Do `env` canonicalization and get `rest_canonicalizer`, and // fill in the cache entry. - let (param_env, rest_canonicalizer) = do_env_and_make_rest(); + let (param_env, rest_canonicalizer, var_kinds) = do_env_and_make_rest(true); e.insert(CanonicalParamEnvCacheEntry { param_env, variables: rest_canonicalizer.state.variables.clone(), - var_kinds: rest_canonicalizer.state.var_kinds.clone(), + var_kinds: var_kinds.unwrap(), // SAFETY: The iterated elements go straight back into a hashmap. #[allow(rustc::potential_query_instability)] variable_lookup_table: rest_canonicalizer @@ -174,10 +184,12 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let e = e.get(); let mut rest_canonicalizer = Canonicalizer::new( delegate, - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate), + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + param_env_var_kinds: Some(e.var_kinds), + }), ); rest_canonicalizer.state.variables.clone_from(&e.variables); - rest_canonicalizer.state.var_kinds.clone_from(&e.var_kinds); + e.var_kinds.as_slice().clone_into(&mut rest_canonicalizer.state.var_kinds); rest_canonicalizer .state .variable_lookup_table @@ -187,7 +199,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }) } else { // Do `env` canonicalization and get `rest_canonicalizer`. - do_env_and_make_rest() + let (param_env, rest_canonicalizer, _) = do_env_and_make_rest(false); + (param_env, rest_canonicalizer) } } @@ -278,7 +291,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // during canonicalization in the new solver. let max_universe = match self.canonicalize_mode { // All placeholders and vars are canonicalized in the root universe. - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { debug_assert!( self.state .var_kinds @@ -309,7 +322,15 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { .unwrap_or(ty::UniverseIndex::ROOT) } }; - let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&self.state.var_kinds); + let var_kinds = match self.canonicalize_mode { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + param_env_var_kinds: Some(cached), + }) if cached.len() == self.state.variables.len() => { + debug_assert_eq!(cached.as_slice(), self.state.var_kinds.as_slice()); + cached + } + _ => self.delegate.cx().mk_canonical_var_kinds(&self.state.var_kinds), + }; // We have finished with this canonicalizer and can return its state to the delegate for // later reuse. @@ -330,7 +351,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let sub_root = self.get_or_insert_sub_root(vid); let ui = match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => ty::UniverseIndex::ROOT, + CanonicalizeMode::Input(_) => ty::UniverseIndex::ROOT, CanonicalizeMode::Response { .. } => self .delegate .universe_of_ty(vid) @@ -359,7 +380,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } }, ty::Placeholder(placeholder) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::PlaceholderTy(PlaceholderType::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -368,7 +389,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), }, ty::Param(_) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::PlaceholderTy(PlaceholderType::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -429,7 +450,7 @@ impl, I: Interner> TypeFolder for Canonicaliz // We don't canonicalize `ReStatic` in the `param_env` as we use it // when checking whether a `ParamEnv` candidate is global. ty::ReStatic => match self.canonicalize_mode { - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -541,7 +562,7 @@ impl, I: Interner> TypeFolder for Canonicaliz ); match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::Const(ty::UniverseIndex::ROOT) } CanonicalizeMode::Response { .. } => { @@ -552,7 +573,7 @@ impl, I: Interner> TypeFolder for Canonicaliz ty::InferConst::Fresh(_) => unimplemented!(), }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::PlaceholderConst(PlaceholderConst::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -563,7 +584,7 @@ impl, I: Interner> TypeFolder for Canonicaliz } }, ty::ConstKind::Param(_) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::PlaceholderConst(PlaceholderConst::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -592,7 +613,7 @@ impl, I: Interner> TypeFolder for Canonicaliz match self.canonicalize_mode { CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) | CanonicalizeMode::Response { max_input_universe: _ } => {} - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { panic!("erasing 'static in env") } } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 7aa3d87328fe7..edcc0082a942f 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -317,7 +317,7 @@ pub struct CanonicalParamEnvCacheEntry { pub param_env: I::ParamEnv, pub variables: Vec, pub variable_lookup_table: HashMap, - pub var_kinds: Vec>, + pub var_kinds: I::CanonicalVarKinds, } /// State used and modified by a canonicalizer during canonicalization. To avoid many allocations, From bec219061d27a7f7b15808f663127242f6087641 Mon Sep 17 00:00:00 2001 From: Acrimon Date: Sat, 26 Sep 2026 21:22:17 +0200 Subject: [PATCH 07/31] inline and cold attributes on async fn and async closures affect the poll impl instead of the desugared creator function. --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 67 ++++++++++++++++- tests/codegen-llvm/async-fn-cold-attr.rs | 51 +++++++++++++ tests/codegen-llvm/async-fn-inline-attr.rs | 71 +++++++++++++++++++ .../inline-always-async-fn.aarch64.stderr | 10 +++ .../target-feature/inline-always-async-fn.rs | 29 ++++++++ .../inline-always-async-fn.x86_64.stderr | 10 +++ 6 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 tests/codegen-llvm/async-fn-cold-attr.rs create mode 100644 tests/codegen-llvm/async-fn-inline-attr.rs create mode 100644 tests/ui/target-feature/inline-always-async-fn.aarch64.stderr create mode 100644 tests/ui/target-feature/inline-always-async-fn.rs create mode 100644 tests/ui/target-feature/inline-always-async-fn.x86_64.stderr diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index c3bace9569dd0..691224662f132 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -72,8 +72,15 @@ fn process_builtin_attrs( AttributeKind::Cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, AttributeKind::ExportName { name, .. } => codegen_fn_attrs.symbol_name = Some(*name), AttributeKind::Inline(inline, span) => { - codegen_fn_attrs.inline = *inline; - interesting_spans.inline = Some(*span); + // On an `async fn` (or similar), inlining hints are meant for the code the user + // wrote, which lives in the body coroutine. The constructor is trivial and left to + // the usual heuristics. `#[rustc_force_inline]` is rejected on such items anyway. + if matches!(inline, InlineAttr::Force { .. }) + || !constructs_desugared_body_coroutine(tcx, did) + { + codegen_fn_attrs.inline = *inline; + interesting_spans.inline = Some(*span); + } } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::RustcAlign { align, .. } => codegen_fn_attrs.alignment = Some(*align), @@ -297,9 +304,52 @@ fn process_builtin_attrs( } } + // The body coroutine can't carry attributes of its own, so it takes the ones describing the + // code the user wrote from the `async fn` (or similar) it was desugared from. This makes e.g. + // `#[inline(never)] async fn` affect `Future::poll`. See #129347. + if is_desugared_body_coroutine(tcx, did) { + let parent = tcx.local_parent(did); + if let Some((inline, span)) = find_attr!( + tcx, + parent, + Inline(inline, span) if !matches!(inline, InlineAttr::Force { .. }) => (*inline, *span) + ) { + codegen_fn_attrs.inline = inline; + interesting_spans.inline = Some(span); + } + // Unlike inlining hints, `#[cold]` stays on the constructor as well: calling it is just as + // unlikely, and its call sites are only recognized as cold through that. + if find_attr!(tcx, parent, Cold) { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; + } + } + interesting_spans } +/// Whether `did` is the coroutine holding the body of an `async fn`, `gen fn`, `async gen fn`, or +/// `async` closure, as opposed to one written as an `async {}` block. +fn is_desugared_body_coroutine(tcx: TyCtxt<'_>, did: LocalDefId) -> bool { + matches!( + tcx.coroutine_kind(did), + Some(hir::CoroutineKind::Desugared( + _, + hir::CoroutineSource::Fn | hir::CoroutineSource::Closure + )) + ) +} + +/// Whether `did` is an `async fn`, `gen fn`, `async gen fn`, or `async` closure, i.e. its body +/// does nothing but construct a [desugared body coroutine](is_desugared_body_coroutine). +fn constructs_desugared_body_coroutine(tcx: TyCtxt<'_>, did: LocalDefId) -> bool { + tcx.hir_maybe_body_owned_by(did).is_some_and(|body| { + matches!( + body.value.kind, + hir::ExprKind::Closure(closure) if is_desugared_body_coroutine(tcx, closure.def_id) + ) + }) +} + /// Applies overrides for codegen fn attrs. These often have a specific reason why they're necessary. /// Please comment why when adding a new one! fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut CodegenFnAttrs) { @@ -336,7 +386,18 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // its parent function, which effectively inherits the features anyway. Boxing this closure // would result in this closure being compiled without the inherited target features, but this // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. - if tcx.is_closure_like(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always { + // + // That reasoning doesn't hold for the body coroutine of an `async fn` or `gen fn`: it is never + // inlined into the function constructing it, yet its body was checked as part of that function. + // It always inherits, which makes `check_result` reject `#[inline(always)]` there just like it + // does on the function itself. + if tcx.is_closure_like(did.to_def_id()) + && (codegen_fn_attrs.inline != InlineAttr::Always + || matches!( + tcx.coroutine_kind(did), + Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Fn)) + )) + { let owner_id = tcx.parent(did.to_def_id()); if tcx.def_kind(owner_id).has_codegen_attrs() { codegen_fn_attrs diff --git a/tests/codegen-llvm/async-fn-cold-attr.rs b/tests/codegen-llvm/async-fn-cold-attr.rs new file mode 100644 index 0000000000000..3f4925d9208d4 --- /dev/null +++ b/tests/codegen-llvm/async-fn-cold-attr.rs @@ -0,0 +1,51 @@ +// Checks that `#[cold]` on `async fn`s and async closures applies to the coroutine holding their +// body (i.e. the `Future::poll` implementation), in addition to the function or closure that +// constructs it. +// +//@ edition: 2024 +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no +#![crate_type = "lib"] +#![feature(stmt_expr_attributes)] + +use std::future::Future; +use std::pin::pin; +use std::task::Context; + +// CHECK: ; async_fn_cold_attr::cold{{$}} +// CHECK-NEXT: ; Function Attrs: cold +// CHECK: ; async_fn_cold_attr::cold::{closure#0} +// CHECK-NEXT: ; Function Attrs: cold +#[cold] +pub async fn cold() {} + +// CHECK: ; async_fn_cold_attr::not_cold::{closure#0} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: cold +// CHECK-SAME: {{$}} +pub async fn not_cold() {} + +pub struct S; + +impl S { + // CHECK: ; ::method{{$}} + // CHECK-NEXT: ; Function Attrs: cold + // CHECK: ; ::method::{closure#0} + // CHECK-NEXT: ; Function Attrs: cold + #[cold] + pub async fn method(&self) {} +} + +// CHECK: ; async_fn_cold_attr::poll_all{{$}} +pub fn poll_all(cx: &mut Context<'_>) { + let _ = pin!(cold()).poll(cx); + let _ = pin!(not_cold()).poll(cx); + let _ = pin!(S.method()).poll(cx); + + // CHECK: ; async_fn_cold_attr::poll_all::{closure#0}{{$}} + // CHECK-NEXT: ; Function Attrs: cold + // CHECK: ; async_fn_cold_attr::poll_all::{closure#0}::{closure#0}:: + // CHECK-NEXT: ; Function Attrs: cold + let closure = #[cold] + async || {}; + let _ = pin!(closure()).poll(cx); +} diff --git a/tests/codegen-llvm/async-fn-inline-attr.rs b/tests/codegen-llvm/async-fn-inline-attr.rs new file mode 100644 index 0000000000000..d97300dd6046c --- /dev/null +++ b/tests/codegen-llvm/async-fn-inline-attr.rs @@ -0,0 +1,71 @@ +// Checks that inline attributes on `async fn`s and async closures apply to the coroutine holding +// their body (i.e. the `Future::poll` implementation) rather than to the function or closure that +// merely constructs it. See #129347. +// +//@ edition: 2024 +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no +#![crate_type = "lib"] +#![feature(stmt_expr_attributes)] + +use std::future::Future; +use std::pin::pin; +use std::task::Context; + +// CHECK: ; async_fn_inline_attr::never{{$}} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: noinline +// CHECK-SAME: {{$}} +// CHECK: ; async_fn_inline_attr::never::{closure#0} +// CHECK-NEXT: ; Function Attrs: noinline +#[inline(never)] +pub async fn never() {} + +// CHECK: ; async_fn_inline_attr::always{{$}} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: alwaysinline +// CHECK-SAME: {{$}} +// CHECK: ; async_fn_inline_attr::always::{closure#0} +// CHECK-NEXT: ; Function Attrs: alwaysinline +#[inline(always)] +pub async fn always() {} + +// The body coroutine would get an inline hint regardless, like all closures. +// CHECK: ; async_fn_inline_attr::hint{{$}} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: inlinehint +// CHECK-SAME: {{$}} +// CHECK: ; async_fn_inline_attr::hint::{closure#0} +// CHECK-NEXT: ; Function Attrs: inlinehint +#[inline] +pub async fn hint() {} + +pub struct S; + +impl S { + // CHECK: ; ::method{{$}} + // CHECK-NEXT: ; Function Attrs: + // CHECK-NOT: noinline + // CHECK-SAME: {{$}} + // CHECK: ; ::method::{closure#0} + // CHECK-NEXT: ; Function Attrs: noinline + #[inline(never)] + pub async fn method(&self) {} +} + +// CHECK: ; async_fn_inline_attr::poll_all{{$}} +pub fn poll_all(cx: &mut Context<'_>) { + let _ = pin!(never()).poll(cx); + let _ = pin!(always()).poll(cx); + let _ = pin!(hint()).poll(cx); + let _ = pin!(S.method()).poll(cx); + + // CHECK: ; async_fn_inline_attr::poll_all::{closure#0}{{$}} + // CHECK-NEXT: ; Function Attrs: + // CHECK-NOT: noinline + // CHECK-SAME: {{$}} + // CHECK: ; async_fn_inline_attr::poll_all::{closure#0}::{closure#0}:: + // CHECK-NEXT: ; Function Attrs: noinline + let closure = #[inline(never)] + async || {}; + let _ = pin!(closure()).poll(cx); +} diff --git a/tests/ui/target-feature/inline-always-async-fn.aarch64.stderr b/tests/ui/target-feature/inline-always-async-fn.aarch64.stderr new file mode 100644 index 0000000000000..40ce807d0b01c --- /dev/null +++ b/tests/ui/target-feature/inline-always-async-fn.aarch64.stderr @@ -0,0 +1,10 @@ +error: cannot use `#[inline(always)]` with `#[target_feature]` + --> $DIR/inline-always-async-fn.rs:13:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + | + = note: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574 + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/inline-always-async-fn.rs b/tests/ui/target-feature/inline-always-async-fn.rs new file mode 100644 index 0000000000000..c6b49819d8733 --- /dev/null +++ b/tests/ui/target-feature/inline-always-async-fn.rs @@ -0,0 +1,29 @@ +// Inlining attributes on an `async fn` apply to its body coroutine instead of the function +// constructing it (#129347). The body coroutine inherits the function's target features, so +// `#[inline(always)]` must still be rejected together with `#[target_feature]`. +// +//@ revisions: x86_64 aarch64 +//@[x86_64] only-x86_64 +//@[aarch64] only-aarch64 +//@ edition: 2024 + +#![crate_type = "lib"] +#![feature(stmt_expr_attributes)] + +#[inline(always)] +//~^ ERROR cannot use `#[inline(always)]` with `#[target_feature]` +#[cfg_attr(target_arch = "x86_64", target_feature(enable = "sse2"))] +#[cfg_attr(target_arch = "aarch64", target_feature(enable = "neon"))] +pub async fn always() {} + +#[inline(never)] +#[cfg_attr(target_arch = "x86_64", target_feature(enable = "sse2"))] +#[cfg_attr(target_arch = "aarch64", target_feature(enable = "neon"))] +pub async fn never() {} + +#[cfg_attr(target_arch = "x86_64", target_feature(enable = "sse2"))] +#[cfg_attr(target_arch = "aarch64", target_feature(enable = "neon"))] +pub fn with_async_closure() { + // Just like a regular `#[inline(always)]` closure, this doesn't inherit the target features. + let _ = #[inline(always)] async || {}; +} diff --git a/tests/ui/target-feature/inline-always-async-fn.x86_64.stderr b/tests/ui/target-feature/inline-always-async-fn.x86_64.stderr new file mode 100644 index 0000000000000..40ce807d0b01c --- /dev/null +++ b/tests/ui/target-feature/inline-always-async-fn.x86_64.stderr @@ -0,0 +1,10 @@ +error: cannot use `#[inline(always)]` with `#[target_feature]` + --> $DIR/inline-always-async-fn.rs:13:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + | + = note: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574 + +error: aborting due to 1 previous error + From 1c517b29acf029cb01a41e3df33137f44d11329b Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 2 Nov 2026 12:29:21 +0100 Subject: [PATCH 08/31] Don't keep #[rustc_force_inline] on async/gen fn constructors It is already rejected on such functions, and keeping it only produced a redundant 'incompatible with #[cold]' error. --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 8 +++--- tests/ui/force-inlining/invalid-async-cold.rs | 25 +++++++++++++++++++ .../force-inlining/invalid-async-cold.stderr | 20 +++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 tests/ui/force-inlining/invalid-async-cold.rs create mode 100644 tests/ui/force-inlining/invalid-async-cold.stderr diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 691224662f132..711e6ec32aff0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -74,10 +74,8 @@ fn process_builtin_attrs( AttributeKind::Inline(inline, span) => { // On an `async fn` (or similar), inlining hints are meant for the code the user // wrote, which lives in the body coroutine. The constructor is trivial and left to - // the usual heuristics. `#[rustc_force_inline]` is rejected on such items anyway. - if matches!(inline, InlineAttr::Force { .. }) - || !constructs_desugared_body_coroutine(tcx, did) - { + // the usual heuristics. + if !constructs_desugared_body_coroutine(tcx, did) { codegen_fn_attrs.inline = *inline; interesting_spans.inline = Some(*span); } @@ -309,6 +307,8 @@ fn process_builtin_attrs( // `#[inline(never)] async fn` affect `Future::poll`. See #129347. if is_desugared_body_coroutine(tcx, did) { let parent = tcx.local_parent(did); + // `#[rustc_force_inline]` is already rejected on the parent. Propagating it would only + // cause `CheckForceInline` to report the same attribute again for the coroutine. if let Some((inline, span)) = find_attr!( tcx, parent, diff --git a/tests/ui/force-inlining/invalid-async-cold.rs b/tests/ui/force-inlining/invalid-async-cold.rs new file mode 100644 index 0000000000000..f0a699ac1caa0 --- /dev/null +++ b/tests/ui/force-inlining/invalid-async-cold.rs @@ -0,0 +1,25 @@ +//@ edition: 2024 +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(gen_blocks)] +#![feature(rustc_attrs)] + +// `#[inline]` on an `async fn` or `gen fn` applies to its body coroutine, but +// `#[rustc_force_inline]` must not: it is already rejected on such functions, +// so it must not also be reported as incompatible with `#[cold]`, which both +// the function and its body coroutine get. + +#[rustc_force_inline] +//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function +#[cold] +pub async fn async_cold() {} + +#[rustc_force_inline] +//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function +#[cold] +pub gen fn gen_cold() {} + +pub fn caller() { + let _ = async_cold(); + let _ = gen_cold(); +} diff --git a/tests/ui/force-inlining/invalid-async-cold.stderr b/tests/ui/force-inlining/invalid-async-cold.stderr new file mode 100644 index 0000000000000..cc176458c0c13 --- /dev/null +++ b/tests/ui/force-inlining/invalid-async-cold.stderr @@ -0,0 +1,20 @@ +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid-async-cold.rs:12:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | pub async fn async_cold() {} + | ------------------------- `async`, `gen` or `async gen` function + +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid-async-cold.rs:17:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | pub gen fn gen_cold() {} + | --------------------- `async`, `gen` or `async gen` function + +error: aborting due to 2 previous errors + From 765b3ac2fb780b220afb50ec7b02f0945d058ada Mon Sep 17 00:00:00 2001 From: panstromek Date: Mon, 2 Nov 2026 12:36:30 +0100 Subject: [PATCH 09/31] ref: lookup source info in PackedRefChecker only when it's needed instead tracking it through the whole traversal even if the lint is never fired --- .../src/check_packed_ref.rs | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 115d687c44b26..2b90b9732d484 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -10,8 +10,7 @@ pub(super) struct CheckPackedRef; impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let typing_env = body.typing_env(tcx); - let source_info = SourceInfo::outermost(body.span); - let mut checker = PackedRefChecker { body, tcx, typing_env, source_info }; + let mut checker = PackedRefChecker { body, tcx, typing_env }; checker.visit_body(body); } } @@ -20,27 +19,15 @@ struct PackedRefChecker<'a, 'tcx> { body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - source_info: SourceInfo, } impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - // Make sure we know where in the MIR we are. - self.source_info = terminator.source_info; - self.super_terminator(terminator, location); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - // Make sure we know where in the MIR we are. - self.source_info = statement.source_info; - self.super_statement(statement, location); - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { if context.is_borrow() && let Some((adt, pack)) = util::place_unalignment(self.tcx, self.body, self.typing_env, *place) { + let source_info = self.body.source_info(location); let def_id = self.body.source.instance.def_id(); if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id) && self.tcx.is_builtin_derived(impl_def_id) @@ -48,10 +35,10 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { // If we ever reach here it means that the generated derive // code is somehow doing an unaligned reference, which it // shouldn't do. - span_bug!(self.source_info.span, "builtin derive created an unaligned reference"); + span_bug!(source_info.span, "builtin derive created an unaligned reference"); } else { self.tcx.dcx().emit_err(diagnostics::UnalignedPackedRef { - span: self.source_info.span, + span: source_info.span, ty_descr: adt.descr(), align: pack.bytes(), }); From 2caedab4f6ededde58be975e6bc7a883a8483543 Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 2 Nov 2026 12:39:39 +0100 Subject: [PATCH 10/31] Adapt async fn inline attrs to #[inline(always)] + #[target_feature] being allowed Upstream no longer rejects the combination, so replace the UI test expecting that error with a codegen test checking that the body coroutine still inherits the target features. --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 3 +- .../async-fn-inline-always-target-feature.rs | 32 +++++++++++++++++++ .../inline-always-async-fn.aarch64.stderr | 10 ------ .../target-feature/inline-always-async-fn.rs | 29 ----------------- .../inline-always-async-fn.x86_64.stderr | 10 ------ 5 files changed, 33 insertions(+), 51 deletions(-) create mode 100644 tests/codegen-llvm/async-fn-inline-always-target-feature.rs delete mode 100644 tests/ui/target-feature/inline-always-async-fn.aarch64.stderr delete mode 100644 tests/ui/target-feature/inline-always-async-fn.rs delete mode 100644 tests/ui/target-feature/inline-always-async-fn.x86_64.stderr diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 711e6ec32aff0..10baf16915d15 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -389,8 +389,7 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // // That reasoning doesn't hold for the body coroutine of an `async fn` or `gen fn`: it is never // inlined into the function constructing it, yet its body was checked as part of that function. - // It always inherits, which makes `check_result` reject `#[inline(always)]` there just like it - // does on the function itself. + // It always inherits, so it is compiled with the same features as the function itself. if tcx.is_closure_like(did.to_def_id()) && (codegen_fn_attrs.inline != InlineAttr::Always || matches!( diff --git a/tests/codegen-llvm/async-fn-inline-always-target-feature.rs b/tests/codegen-llvm/async-fn-inline-always-target-feature.rs new file mode 100644 index 0000000000000..83e635c03a50d --- /dev/null +++ b/tests/codegen-llvm/async-fn-inline-always-target-feature.rs @@ -0,0 +1,32 @@ +// `#[inline(always)]` on an `async fn` applies to its body coroutine (#129347). Unlike a closure +// marked `#[inline(always)]`, that coroutine is never inlined into the function it was written +// in, so it must still inherit that function's `#[target_feature]`s. +// +//@ revisions: x86_64 aarch64 +//@[x86_64] only-x86_64 +//@[aarch64] only-aarch64 +//@ edition: 2024 +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no +#![crate_type = "lib"] + +use std::future::Future; +use std::pin::pin; +use std::task::{Context, Waker}; + +// CHECK: ; async_fn_inline_always_target_feature::always::{closure#0} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define {{.*}} #[[ATTRS:[0-9]+]] +#[inline(always)] +#[cfg_attr(target_arch = "x86_64", target_feature(enable = "avx2"))] +#[cfg_attr(target_arch = "aarch64", target_feature(enable = "sha3"))] +pub async fn always() {} + +#[cfg_attr(target_arch = "x86_64", target_feature(enable = "avx2"))] +#[cfg_attr(target_arch = "aarch64", target_feature(enable = "sha3"))] +pub fn poll_always() { + let mut cx = Context::from_waker(Waker::noop()); + let _ = pin!(always()).poll(&mut cx); +} + +// x86_64: attributes #[[ATTRS]] = {{{.*}}"target-features"="{{[^"]*}}+avx2 +// aarch64: attributes #[[ATTRS]] = {{{.*}}"target-features"="{{[^"]*}}+sha3 diff --git a/tests/ui/target-feature/inline-always-async-fn.aarch64.stderr b/tests/ui/target-feature/inline-always-async-fn.aarch64.stderr deleted file mode 100644 index 40ce807d0b01c..0000000000000 --- a/tests/ui/target-feature/inline-always-async-fn.aarch64.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/inline-always-async-fn.rs:13:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - | - = note: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574 - -error: aborting due to 1 previous error - diff --git a/tests/ui/target-feature/inline-always-async-fn.rs b/tests/ui/target-feature/inline-always-async-fn.rs deleted file mode 100644 index c6b49819d8733..0000000000000 --- a/tests/ui/target-feature/inline-always-async-fn.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Inlining attributes on an `async fn` apply to its body coroutine instead of the function -// constructing it (#129347). The body coroutine inherits the function's target features, so -// `#[inline(always)]` must still be rejected together with `#[target_feature]`. -// -//@ revisions: x86_64 aarch64 -//@[x86_64] only-x86_64 -//@[aarch64] only-aarch64 -//@ edition: 2024 - -#![crate_type = "lib"] -#![feature(stmt_expr_attributes)] - -#[inline(always)] -//~^ ERROR cannot use `#[inline(always)]` with `#[target_feature]` -#[cfg_attr(target_arch = "x86_64", target_feature(enable = "sse2"))] -#[cfg_attr(target_arch = "aarch64", target_feature(enable = "neon"))] -pub async fn always() {} - -#[inline(never)] -#[cfg_attr(target_arch = "x86_64", target_feature(enable = "sse2"))] -#[cfg_attr(target_arch = "aarch64", target_feature(enable = "neon"))] -pub async fn never() {} - -#[cfg_attr(target_arch = "x86_64", target_feature(enable = "sse2"))] -#[cfg_attr(target_arch = "aarch64", target_feature(enable = "neon"))] -pub fn with_async_closure() { - // Just like a regular `#[inline(always)]` closure, this doesn't inherit the target features. - let _ = #[inline(always)] async || {}; -} diff --git a/tests/ui/target-feature/inline-always-async-fn.x86_64.stderr b/tests/ui/target-feature/inline-always-async-fn.x86_64.stderr deleted file mode 100644 index 40ce807d0b01c..0000000000000 --- a/tests/ui/target-feature/inline-always-async-fn.x86_64.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/inline-always-async-fn.rs:13:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - | - = note: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574 - -error: aborting due to 1 previous error - From edf718d00bbb9b067e3ed3d8aac11a3f53704047 Mon Sep 17 00:00:00 2001 From: panstromek Date: Mon, 2 Nov 2026 12:40:03 +0100 Subject: [PATCH 11/31] ref: avoid unnecessary MIR traversals in CheckPackedRef We only need to traverse CFG for this lint, so we can iterate over basic blocks directly. --- compiler/rustc_mir_transform/src/check_packed_ref.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 2b90b9732d484..e3262a8080071 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -11,7 +11,9 @@ impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let typing_env = body.typing_env(tcx); let mut checker = PackedRefChecker { body, tcx, typing_env }; - checker.visit_body(body); + for (bb, data) in body.basic_blocks.iter_enumerated() { + checker.visit_basic_block_data(bb, data); + } } } From 9bf6dcff21806ee072d014142f18b19ce9806ef8 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Fri, 16 Oct 2026 09:35:58 +0700 Subject: [PATCH 12/31] Add `let_underscore_drop_guard` lint. This lint is similar to the existing `let_underscore_lock` lint, but applies to `DropGuard` instead of `MutexGuard` and similar types. --- compiler/rustc_lint/src/diagnostics.rs | 7 ++ compiler/rustc_lint/src/let_underscore.rs | 48 ++++++++++- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/mem/drop_guard.rs | 1 + .../let_underscore_drop_guard.rs | 23 +++++ .../let_underscore_drop_guard.stderr | 86 +++++++++++++++++++ 6 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/let_underscore/let_underscore_drop_guard.rs create mode 100644 tests/ui/lint/let_underscore/let_underscore_drop_guard.stderr diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index 652fbabb174cd..2b1a8132e65e8 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -1348,6 +1348,13 @@ pub(crate) enum NonBindingLet { #[subdiagnostic] sub: NonBindingLetSub, }, + #[diag("non-binding let on a `DropGuard`")] + DropGuard { + #[label("this `DropGuard` is not assigned to a binding and is immediately dropped")] + pat: Span, + #[subdiagnostic] + sub: NonBindingLetSub, + }, #[diag("non-binding let on a type that has a destructor")] DropType { #[subdiagnostic] diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 9d154be832995..07c2bf6f0ca13 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -95,7 +95,45 @@ declare_lint! { "non-binding let on a synchronization lock" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]); +declare_lint! { + /// The `let_underscore_drop_guard` lint checks for statements which don't bind + /// a `DropGuard` to anything, causing its closure to run immediately instead + /// of at end of scope, which is typically incorrect. + /// + /// ### Example + #[cfg_attr(bootstrap, doc = "```rust")] + #[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")] + /// use std::mem::DropGuard; + /// + /// // The closure runs immediately instead of at the end of the scope, + /// // which is probably not intended. + /// let _ = DropGuard::new((), |_| { + /// println!("cleaning up"); + /// }); + #[cfg_attr(bootstrap, doc = "```")] + #[cfg_attr(not(bootstrap), doc = "```")] + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Statements which assign an expression to an underscore causes the + /// expression to immediately drop instead of extending the expression's + /// lifetime to the end of the scope. This is usually unintended, + /// especially for types like `DropGuard`, which are typically used to + /// ensure running some cleanup code at the end of a scope. + /// + /// If you want to extend the expression's lifetime to the end of the scope, + /// assign an underscore-prefixed name (such as `_foo`) to the expression. + /// If you do actually want to drop the expression immediately, then + /// calling `std::mem::drop` on the expression is clearer and helps convey + /// intent. + pub LET_UNDERSCORE_DROP_GUARD, + Deny, + "non-binding let on a `DropGuard`" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP_GUARD]); const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [ rustc_span::sym::MutexGuard, @@ -144,6 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())), _ => false, }; + let is_drop_guard = matches!(ty.kind(), ty::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::DropGuard, adt.did())); let can_use_init = is_top_level.then_some(local.init).flatten(); @@ -161,6 +200,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { span, NonBindingLet::SyncLock { sub, pat: pat.span }, ); + } else if is_drop_guard { + let span = MultiSpan::from_span(pat.span); + cx.emit_span_lint( + LET_UNDERSCORE_DROP_GUARD, + span, + NonBindingLet::DropGuard { sub, pat: pat.span }, + ); // Only emit let_underscore_drop for top-level `_` patterns. } else if can_use_init.is_some() { cx.emit_span_lint(LET_UNDERSCORE_DROP, local.span, NonBindingLet::DropType { sub }); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6f078fef4892b..8e477a7a5e057 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -208,6 +208,7 @@ symbols! { Deref, DispatchFromDyn, Display, + DropGuard, Dual, DualOnly, Dualv, diff --git a/library/core/src/mem/drop_guard.rs b/library/core/src/mem/drop_guard.rs index d997ab680e354..f7e610c68ddc9 100644 --- a/library/core/src/mem/drop_guard.rs +++ b/library/core/src/mem/drop_guard.rs @@ -30,6 +30,7 @@ use crate::ops::{Deref, DerefMut}; #[stable(feature = "drop_guard", since = "1.100.0")] #[doc(alias = "ScopeGuard")] #[doc(alias = "defer")] +#[rustc_diagnostic_item = "DropGuard"] pub struct DropGuard<#[rustc_assert_variance(covariant)] T, #[rustc_assert_variance(covariant)] F> where F: FnOnce(T), diff --git a/tests/ui/lint/let_underscore/let_underscore_drop_guard.rs b/tests/ui/lint/let_underscore/let_underscore_drop_guard.rs new file mode 100644 index 0000000000000..b1a82438acdfc --- /dev/null +++ b/tests/ui/lint/let_underscore/let_underscore_drop_guard.rs @@ -0,0 +1,23 @@ +use std::mem::DropGuard; + +struct Struct { + a: T, +} + +fn main() { + let _ = DropGuard::new((), |_| {}); + //~^ERROR non-binding let on a `DropGuard` + _ = DropGuard::new((), |_| {}); + //~^ERROR non-binding let on a `DropGuard` + + let (_, _) = (DropGuard::new((), |_| {}), 1); + //~^ERROR non-binding let on a `DropGuard` + (_, _) = (DropGuard::new((), |_| {}), 1); + //~^ERROR non-binding let on a `DropGuard` + + let (_a, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + //~^ERROR non-binding let on a `DropGuard` + let _b; + (_b, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + //~^ERROR non-binding let on a `DropGuard` +} diff --git a/tests/ui/lint/let_underscore/let_underscore_drop_guard.stderr b/tests/ui/lint/let_underscore/let_underscore_drop_guard.stderr new file mode 100644 index 0000000000000..c4c58fa6b4b95 --- /dev/null +++ b/tests/ui/lint/let_underscore/let_underscore_drop_guard.stderr @@ -0,0 +1,86 @@ +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:8:9 + | +LL | let _ = DropGuard::new((), |_| {}); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | + = note: `#[deny(let_underscore_drop_guard)]` on by default +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let _unused = DropGuard::new((), |_| {}); + | ++++++ +help: consider immediately dropping the value + | +LL - let _ = DropGuard::new((), |_| {}); +LL + drop(DropGuard::new((), |_| {})); + | + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:10:5 + | +LL | _ = DropGuard::new((), |_| {}); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL - _ = DropGuard::new((), |_| {}); +LL + let _unused = DropGuard::new((), |_| {}); + | +help: consider immediately dropping the value + | +LL - _ = DropGuard::new((), |_| {}); +LL + drop(DropGuard::new((), |_| {})); + | + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:13:10 + | +LL | let (_, _) = (DropGuard::new((), |_| {}), 1); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | + = help: consider immediately dropping the value using `drop(..)` after the `let` statement +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let (_unused, _) = (DropGuard::new((), |_| {}), 1); + | ++++++ + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:15:6 + | +LL | (_, _) = (DropGuard::new((), |_| {}), 1); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + --> $DIR/let_underscore_drop_guard.rs:15:6 + | +LL | (_, _) = (DropGuard::new((), |_| {}), 1); + | ^ + = help: consider immediately dropping the value using `drop(..)` after the `let` statement + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:18:26 + | +LL | let (_a, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | + = help: consider immediately dropping the value using `drop(..)` after the `let` statement +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let (_a, Struct { a: _unused }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + | ++++++ + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:21:22 + | +LL | (_b, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + --> $DIR/let_underscore_drop_guard.rs:21:22 + | +LL | (_b, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + | ^ + = help: consider immediately dropping the value using `drop(..)` after the `let` statement + +error: aborting due to 6 previous errors + From 9b1ceffc48c4ca593b68400f9afccb8e3e761b2e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 2 Nov 2026 10:36:51 -0500 Subject: [PATCH 13/31] Reenable the cg_gcc tests that were disabled by accident --- src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile b/src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile index d248faaabca6c..2a721006bfdc0 100644 --- a/src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile +++ b/src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile @@ -42,7 +42,7 @@ ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --set llvm.libzstd=true" ENV SCRIPT="python3 ../x.py \ --stage 2 \ - test tests \ + test tests compiler/rustc_codegen_gcc \ --test-codegen-backend gcc \ --skip tests/coverage \ --skip tests/coverage-run-rustdoc \ From 86fd1018211811855ebaf4415cacdca7249f3cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 2 Nov 2026 20:56:02 +0100 Subject: [PATCH 14/31] rename sizedness_fast_path to implicit_fast_path --- compiler/rustc_trait_selection/src/solve/delegate.rs | 4 ++-- compiler/rustc_trait_selection/src/traits/fulfill.rs | 4 ++-- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/query/type_op/prove_predicate.rs | 4 ++-- compiler/rustc_trait_selection/src/traits/select/mod.rs | 4 ++-- compiler/rustc_trait_selection/src/traits/util.rs | 2 +- compiler/rustc_traits/src/evaluate_obligation.rs | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index c55c43e18d2bf..be07ff71ccf34 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -33,7 +33,7 @@ use thin_vec::{ThinVec, thin_vec}; use super::inspect::InferCtxtProofTreeExt; use crate::solve::inspect::{self, InspectConfig, ProofTreeVisitor}; -use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph}; +use crate::traits::{EvaluateConstErr, ObligationCause, implicit_fast_path, specialization_graph}; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -178,7 +178,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< match self.0.tcx.as_lang_item(trait_pred.def_id()) { Some(LangItem::Sized) | Some(LangItem::MetaSized) => { let predicate = self.deeply_resolve_ignoring_regions(goal.predicate); - if sizedness_fast_path(self.tcx, predicate, goal.param_env) { + if implicit_fast_path(self.tcx, predicate, goal.param_env) { Outcome::TriviallyHolds } else { Outcome::NoFastPath diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 3a1ad2ee5feab..56e80958e6892 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -33,7 +33,7 @@ use crate::infer::InferCtxt; use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{EvaluateConstErr, sizedness_fast_path}; +use crate::traits::{EvaluateConstErr, implicit_fast_path}; pub(crate) type PendingPredicateObligations<'tcx> = ThinVec>; @@ -398,7 +398,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; if !infcx.disable_trait_solver_fast_paths() - && sizedness_fast_path(infcx.tcx, obligation.predicate, obligation.param_env) + && implicit_fast_path(infcx.tcx, obligation.predicate, obligation.param_env) { return ProcessResult::Changed(thin_vec![]); } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 7076ec99c141c..326710007564c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -66,7 +66,7 @@ pub use self::specialize::{ pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::{ BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final, - sizedness_fast_path, supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, + implicit_fast_path, supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars, }; use crate::error_reporting::InferCtxtErrorExt; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 148f75e0a6308..b8c2a3078e8cb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; use crate::infer::InferCtxt; use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse}; -use crate::traits::{ObligationCtxt, sizedness_fast_path}; +use crate::traits::{ObligationCtxt, implicit_fast_path}; impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { type QueryResponse = (); @@ -15,7 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { infcx: &InferCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>, ) -> Option { - if sizedness_fast_path(infcx.tcx, key.value.predicate, key.param_env) { + if implicit_fast_path(infcx.tcx, key.value.predicate, key.param_env) { return Some(()); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e280184169844..279392221a33c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -47,7 +47,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{EvaluateConstErr, ProjectionCacheKey, effects, sizedness_fast_path}; +use crate::traits::{EvaluateConstErr, ProjectionCacheKey, effects, implicit_fast_path}; mod _match; mod candidate_assembly; @@ -537,7 +537,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if !self.infcx.disable_trait_solver_fast_paths() - && sizedness_fast_path(self.tcx(), obligation.predicate, obligation.param_env) + && implicit_fast_path(self.tcx(), obligation.predicate, obligation.param_env) { return Ok(EvaluatedToOk); } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c60ebc4758ead..9cbb53c6f63bd 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -217,7 +217,7 @@ pub fn with_replaced_escaping_bound_vars< } } -pub fn sizedness_fast_path<'tcx>( +pub fn implicit_fast_path<'tcx>( tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 6bc6543a0a01b..ac5df8b93f482 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -5,7 +5,7 @@ use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; use rustc_trait_selection::traits::{ EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, - sizedness_fast_path, + implicit_fast_path, }; use tracing::debug; @@ -24,7 +24,7 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; - if !tcx.disable_trait_solver_fast_paths() && sizedness_fast_path(tcx, predicate, param_env) { + if !tcx.disable_trait_solver_fast_paths() && implicit_fast_path(tcx, predicate, param_env) { return Ok(EvaluationResult::EvaluatedToOk); } From 1b8ce170a333c8e8b984f62796fceedbb5715ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 2 Nov 2026 21:17:24 +0100 Subject: [PATCH 15/31] refactor implicit bounds addition --- .../src/collect/clauses_of.rs | 41 ++++----------- .../src/collect/item_bounds.rs | 21 ++------ .../src/hir_ty_lowering/bounds.rs | 52 ++++++++++++------- .../src/hir_ty_lowering/dyn_trait.rs | 4 +- .../src/hir_ty_lowering/mod.rs | 6 ++- 5 files changed, 53 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs index ae384a67ee6aa..49f56ddefb0e0 100644 --- a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs @@ -16,6 +16,7 @@ use super::item_bounds::explicit_item_bounds_with_filter; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; use crate::delegation::inherit_clauses_for_delegation_item; +use crate::hir_ty_lowering::bounds::IncludeSizedImplicitBound; use crate::hir_ty_lowering::{ HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, @@ -195,19 +196,13 @@ fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generi PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - tcx.types.self_param, - self_bounds, - ImpliedBoundsContext::TraitDef(def_id), - span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, tcx.types.self_param, self_bounds, ImpliedBoundsContext::TraitDef(def_id), span, + IncludeSizedImplicitBound::Yes, ); clauses.extend(bounds); } @@ -234,19 +229,13 @@ fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generi let param_ty = icx.lowerer().lower_ty_param(param.hir_id); let mut bounds = Vec::new(); // Implicit bounds are added to type params unless a `?Trait` bound is found - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - param_ty, - &[], - ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), - param.span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, param_ty, &[], ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, + IncludeSizedImplicitBound::Yes, ); trace!(?bounds); clauses.extend(bounds); @@ -690,19 +679,13 @@ pub(super) fn implied_clauses_with_filter<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - self_param_ty, - superbounds, - ImpliedBoundsContext::TraitDef(trait_def_id), - item.span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, self_param_ty, superbounds, ImpliedBoundsContext::TraitDef(trait_def_id), item.span, + IncludeSizedImplicitBound::Yes, ); } //`ConstIfConst` is only interested in `[const]` bounds. @@ -992,19 +975,13 @@ impl<'tcx> ItemCtxt<'tcx> { match param.kind { hir::GenericParamKind::Type { .. } => { let param_ty = self.lowerer().lower_ty_param(param.hir_id); - self.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - param_ty, - &[], - ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), - param.span, - ); - self.lowerer().add_default_traits( + self.lowerer().add_implicit_bounds( &mut bounds, param_ty, &[], ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, + IncludeSizedImplicitBound::Yes, ); } hir::GenericParamKind::Lifetime { .. } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 5ed5745310f16..a805ea0c29e7a 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -11,6 +11,7 @@ use tracing::{debug, instrument}; use super::ItemCtxt; use super::clauses_of::assert_only_contains_clauses_from; +use crate::hir_ty_lowering::bounds::IncludeSizedImplicitBound; use crate::hir_ty_lowering::{ HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, }; @@ -54,19 +55,13 @@ fn associated_type_bounds<'tcx>( | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { // Implicit bounds are added to associated types unless a `?Trait` bound is found. - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - item_ty, - hir_bounds, - ImpliedBoundsContext::AssociatedTypeOrImplTrait, - span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, item_ty, hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, + IncludeSizedImplicitBound::Yes, ); // Also collect `where Self::Assoc: Trait` from the parent trait's where clauses. @@ -381,19 +376,13 @@ fn opaque_type_bounds<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - item_ty, - hir_bounds, - ImpliedBoundsContext::AssociatedTypeOrImplTrait, - span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, item_ty, hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, + IncludeSizedImplicitBound::Yes, ); } //`ConstIfConst` is only interested in `[const]` bounds. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 0b7df89551da8..c4b4b8f04427b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -137,7 +137,35 @@ fn add_trait_bound<'tcx>( bounds.insert(0, (trait_ref.upcast(tcx), span)); } +pub(crate) enum IncludeSizedImplicitBound { + Yes, + No, +} + impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { + /// Adds implicit sizedness, and in the future `Move` and `Forget`, and default trait bounds. + pub(crate) fn add_implicit_bounds( + &self, + bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, + self_ty: Ty<'tcx>, + hir_bounds: &[hir::GenericBound<'_>], + context: ImpliedBoundsContext<'tcx>, + span: Span, + // Sized is treated slightly more specially than the other implicit bounds. + include_sized: IncludeSizedImplicitBound, + ) { + // Skip adding any default bounds if `#![rustc_no_implicit_bounds]` + if find_attr!(self.tcx(), crate, RustcNoImplicitBounds) { + return; + } + + self.add_default_traits(bounds, self_ty, hir_bounds, context, span); + + if let IncludeSizedImplicitBound::Yes = include_sized { + self.add_implicit_sizedness_bounds(bounds, self_ty, hir_bounds, context, span); + } + } + /// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type. /// /// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit @@ -146,7 +174,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// bounds are present. /// - On parameters, opaque type, associated types and trait aliases, add a `MetaSized` bound if /// a `?Sized` bound is present. - pub(crate) fn add_implicit_sizedness_bounds( + fn add_implicit_sizedness_bounds( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, @@ -156,11 +184,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) { let tcx = self.tcx(); - // Skip adding any default bounds if `#![rustc_no_implicit_bounds]` - if find_attr!(tcx, crate, RustcNoImplicitBounds) { - return; - } - let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); @@ -208,7 +231,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - pub(crate) fn add_default_traits( + fn add_default_traits( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, @@ -224,7 +247,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `experimental_default_bounds` bound to the `bounds` if appropriate. /// /// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`. - pub(crate) fn add_default_trait( + fn add_default_trait( &self, trait_: LangItem, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, @@ -244,23 +267,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } if let Some(trait_did) = tcx.lang_items().get(trait_) - && self.should_add_default_traits(trait_did, hir_bounds, context) + && !collect_bounds(hir_bounds, context, trait_did).any() { add_trait_bound(tcx, bounds, self_ty, trait_did, span); } } - /// Returns `true` if default trait bound should be added. - fn should_add_default_traits( - &self, - trait_def_id: DefId, - hir_bounds: &[hir::GenericBound<'_>], - context: ImpliedBoundsContext<'tcx>, - ) -> bool { - let collected = collect_bounds(hir_bounds, context, trait_def_id); - !find_attr!(self.tcx(), crate, RustcNoImplicitBounds) && !collected.any() - } - pub(crate) fn require_bound_to_relax_default_trait( &self, trait_ref: hir::TraitRef<'_>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index c652174f9ba68..8d9174a74444a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -23,6 +23,7 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::diagnostics::DynTraitAssocItemBindingMentionsSelf; +use crate::hir_ty_lowering::bounds::IncludeSizedImplicitBound; use crate::hir_ty_lowering::{ GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, @@ -75,7 +76,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - self.add_default_traits( + self.add_implicit_bounds( &mut user_written_bounds, dummy_self, &hir_bounds @@ -84,6 +85,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect::>(), ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, + IncludeSizedImplicitBound::No, ); let (mut elaborated_trait_bounds, elaborated_projection_bounds) = diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5edf50d5cb33b..fb07f250cf3ce 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -15,7 +15,7 @@ //! [^1]: This includes types, lifetimes / regions, constants in type positions, //! trait references and bounds. -mod bounds; +pub(crate) mod bounds; mod cmse; mod dyn_trait; pub mod errors; @@ -57,6 +57,7 @@ use tracing::{debug, instrument}; use crate::check::check_abi; use crate::check_c_variadic_abi; use crate::diagnostics::{self, BadReturnTypeNotation, NoFieldOnType, NoVariantNamed}; +use crate::hir_ty_lowering::bounds::IncludeSizedImplicitBound; use crate::hir_ty_lowering::errors::{ GenericsArgsErrExtend, eq_ctxt_suggestion_span, prohibit_assoc_item_constraint, }; @@ -3326,12 +3327,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); - self.add_implicit_sizedness_bounds( + self.add_implicit_bounds( &mut bounds, self_ty, hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, hir_ty.span, + IncludeSizedImplicitBound::Yes, ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); self_ty From 7eb4e4477b662ae7cb6db75a36e4f1d8b3dedbd5 Mon Sep 17 00:00:00 2001 From: Xing Xue Date: Fri, 30 Oct 2026 13:56:53 -0400 Subject: [PATCH 16/31] Implement AIX TLS destructor guard in std and update dynamic-loading-cdylib test: - Add `sys::thread_local::guard::aix` using `__pt_atexit_np` to run main thread TLS destructors on process exit on AIX. - Update `dynamic-loading-cdylib` to use member archive syntax (`RTLD_MEMBER`) for `dlopen` on AIX. - Replace the mode array in `dynamic-loading-cdylib` with a `COMMAND_ARGS` constant that selects `load_only` for musl and AIX because `dlclose` does not invoke TLS destructors on those platforms. --- library/std/src/sys/thread_local/guard/aix.rs | 30 +++++++++++++++++++ library/std/src/sys/thread_local/mod.rs | 4 +++ .../dynamic-loading-cdylib/load_and_unload.rs | 13 ++++++-- .../run-make/dynamic-loading-cdylib/rmake.rs | 18 +++++++---- 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 library/std/src/sys/thread_local/guard/aix.rs diff --git a/library/std/src/sys/thread_local/guard/aix.rs b/library/std/src/sys/thread_local/guard/aix.rs new file mode 100644 index 0000000000000..9b945456bf790 --- /dev/null +++ b/library/std/src/sys/thread_local/guard/aix.rs @@ -0,0 +1,30 @@ +//! AIX registers thread destructors using `__pt_atexit_np`. +//! Calling it registers a callback that runs on thread termination +//! and upon process exit (for the main thread). + +use crate::cell::Cell; +use crate::sys::thread_local::destructors; + +pub fn enable() { + #[thread_local] + static REGISTERED: Cell = Cell::new(false); + + unsafe extern "C" { + fn __pt_atexit_np(flags: i32, dtor: unsafe extern "C" fn(i32) -> i32) -> i32; + } + + if !REGISTERED.replace(true) { + let ret = unsafe { __pt_atexit_np(0, run_dtors) }; + if ret != 0 { + rtabort!("failed to register thread destructor"); + } + } + + unsafe extern "C" fn run_dtors(_: i32) -> i32 { + unsafe { + destructors::run(); + crate::rt::thread_cleanup(); + } + 0 + } +} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 5d3c23ce04678..1c137e52d9319 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -101,6 +101,10 @@ pub(crate) mod guard { mod apple; pub(crate) use apple::enable; } + all(target_thread_local, target_os = "aix") => { + mod aix; + pub(crate) use aix::enable; + } target_os = "windows" => { mod windows; pub(crate) use windows::enable; diff --git a/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs b/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs index eb1baea93dc00..38669eb1a21d7 100644 --- a/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs +++ b/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs @@ -48,6 +48,8 @@ mod libloading { use std::ffi::{c_char, c_int, c_void}; const RTLD_NOW: c_int = 2; + #[cfg(target_os = "aix")] + const RTLD_MEMBER: c_int = 0x00040000; fn cstr_null(s: &str) -> Vec { assert!(!s.as_bytes().contains(&0), "string must not contain interior NUL"); @@ -58,10 +60,17 @@ mod libloading { #[cfg(target_os = "macos")] let filename = cstr_null(&format!("lib{}.dylib", lib_name)); - #[cfg(not(target_os = "macos"))] + #[cfg(target_os = "aix")] + let filename = cstr_null(&format!("./lib{0}.a(lib{0}.so)", lib_name)); + + #[cfg(not(any(target_os = "macos", target_os = "aix")))] let filename = cstr_null(&format!("./lib{}.so", lib_name)); - let handle = unsafe { dlopen(filename.as_ptr(), RTLD_NOW) }; + let flags = RTLD_NOW; + #[cfg(target_os = "aix")] + let flags = flags | RTLD_MEMBER; + + let handle = unsafe { dlopen(filename.as_ptr(), flags) }; if handle.is_null() { None } else { Some(handle) } } diff --git a/tests/run-make/dynamic-loading-cdylib/rmake.rs b/tests/run-make/dynamic-loading-cdylib/rmake.rs index 975722da75d6b..b931863b694a8 100644 --- a/tests/run-make/dynamic-loading-cdylib/rmake.rs +++ b/tests/run-make/dynamic-loading-cdylib/rmake.rs @@ -5,21 +5,29 @@ // - `foo.rs` is a cdylib. // - `load_and_unload.rs` is a binary that loads and unloads the cdylib. // -// This test is ignored on musl hosts because musl's dlclose is a no-op and -// therefore destructors won't run when the library is unloaded. -// See https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries //@ ignore-cross-compile -//@ ignore-musl use run_make_support::{diff, run_with_args, rustc}; +// On musl and AIX, `dlclose` does not invoke TLS destructors upon unloading, +// so only the `load_only` case is tested on those platforms. +// +// Reference for musl: +// https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries + +#[cfg(any(target_env = "musl", target_os = "aix"))] +const TEST_MODES: &[&str] = &["load_only"]; + +#[cfg(not(any(target_env = "musl", target_os = "aix")))] +const TEST_MODES: &[&str] = &["unload", "load_only"]; + fn main() { rustc().input("foo.rs").run(); rustc().crate_type("bin").crate_name("load_and_unload_bin").input("load_and_unload.rs").run(); - for command_arg in ["unload", "load_only"] { + for command_arg in TEST_MODES { let out_raw = run_with_args("load_and_unload_bin", &[command_arg]).stdout_utf8(); #[cfg(windows)] From f0767bbb0afbe72ab78bb7b12380a9925eee231f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 2 Nov 2026 22:11:10 +0100 Subject: [PATCH 17/31] add is_implicit_trait to tcx --- compiler/rustc_hir_analysis/src/check/mod.rs | 4 +++- .../rustc_hir_analysis/src/collect/clauses_of.rs | 12 ++++++------ .../src/collect/item_bounds.rs | 9 ++++----- .../src/hir_ty_lowering/bounds.rs | 16 ++++++---------- .../src/hir_ty_lowering/dyn_trait.rs | 7 +++---- .../src/hir_ty_lowering/mod.rs | 9 ++++----- .../src/multiple_supertrait_upcastable.rs | 6 ++++-- compiler/rustc_middle/src/ty/context.rs | 15 ++++++++++++++- .../rustc_middle/src/ty/context/impl_interner.rs | 12 ++++++++++-- .../src/solve/trait_goals.rs | 14 ++++++++++---- .../src/traits/select/candidate_assembly.rs | 6 +++--- compiler/rustc_type_ir/src/interner.rs | 11 +++++++++++ compiler/rustc_type_ir/src/solve/mod.rs | 5 ++--- 13 files changed, 80 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index bf0d64d78d395..02acd8dc58918 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -402,7 +402,9 @@ fn bounds_from_generic_clauses<'tcx>( ty::ClauseKind::Trait(trait_predicate) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); - if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) { + if !tcx.is_implicit_trait(def_id, ty::IncludeSizedImplicitBounds::No) + && !tcx.is_lang_item(def_id, LangItem::Sized) + { // Do not add that restriction to the list if it is a positive requirement. entry.push(trait_predicate.def_id()); } diff --git a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs index 49f56ddefb0e0..ba1c1197bee92 100644 --- a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs @@ -7,7 +7,8 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{ - self, GenericClauses, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable, TypeVisitor, Upcast, + self, GenericClauses, ImplTraitInTraitData, IncludeSizedImplicitBounds, Ty, TyCtxt, + TypeVisitable, TypeVisitor, Upcast, }; use rustc_span::{DUMMY_SP, Ident, Span, bug, span_bug}; use tracing::{debug, instrument, trace}; @@ -16,7 +17,6 @@ use super::item_bounds::explicit_item_bounds_with_filter; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; use crate::delegation::inherit_clauses_for_delegation_item; -use crate::hir_ty_lowering::bounds::IncludeSizedImplicitBound; use crate::hir_ty_lowering::{ HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, @@ -202,7 +202,7 @@ fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generi self_bounds, ImpliedBoundsContext::TraitDef(def_id), span, - IncludeSizedImplicitBound::Yes, + IncludeSizedImplicitBounds::Yes, ); clauses.extend(bounds); } @@ -235,7 +235,7 @@ fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generi &[], ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, - IncludeSizedImplicitBound::Yes, + IncludeSizedImplicitBounds::Yes, ); trace!(?bounds); clauses.extend(bounds); @@ -685,7 +685,7 @@ pub(super) fn implied_clauses_with_filter<'tcx>( superbounds, ImpliedBoundsContext::TraitDef(trait_def_id), item.span, - IncludeSizedImplicitBound::Yes, + IncludeSizedImplicitBounds::Yes, ); } //`ConstIfConst` is only interested in `[const]` bounds. @@ -981,7 +981,7 @@ impl<'tcx> ItemCtxt<'tcx> { &[], ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, - IncludeSizedImplicitBound::Yes, + IncludeSizedImplicitBounds::Yes, ); } hir::GenericParamKind::Lifetime { .. } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index a805ea0c29e7a..131af48cd52bd 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -2,8 +2,8 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::{ - self, GenericArgs, PredicateProxy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, Upcast, shift_vars, + self, GenericArgs, IncludeSizedImplicitBounds, PredicateProxy, Ty, TyCtxt, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, shift_vars, }; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{Span, bug, span_bug}; @@ -11,7 +11,6 @@ use tracing::{debug, instrument}; use super::ItemCtxt; use super::clauses_of::assert_only_contains_clauses_from; -use crate::hir_ty_lowering::bounds::IncludeSizedImplicitBound; use crate::hir_ty_lowering::{ HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, }; @@ -61,7 +60,7 @@ fn associated_type_bounds<'tcx>( hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, - IncludeSizedImplicitBound::Yes, + IncludeSizedImplicitBounds::Yes, ); // Also collect `where Self::Assoc: Trait` from the parent trait's where clauses. @@ -382,7 +381,7 @@ fn opaque_type_bounds<'tcx>( hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, - IncludeSizedImplicitBound::Yes, + IncludeSizedImplicitBounds::Yes, ); } //`ConstIfConst` is only interested in `[const]` bounds. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index c4b4b8f04427b..88924a9d6a98e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -10,8 +10,8 @@ use rustc_hir::PolyTraitRef; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_middle::ty::{ - self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, - TypeVisitor, Upcast, + self as ty, IncludeSizedImplicitBounds, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, }; use rustc_span::{ErrorGuaranteed, Ident, Span, bug, kw}; use rustc_trait_selection::traits; @@ -137,11 +137,6 @@ fn add_trait_bound<'tcx>( bounds.insert(0, (trait_ref.upcast(tcx), span)); } -pub(crate) enum IncludeSizedImplicitBound { - Yes, - No, -} - impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Adds implicit sizedness, and in the future `Move` and `Forget`, and default trait bounds. pub(crate) fn add_implicit_bounds( @@ -152,7 +147,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { context: ImpliedBoundsContext<'tcx>, span: Span, // Sized is treated slightly more specially than the other implicit bounds. - include_sized: IncludeSizedImplicitBound, + include_sized: IncludeSizedImplicitBounds, ) { // Skip adding any default bounds if `#![rustc_no_implicit_bounds]` if find_attr!(self.tcx(), crate, RustcNoImplicitBounds) { @@ -161,7 +156,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.add_default_traits(bounds, self_ty, hir_bounds, context, span); - if let IncludeSizedImplicitBound::Yes = include_sized { + if let IncludeSizedImplicitBounds::Yes = include_sized { self.add_implicit_sizedness_bounds(bounds, self_ty, hir_bounds, context, span); } } @@ -281,7 +276,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res - && (tcx.is_lang_item(def_id, LangItem::Sized) || tcx.is_default_trait(def_id)) + && (tcx.is_lang_item(def_id, LangItem::Sized) + || tcx.is_implicit_trait(def_id, IncludeSizedImplicitBounds::No)) { return; } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 8d9174a74444a..4a763e5b89316 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -9,8 +9,8 @@ use rustc_hir::{self as hir, HirId}; use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS}; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; use rustc_middle::ty::{ - self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, - TypeVisitableExt, Upcast, + self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, IncludeSizedImplicitBounds, Ty, + TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{ErrorGuaranteed, Span}; @@ -23,7 +23,6 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::diagnostics::DynTraitAssocItemBindingMentionsSelf; -use crate::hir_ty_lowering::bounds::IncludeSizedImplicitBound; use crate::hir_ty_lowering::{ GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, @@ -85,7 +84,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect::>(), ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, - IncludeSizedImplicitBound::No, + IncludeSizedImplicitBounds::No, ); let (mut elaborated_trait_bounds, elaborated_projection_bounds) = diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index fb07f250cf3ce..f15b8c81c51d2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -43,9 +43,9 @@ use rustc_lint_defs::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::{ - self, Const, FnSigKind, GenericArgKind, GenericParamDefKind, LitToConstInput, Ty, TyCtxt, - TypeSuperFoldable, TypeVisitableExt, TypingMode, Unnormalized, Upcast, const_lit_matches_ty, - fold_regions, + self, Const, FnSigKind, GenericArgKind, GenericParamDefKind, IncludeSizedImplicitBounds, + LitToConstInput, Ty, TyCtxt, TypeSuperFoldable, TypeVisitableExt, TypingMode, Unnormalized, + Upcast, const_lit_matches_ty, fold_regions, }; use rustc_session::diagnostics::feature_err; use rustc_span::def_id::{LocalModId, ModId}; @@ -57,7 +57,6 @@ use tracing::{debug, instrument}; use crate::check::check_abi; use crate::check_c_variadic_abi; use crate::diagnostics::{self, BadReturnTypeNotation, NoFieldOnType, NoVariantNamed}; -use crate::hir_ty_lowering::bounds::IncludeSizedImplicitBound; use crate::hir_ty_lowering::errors::{ GenericsArgsErrExtend, eq_ctxt_suggestion_span, prohibit_assoc_item_constraint, }; @@ -3333,7 +3332,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, hir_ty.span, - IncludeSizedImplicitBound::Yes, + IncludeSizedImplicitBounds::Yes, ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); self_ty diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 75552ab759fd5..12b52f4e2801e 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -1,7 +1,7 @@ use rustc_attr_ir::lang_items::LangItem; use rustc_hir as hir; use rustc_lint_defs::{declare_lint, declare_lint_pass}; -use rustc_middle::ty::Unnormalized; +use rustc_middle::ty::{IncludeSizedImplicitBounds, Unnormalized}; use crate::{LateContext, LateLintPass, LintContext}; @@ -51,7 +51,9 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { .map(Unnormalized::skip_norm_wip) .filter_map(|(clause, _)| clause.as_trait_clause()) .filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), LangItem::MetaSized)) - .filter(|pred| !cx.tcx.is_default_trait(pred.def_id())); + .filter(|pred| { + !cx.tcx.is_implicit_trait(pred.def_id(), IncludeSizedImplicitBounds::No) + }); if direct_super_traits_iter.count() > 1 { cx.emit_span_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9f6a6a58bb7b3..116babf53816f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -48,7 +48,8 @@ use rustc_structures::{CrateType, Limit}; use rustc_type_ir::TyKind::*; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::{ - CollectAndApply, PlaceholderType, WithCachedTypeInfo, elaborate, search_graph, + CollectAndApply, IncludeSizedImplicitBounds, PlaceholderType, WithCachedTypeInfo, elaborate, + search_graph, }; use tracing::{debug, instrument}; @@ -955,6 +956,18 @@ impl<'tcx> TyCtxt<'tcx> { self.default_traits().iter().any(|&default_trait| self.is_lang_item(def_id, default_trait)) } + /// Returns true if a trait is an "implicit trait", which is a trait which is added + /// to bounds on generic types automatically by the compiler. + pub fn is_implicit_trait( + self, + def_id: DefId, + including_sized: IncludeSizedImplicitBounds, + ) -> bool { + self.is_default_trait(def_id) + // NOTE: add move and forget here later + || (matches!(including_sized, IncludeSizedImplicitBounds::Yes) && self.is_sizedness_trait(def_id)) + } + pub fn is_sizedness_trait(self, def_id: DefId) -> bool { matches!(self.as_lang_item(def_id), Some(LangItem::Sized | LangItem::MetaSized)) } diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index eb81ea291759b..c62bdcebec389 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -12,8 +12,8 @@ use rustc_span::{DUMMY_SP, Span, Symbol, bug}; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::CanonicalInputData; use rustc_type_ir::{ - BoundVar, CollectAndApply, DebruijnIndex, Interner, RegionVid, TypeFoldable, Unnormalized, - VisitorResult, WithCachedTypeInfo, search_graph, try_visit, + BoundVar, CollectAndApply, DebruijnIndex, IncludeSizedImplicitBounds, Interner, RegionVid, + TypeFoldable, Unnormalized, VisitorResult, WithCachedTypeInfo, search_graph, try_visit, }; use crate::dep_graph::{DepKind, DepNodeIndex}; @@ -527,6 +527,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.is_default_trait(def_id) } + fn is_implicit_trait( + self, + def_id: Self::TraitId, + including_sized: IncludeSizedImplicitBounds, + ) -> bool { + self.is_implicit_trait(def_id, including_sized) + } + fn is_sizedness_trait(self, def_id: DefId) -> bool { self.is_sizedness_trait(def_id) } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 5ae19b2eb6935..685897188a6bf 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -10,9 +10,9 @@ use rustc_type_ir::solve::{ QueryResultOrRerunNonErased, RerunNonErased, RerunReason, RerunResultExt, SizedTraitKind, }; use rustc_type_ir::{ - self as ty, ClausePolarity, ExistentialPredicate, FieldInfo, Interner, MayBeErased, Movability, - Region, TraitClause, TraitRef, TypeVisitableExt as _, TypingMode, Unnormalized, Upcast as _, - elaborate, + self as ty, ClausePolarity, ExistentialPredicate, FieldInfo, IncludeSizedImplicitBounds, + Interner, MayBeErased, Movability, Region, TraitClause, TraitRef, TypeVisitableExt as _, + TypingMode, Unnormalized, Upcast as _, elaborate, }; use tracing::{debug, instrument, trace, warn}; @@ -1413,7 +1413,13 @@ where // Backward compatibility for default auto traits. // Test: ui/traits/default_auto_traits/extern-types.rs - ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(), + ty::Foreign(..) + if self + .cx() + .is_implicit_trait(goal.predicate.def_id(), IncludeSizedImplicitBounds::No) => + { + check_impls() + } // These types cannot be structurally decomposed into constituent // types, and therefore have no built-in auto impl. diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 8a770bea8468b..0d497fe86cf44 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -15,8 +15,8 @@ use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind}; use rustc_infer::traits::{Obligation, PolyTraitObligation, PredicateObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{ - self, ExistentialPredicate, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, - elaborate, + self, ExistentialPredicate, FieldInfo, IncludeSizedImplicitBounds, SizedTraitKind, TraitRef, + Ty, TypeVisitableExt, elaborate, }; use rustc_span::{DUMMY_SP, bug, span_bug}; use tracing::{debug, instrument, trace}; @@ -782,7 +782,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Backward compatibility for default auto traits. // Test: ui/traits/default_auto_traits/extern-types.rs - if self.tcx().is_default_trait(def_id) { + if self.tcx().is_implicit_trait(def_id, IncludeSizedImplicitBounds::No) { check_impls() } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index be0114b8f3af3..4de18651b3520 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -461,6 +461,12 @@ pub trait Interner: fn is_default_trait(self, def_id: Self::TraitId) -> bool; + fn is_implicit_trait( + self, + def_id: Self::TraitId, + including_sized: IncludeSizedImplicitBounds, + ) -> bool; + fn is_sizedness_trait(self, def_id: Self::TraitId) -> bool; fn as_projection_lang_item( @@ -786,3 +792,8 @@ impl search_graph::Cx for I { self.assert_evaluation_is_concurrent() } } + +pub enum IncludeSizedImplicitBounds { + Yes, + No, +} diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 53afc311cc623..e300b94cbc438 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -461,9 +461,8 @@ pub enum CandidatePreferenceMode { impl CandidatePreferenceMode { /// Given `trait_def_id`, which candidate preference mode should be used? pub fn compute(cx: I, trait_id: I::TraitId) -> CandidatePreferenceMode { - let is_sizedness_or_auto_or_default_goal = cx.is_sizedness_trait(trait_id) - || cx.trait_is_auto(trait_id) - || cx.is_default_trait(trait_id); + let is_sizedness_or_auto_or_default_goal = cx.trait_is_auto(trait_id) + || cx.is_implicit_trait(trait_id, ty::IncludeSizedImplicitBounds::Yes); if is_sizedness_or_auto_or_default_goal { CandidatePreferenceMode::Marker } else { From 3ad3b9a06c950478be376e37b2c5ac0ff7f5c7d9 Mon Sep 17 00:00:00 2001 From: zakrad <49591476+zakrad@users.noreply.github.com> Date: Tue, 3 Nov 2026 02:16:25 +0330 Subject: [PATCH 18/31] Add codegen test for unused match arms removed after inlining --- ...inlined-match-unused-arms-removed-74183.rs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/codegen-llvm/issues/inlined-match-unused-arms-removed-74183.rs diff --git a/tests/codegen-llvm/issues/inlined-match-unused-arms-removed-74183.rs b/tests/codegen-llvm/issues/inlined-match-unused-arms-removed-74183.rs new file mode 100644 index 0000000000000..49f2ce3c4f611 --- /dev/null +++ b/tests/codegen-llvm/issues/inlined-match-unused-arms-removed-74183.rs @@ -0,0 +1,43 @@ +//! Regression test for . +//! +//! After inlining `doc_comment_kind`, the match arms for block comments are +//! not needed by `is_line_doc_comment`, so the checks for `*` must be removed. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +enum AttrStyle { + Inner, + Outer, +} + +enum DocCommentKind { + Line, + Block, +} + +#[inline(always)] +const fn doc_comment_kind(s: &str) -> Option<(DocCommentKind, AttrStyle)> { + match s.as_bytes() { + [b'/', b'/', b'/', b'/', ..] => None, + [b'/', b'/', b'/', ..] => Some((DocCommentKind::Line, AttrStyle::Inner)), + [b'/', b'/', b'!', ..] => Some((DocCommentKind::Line, AttrStyle::Outer)), + [b'/', b'*', b'*', b'*', _, ..] => None, + [b'/', b'*', b'*', _, _, ..] => Some((DocCommentKind::Block, AttrStyle::Inner)), + [b'/', b'*', b'!', _, _, ..] => Some((DocCommentKind::Block, AttrStyle::Outer)), + _ => None, + } +} + +// CHECK-LABEL: @is_line_doc_comment +#[no_mangle] +pub const fn is_line_doc_comment(s: &str) -> bool { + // CHECK-NOT: call + // CHECK-NOT: i8 42 + // CHECK: ret i1 + match doc_comment_kind(s) { + Some((DocCommentKind::Line, _)) => true, + _ => false, + } +} From dbbdb56d9ea2a77e944d0789eedac020b334f404 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 3 Nov 2026 00:12:20 +0100 Subject: [PATCH 19/31] make the `no_implicit_prelude` not suppress tool attributes --- compiler/rustc_resolve/src/ident.rs | 2 +- tests/ui/tool-attributes/no_implicit_prelude.rs | 4 ++-- tests/ui/tool-attributes/no_implicit_prelude.stderr | 9 +-------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 6b460195b9b5b..25b1ad5e9d01c 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -161,7 +161,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { use_prelude || module_and_extern_prelude || extern_prelude } - Scope::ToolAttributePrelude => use_prelude, + Scope::ToolAttributePrelude => true, Scope::StdLibPrelude => use_prelude || ns == MacroNS, Scope::BuiltinTypes => true, }; diff --git a/tests/ui/tool-attributes/no_implicit_prelude.rs b/tests/ui/tool-attributes/no_implicit_prelude.rs index 7b06ea30d73f6..29a2372acd707 100644 --- a/tests/ui/tool-attributes/no_implicit_prelude.rs +++ b/tests/ui/tool-attributes/no_implicit_prelude.rs @@ -17,8 +17,8 @@ mod test2 { pub use ::std::derive as format_args; } - #[rustfmt::skip] - //~^ ERROR cannot find module or crate `rustfmt` in this scope + #[my_tool::attr] // Unaffected by the `no_implicit_prelude` attribute + #[rustfmt::skip] // Unaffected by the `no_implicit_prelude` attribute #[clippy::format_args(Debug)] //~^ ERROR attribute macro `clippy::format_args` is ambiguous struct Foo; diff --git a/tests/ui/tool-attributes/no_implicit_prelude.stderr b/tests/ui/tool-attributes/no_implicit_prelude.stderr index 64ef7891c42cb..8aa6407ac3ed0 100644 --- a/tests/ui/tool-attributes/no_implicit_prelude.stderr +++ b/tests/ui/tool-attributes/no_implicit_prelude.stderr @@ -16,12 +16,5 @@ LL | #[clippy::format_args(Debug)] = note: ambiguous because of a name conflict with a tool namespace = note: `clippy` could refer to a tool namespace -error[E0433]: cannot find module or crate `rustfmt` in this scope - --> $DIR/no_implicit_prelude.rs:20:7 - | -LL | #[rustfmt::skip] - | ^^^^^^^ use of unresolved module or unlinked crate `rustfmt` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0433`. From 79520af69f58695f824f54ae76a4b6e594ff32a4 Mon Sep 17 00:00:00 2001 From: Andrew Teylu Date: Thu, 10 Sep 2026 19:02:06 +0100 Subject: [PATCH 20/31] Avoid oscillating line wrapping due to symbol indices A comment against PR 151817 mentioned that the test file added in this PR kept causing "arbitrary" test file changes. This is because one line of the expanded output sits *just* at 78 columns, which is the pretty-printer's margin. Adding or removing a symbol shifts every index after it, and when one of those gains or loses a digit, the wrapping moves. We cannot use `normalize-stdout` as the layout is decided before normalization runs. We fix this by avoiding a strict golden comparison, and instead using a regex to directly test that the expected syntax contexts exist in the expanded output. --- tests/ui/hygiene/unpretty-debug-lifetimes.rs | 11 +++++-- .../hygiene/unpretty-debug-lifetimes.stdout | 33 ------------------- 2 files changed, 9 insertions(+), 35 deletions(-) delete mode 100644 tests/ui/hygiene/unpretty-debug-lifetimes.stdout diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.rs b/tests/ui/hygiene/unpretty-debug-lifetimes.rs index ee8be21b60d01..5f8a20281ab04 100644 --- a/tests/ui/hygiene/unpretty-debug-lifetimes.rs +++ b/tests/ui/hygiene/unpretty-debug-lifetimes.rs @@ -4,8 +4,15 @@ // Regression test for lifetime hygiene annotations in -Zunpretty=expanded,hygiene // Previously, lifetimes were missing the #N syntax context suffix. -// Don't break whenever Symbol numbering changes -//@ normalize-stdout: "\d+#" -> "0#" +// This test deliberately has no `.stdout` snapshot. The hygiene annotations +// embed `Symbol` indices, whose width feeds into the pretty-printer's line +// breaking, so the layout shifts whenever a `Symbol` gains or loses a digit. +// `normalize-stdout` can't help, because the layout is decided before +// normalization runs. Assert the property this test is about instead: the two +// `'a` share their text but carry different syntax contexts. +//@ dont-check-compiler-stdout +//@ check-stdout +//@ regex-error-pattern: f\s*/\*\s*\d+#0\s*\*/<'a\s*/\*\s*\d+#0\s*\*/,\s*'a\s*/\*\s*\d+#1\s*\*/ #![feature(decl_macro)] #![feature(no_core)] diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout deleted file mode 100644 index c75cc7b2179d3..0000000000000 --- a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout +++ /dev/null @@ -1,33 +0,0 @@ -//@ check-pass -//@ compile-flags: -Zunpretty=expanded,hygiene - -// Regression test for lifetime hygiene annotations in -Zunpretty=expanded,hygiene -// Previously, lifetimes were missing the #N syntax context suffix. - -// Don't break whenever Symbol numbering changes -//@ normalize-stdout: "\d+#" -> "0#" - -#![feature /* 0#0 */(decl_macro /* 0#0 */)] -#![feature /* 0#0 */(no_core /* 0#0 */)] -#![no_core /* 0#0 */] - -macro lifetime_hygiene - /* - 0#0 - */ { - ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 - */>) => - { fn /* 0#0 */ $f /* 0#0 */<$a /* 0#0 */, 'a /* 0#0 */>() {} } -} -fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {} - - -/* -Expansions: -crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root -crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "lifetime_hygiene") - -SyntaxContexts: -#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) -#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) -*/ From a72068e1e3549426a9533a56496c9f6441e21588 Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Tue, 3 Nov 2026 01:00:26 +0000 Subject: [PATCH 21/31] Fix rigidity assertion ICE * Add regression test against rigidity assertion * Make non-rigid types equal to one another on error reporting * Bless errors after rigid treatment change * Remove previously useful crash test! * Add suggested comments from code review --- .../src/error_reporting/infer/mod.rs | 9 +++++--- tests/crashes/158773.rs | 16 -------------- ...-impl-missing-assoc-type-ice-152668.stderr | 5 +++++ .../fn_def_opaque_coercion_to_fn_ptr.stderr | 4 ++++ .../issue-62529-3.stderr | 2 -- tests/ui/impl-trait/in-assoc-type.stderr | 4 ++++ .../ui/suggestions/if-then-neeing-semi.stderr | 8 +++---- .../match-prev-arm-needing-semi.stderr | 8 +++---- ...missing-associated-type-restriction.stderr | 4 ++++ ...m-concrete-alias-to-generic.current.stderr | 4 ++++ ...lias-in-same-type-modulo-infer.next.stderr | 16 ++++++++++++++ ...alias-in-same-type-modulo-infer.old.stderr | 16 ++++++++++++++ .../rigid-alias-in-same-type-modulo-infer.rs | 21 +++++++++++++++++++ 13 files changed, 86 insertions(+), 31 deletions(-) delete mode 100644 tests/crashes/158773.rs create mode 100644 tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.next.stderr create mode 100644 tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.old.stderr create mode 100644 tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.rs diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index c0097dc5a60c0..8a0c8f598d125 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -64,8 +64,8 @@ use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt}; use rustc_middle::ty::print::{PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths}; use rustc_middle::ty::{ - self, List, Mutability, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, Unnormalized, + self, IsRigid, List, Mutability, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, Unnormalized, }; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, bug, sym}; use thin_vec::ThinVec; @@ -2468,6 +2468,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or /// FloatVar inference type are compatible with themselves or their concrete types (Int and /// Float types, respectively). When comparing two ADTs, these rules apply recursively. + /// Non-rigid aliases are treated just like TyVar since normalization can be ambiguous here. pub fn same_type_modulo_infer>>(&self, a: T, b: T) -> bool { let (a, b) = self.deeply_resolve_ignoring_regions((a, b)); SameTypeModuloInfer(self).relate(a, b).is_ok() @@ -2517,7 +2518,9 @@ impl<'tcx> TypeRelation> for SameTypeModuloInfer<'_, 'tcx> { ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)), ) | (ty::Infer(ty::InferTy::TyVar(_)), _) - | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), + | (_, ty::Infer(ty::InferTy::TyVar(_))) + | (ty::Alias(IsRigid::No, _), _) + | (_, ty::Alias(IsRigid::No, _)) => Ok(a), (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), _ => relate::structurally_relate_tys(self, a, b), } diff --git a/tests/crashes/158773.rs b/tests/crashes/158773.rs deleted file mode 100644 index 3020ab6206e4b..0000000000000 --- a/tests/crashes/158773.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #158773 -//@ needs-rustc-debug-assertions -//@ compile-flags: -Znext-solver=globally -trait HasLifetime { - type AtLifetime<'a>; -} - -pub struct ExistentialLifetime(S::AtLifetime<'static>); - -impl ExistentialLifetime { - fn new() -> ExistentialLifetime { - ExistentialLifetime(ExistentialLifetime(())) - } -} - -fn main() {} diff --git a/tests/ui/associated-types/dyn-impl-missing-assoc-type-ice-152668.stderr b/tests/ui/associated-types/dyn-impl-missing-assoc-type-ice-152668.stderr index 923972d02b713..f8d9b80ddbf62 100644 --- a/tests/ui/associated-types/dyn-impl-missing-assoc-type-ice-152668.stderr +++ b/tests/ui/associated-types/dyn-impl-missing-assoc-type-ice-152668.stderr @@ -48,6 +48,11 @@ LL | fn sub(self, rhs: Self) -> Self::Output {} found unit type `()` = help: consider constraining the associated type `<(dyn Vector2 + 'static) as Sub>::Output` to `()` or calling a method that returns `<(dyn Vector2 + 'static) as Sub>::Output` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +note: consider returning one of these bindings + --> $DIR/dyn-impl-missing-assoc-type-ice-152668.rs:10:12 + | +LL | fn sub(self, rhs: Self) -> Self::Output {} + | ^^^^ ^^^ error[E0277]: the size for values of type `(dyn Vector2 + 'static)` cannot be known at compilation time --> $DIR/dyn-impl-missing-assoc-type-ice-152668.rs:10:12 diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr index 4a0991d0eb3cb..8015bc15f510c 100644 --- a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr +++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr @@ -11,6 +11,8 @@ LL | x = foo::<()>; | = note: expected fn item `fn(F) -> F {bar::}` found fn item `fn(()) -> () {foo::<()>}` + = note: different fn items have unique types, even if their signatures are the same + = help: consider casting both fn items to fn pointers using `as fn(Alias(No, Alias { kind: Opaque { def_id: DefId(0:8 ~ fn_def_opaque_coercion_to_fn_ptr[7fda]::F::{opaque#0}) }, args: [], .. })) -> Alias(No, Alias { kind: Opaque { def_id: DefId(0:8 ~ fn_def_opaque_coercion_to_fn_ptr[7fda]::F::{opaque#0}) }, args: [], .. })` error[E0308]: mismatched types --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:29:9 @@ -28,6 +30,8 @@ LL | x = foo::; | = note: expected fn item `fn(()) -> () {bar::<()>}` found fn item `fn(I) -> I {foo::}` + = note: different fn items have unique types, even if their signatures are the same + = help: consider casting both fn items to fn pointers using `as fn(())` help: use parentheses to call this function | LL | x = foo::(/* I */); diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr index f9f39e34b658e..7339b9acaea56 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr @@ -6,8 +6,6 @@ LL | call(f, ()); | | | required by a bound introduced by this call | - = note: expected type with signature `for<'a> fn(<_ as ATC<'a>>::Type)` - found type parameter with signature `fn(())` note: required by a bound in `call` --> $DIR/issue-62529-3.rs:9:36 | diff --git a/tests/ui/impl-trait/in-assoc-type.stderr b/tests/ui/impl-trait/in-assoc-type.stderr index 5a8cc40d0276e..1f824bb23f0b7 100644 --- a/tests/ui/impl-trait/in-assoc-type.stderr +++ b/tests/ui/impl-trait/in-assoc-type.stderr @@ -11,6 +11,10 @@ LL | fn foo(&self) -> >::Bar {} | = note: expected opaque type `<() as Foo<()>>::Bar` found unit type `()` +help: consider returning the local binding `self` + | +LL | fn foo(&self) -> >::Bar { self } + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/if-then-neeing-semi.stderr b/tests/ui/suggestions/if-then-neeing-semi.stderr index 0556d6c50b1ce..105e2756fb1db 100644 --- a/tests/ui/suggestions/if-then-neeing-semi.stderr +++ b/tests/ui/suggestions/if-then-neeing-semi.stderr @@ -52,12 +52,10 @@ help: consider `await`ing on the `Future` | LL | async_dummy2().await | ++++++ -help: consider removing this semicolon and boxing the expressions +help: consider removing this semicolon | -LL ~ Box::new(async_dummy()) -LL | -LL | } else { -LL ~ Box::new(async_dummy2()) +LL - async_dummy(); +LL + async_dummy() | error[E0308]: `if` and `else` have incompatible types diff --git a/tests/ui/suggestions/match-prev-arm-needing-semi.stderr b/tests/ui/suggestions/match-prev-arm-needing-semi.stderr index f70f6a1e1570b..c468433fd4421 100644 --- a/tests/ui/suggestions/match-prev-arm-needing-semi.stderr +++ b/tests/ui/suggestions/match-prev-arm-needing-semi.stderr @@ -52,12 +52,10 @@ help: consider `await`ing on the `Future` | LL | false => async_dummy2().await, | ++++++ -help: consider removing this semicolon and boxing the expressions +help: consider removing this semicolon | -LL ~ Box::new(async_dummy()) -LL | -LL | } -LL ~ false => Box::new(async_dummy2()), +LL - async_dummy(); +LL + async_dummy() | error[E0308]: `match` arms have incompatible types diff --git a/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr b/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr index 03249bd39a8c7..196eafa5bba68 100644 --- a/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr +++ b/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr @@ -11,6 +11,10 @@ help: a method is available that returns `>::A` | LL | fn func(&self) -> Self::A; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func` +help: consider returning the local binding `self` + | +LL | fn funq(&self) -> Self::A { self } + | ++++ error[E0308]: mismatched types --> $DIR/trait-with-missing-associated-type-restriction.rs:14:9 diff --git a/tests/ui/traits/next-solver/normalization-shadowing/is-global-norm-concrete-alias-to-generic.current.stderr b/tests/ui/traits/next-solver/normalization-shadowing/is-global-norm-concrete-alias-to-generic.current.stderr index 0ad8e3444600b..972a42d0f6621 100644 --- a/tests/ui/traits/next-solver/normalization-shadowing/is-global-norm-concrete-alias-to-generic.current.stderr +++ b/tests/ui/traits/next-solver/normalization-shadowing/is-global-norm-concrete-alias-to-generic.current.stderr @@ -13,6 +13,10 @@ LL | x = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html = note: the associated type `<(*const T,) as Id>::This` is defined as `(*const T,)` in the implementation, but the where-bound `(*const T,)` shadows this definition see issue #152409 for more information +help: use a trailing comma to create a tuple with one element + | +LL | (x,) + | + ++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.next.stderr b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.next.stderr new file mode 100644 index 0000000000000..fe8ef6aff748d --- /dev/null +++ b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.next.stderr @@ -0,0 +1,16 @@ +error[E0271]: type mismatch resolving `::AtLifetime<'static> == ExistentialLifetime<_>` + --> $DIR/rigid-alias-in-same-type-modulo-infer.rs:16:9 + | +LL | ExistentialLifetime(ExistentialLifetime(())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `ExistentialLifetime<_>`, found associated type + | + = note: expected struct `ExistentialLifetime<_>` + found associated type `::AtLifetime<'static>` +help: consider constraining the associated type `::AtLifetime<'static>` to `ExistentialLifetime<_>` + | +LL | impl = ExistentialLifetime<_>>> ExistentialLifetime { + | ++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.old.stderr b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.old.stderr new file mode 100644 index 0000000000000..fe8ef6aff748d --- /dev/null +++ b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.old.stderr @@ -0,0 +1,16 @@ +error[E0271]: type mismatch resolving `::AtLifetime<'static> == ExistentialLifetime<_>` + --> $DIR/rigid-alias-in-same-type-modulo-infer.rs:16:9 + | +LL | ExistentialLifetime(ExistentialLifetime(())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `ExistentialLifetime<_>`, found associated type + | + = note: expected struct `ExistentialLifetime<_>` + found associated type `::AtLifetime<'static>` +help: consider constraining the associated type `::AtLifetime<'static>` to `ExistentialLifetime<_>` + | +LL | impl = ExistentialLifetime<_>>> ExistentialLifetime { + | ++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.rs b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.rs new file mode 100644 index 0000000000000..c083234411fe8 --- /dev/null +++ b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.rs @@ -0,0 +1,21 @@ +//! Regression test for . +// Avoids ICE on SameTypeModuloInfer assertion rigidity of two types. +// +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait HasLifetime { + type AtLifetime<'a>; +} + +pub struct ExistentialLifetime(S::AtLifetime<'static>); + +impl ExistentialLifetime { + fn new() -> ExistentialLifetime { + ExistentialLifetime(ExistentialLifetime(())) + //~^ ERROR: type mismatch resolving `::AtLifetime<'static> == ExistentialLifetime<_>` [E0271] + } +} + +fn main() {} From dedfa67f3baca095348c4c6225a4a980b231cefc Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 26 Oct 2026 17:20:48 +0100 Subject: [PATCH 22/31] Make `ExpectedLint` more general --- compiler/rustc_attr_parsing/src/attributes/lint.rs | 6 +++--- compiler/rustc_attr_parsing/src/diagnostics.rs | 8 ++++---- .../deduplicate-diagnostics.deduplicate.stderr | 2 +- .../deduplicate-diagnostics.duplicate.stderr | 6 +++--- tests/ui/diagnostic-flags/deduplicate-diagnostics.rs | 6 +++--- tests/ui/lint/lint-attribute-literals.rs | 12 ++++++------ tests/ui/lint/lint-attribute-literals.stderr | 12 ++++++------ 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/lint.rs b/compiler/rustc_attr_parsing/src/attributes/lint.rs index db57b23f6296a..bf5450651cee8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint.rs @@ -100,15 +100,15 @@ impl LintParser { } } MetaItemOrLitParser::Lit(lit) => { - cx.emit_err(diagnostics::BadAttributeLit { + cx.emit_err(diagnostics::MalformedLintAttributeInput { span: item.span(), help: if lit.kind.is_str() { - diagnostics::BadAttributeLitHelp::StrLit { + diagnostics::MalformedLintAttributeInputHelp::StrLit { sym: lit.symbol, kind: kind.sym(), } } else { - diagnostics::BadAttributeLitHelp::Other { kind: kind.sym() } + diagnostics::MalformedLintAttributeInputHelp::Other { kind: kind.sym() } }, }); } diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index b5bfbc9e3dc3b..0c68090615944 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -2153,17 +2153,17 @@ pub(crate) enum MalformedAttributeKind { } #[derive(Diagnostic)] -#[diag("expected a lint, found literal")] -pub(crate) struct BadAttributeLit { +#[diag("expected a lint")] +pub(crate) struct MalformedLintAttributeInput { #[primary_span] #[label("not the name of a lint")] pub span: Span, #[subdiagnostic] - pub help: BadAttributeLitHelp, + pub help: MalformedLintAttributeInputHelp, } #[derive(Subdiagnostic)] -pub(crate) enum BadAttributeLitHelp { +pub(crate) enum MalformedLintAttributeInputHelp { #[help("try using `#[{$kind}({$sym})]`")] StrLit { sym: Symbol, kind: Symbol }, #[help("for example, write `#[{$kind}(dead_code)]` for `dead_code`")] diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr index 114c37188a9ef..8cbfed641d789 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr @@ -1,4 +1,4 @@ -error: expected a lint, found literal +error: expected a lint --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr index 66d0d94c0e815..6123e0d1ddbf1 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr @@ -1,4 +1,4 @@ -error: expected a lint, found literal +error: expected a lint --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] @@ -20,7 +20,7 @@ LL | #[derive(Unresolved)] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: expected a lint --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] @@ -29,7 +29,7 @@ LL | #[deny("literal")] = help: try using `#[deny(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: expected a lint --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs index b070ec0f7dd93..fb9b8c765bd19 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs @@ -7,7 +7,7 @@ //[duplicate]~| ERROR cannot find derive macro `Unresolved` in this scope struct S; -#[deny("literal")] //~ ERROR expected a lint, found literal - //[duplicate]~| ERROR expected a lint, found literal - //[duplicate]~| ERROR expected a lint, found literal +#[deny("literal")] //~ ERROR expected a lint + //[duplicate]~| ERROR expected a lint + //[duplicate]~| ERROR expected a lint fn main() {} diff --git a/tests/ui/lint/lint-attribute-literals.rs b/tests/ui/lint/lint-attribute-literals.rs index 34a4757adec3c..0140e64356d06 100644 --- a/tests/ui/lint/lint-attribute-literals.rs +++ b/tests/ui/lint/lint-attribute-literals.rs @@ -1,11 +1,11 @@ // Checks that lint attributes with literals have an explanatory error #[allow("literal")] -//~^ ERROR expected a lint, found literal -//~| ERROR expected a lint, found literal -//~| ERROR expected a lint, found literal +//~^ ERROR expected a lint +//~| ERROR expected a lint +//~| ERROR expected a lint #[deny(1.0)] -//~^ ERROR expected a lint, found literal -//~| ERROR expected a lint, found literal -//~| ERROR expected a lint, found literal +//~^ ERROR expected a lint +//~| ERROR expected a lint +//~| ERROR expected a lint fn main() {} diff --git a/tests/ui/lint/lint-attribute-literals.stderr b/tests/ui/lint/lint-attribute-literals.stderr index 7434f8b5c5d4b..7cad3ac9c7a33 100644 --- a/tests/ui/lint/lint-attribute-literals.stderr +++ b/tests/ui/lint/lint-attribute-literals.stderr @@ -1,4 +1,4 @@ -error: expected a lint, found literal +error: expected a lint --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -6,7 +6,7 @@ LL | #[allow("literal")] | = help: try using `#[allow(literal)]` -error: expected a lint, found literal +error: expected a lint --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] @@ -14,7 +14,7 @@ LL | #[deny(1.0)] | = help: for example, write `#[deny(dead_code)]` for `dead_code` -error: expected a lint, found literal +error: expected a lint --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -23,7 +23,7 @@ LL | #[allow("literal")] = help: try using `#[allow(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: expected a lint --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] @@ -32,7 +32,7 @@ LL | #[deny(1.0)] = help: for example, write `#[deny(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: expected a lint --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -41,7 +41,7 @@ LL | #[allow("literal")] = help: try using `#[allow(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: expected a lint --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] From 58c0988aa3bc0f3c3cb3a85dc6444c5ac2e9c8d5 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 27 Oct 2026 10:23:16 +0100 Subject: [PATCH 23/31] Use `ExpectedLint` in more places --- .../rustc_attr_parsing/src/attributes/lint.rs | 12 +++---- .../rustc_attr_parsing/src/diagnostics.rs | 2 -- .../src/error_codes/E0452.md | 2 +- .../unsafe/proc-unsafe-attributes.rs | 6 ++-- .../unsafe/proc-unsafe-attributes.stderr | 19 ++++++----- tests/ui/error-codes/E0452.rs | 12 +++---- tests/ui/error-codes/E0452.stderr | 32 ++++++++++------- tests/ui/lint/lint-malformed.rs | 12 +++---- tests/ui/lint/lint-malformed.stderr | 34 +++++++++++-------- tests/ui/lint/pre-expansion-parsing.rs | 2 +- tests/ui/lint/pre-expansion-parsing.stderr | 7 ++-- tests/ui/lint/reasons-erroneous.rs | 12 +++---- tests/ui/lint/reasons-erroneous.stderr | 18 ++++++---- 13 files changed, 95 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/lint.rs b/compiler/rustc_attr_parsing/src/attributes/lint.rs index bf5450651cee8..272675dc44a64 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint.rs @@ -8,6 +8,7 @@ use thin_vec::ThinVec; use crate::attributes::{AcceptMapping, AttributeParser, AttributeStability}; use crate::context::{AcceptContext, ExpectStringLiteral, FinalizeContext}; +use crate::diagnostics::BadAttributeLitHelp; use crate::parser::{ArgParser, MetaItemOrLitParser}; use crate::target_checking::AllowedTargets; use crate::target_checking::Policy::{Allow, Warn}; @@ -36,9 +37,10 @@ impl LintParser { let p = parsers.last()?.meta_item()?; let nv = p.args().as_name_value()?; if !p.path().word_is(sym::reason) { - cx.emit_err(diagnostics::MalformedAttribute { + // FIXME: We should recommend `reason` here + cx.emit_err(diagnostics::ExpectedLint { span: p.span(), - kind: diagnostics::MalformedAttributeKind::BadAttributeArgument(p.span()), + help: BadAttributeLitHelp::Other { kind: kind.sym() }, }); } else { parsers = &parsers[..(parsers.len() - 1)]; @@ -90,11 +92,9 @@ impl LintParser { nv.expect_string_literal(cx); } ArgParser::NameValue(_) | ArgParser::List(_) => { - cx.emit_err(diagnostics::MalformedAttribute { + cx.emit_err(diagnostics::ExpectedLint { span: p.span(), - kind: diagnostics::MalformedAttributeKind::BadAttributeArgument( - item.span(), - ), + help: BadAttributeLitHelp::Other { kind: kind.sym() }, }); } } diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 0c68090615944..14484fe2daaea 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -2146,8 +2146,6 @@ pub(crate) struct MalformedAttribute { #[derive(Subdiagnostic)] pub(crate) enum MalformedAttributeKind { - #[label("bad attribute argument")] - BadAttributeArgument(#[primary_span] Span), #[label("reason in lint attribute must come last")] ReasonMustComeLast(#[primary_span] Span), } diff --git a/compiler/rustc_error_codes/src/error_codes/E0452.md b/compiler/rustc_error_codes/src/error_codes/E0452.md index 429813a7cdd4e..581687e86974a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0452.md +++ b/compiler/rustc_error_codes/src/error_codes/E0452.md @@ -3,7 +3,7 @@ An invalid lint attribute has been given. Erroneous code example: ```compile_fail,E0452 -#![allow(foo = "")] // error: malformed lint attribute +#![allow(reason = "", foo)] // error: malformed lint attribute ``` Lint attributes only accept a list of identifiers (where each identifier is a diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs index 33324685a84f4..f0212e4744264 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -33,9 +33,9 @@ pub fn e() {} //~| ERROR: expected identifier, found keyword `unsafe` //~| ERROR: expected identifier, found keyword `unsafe` //~| ERROR: expected identifier, found keyword `unsafe` -//~| ERROR: malformed lint attribute input -//~| ERROR: malformed lint attribute input -//~| ERROR: malformed lint attribute input +//~| ERROR: expected a lint +//~| ERROR: expected a lint +//~| ERROR: expected a lint pub fn f() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 04e8c4d2dd453..d6ae4d6e2d823 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -25,11 +25,13 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[allow(dead_code)]` for `dead_code` error: the `proc_macro` attribute is only usable with crates of the `proc-macro` crate type --> $DIR/proc-unsafe-attributes.rs:1:10 @@ -85,12 +87,13 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `proc_macro` is not an unsafe attribute @@ -176,15 +179,15 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 21 previous errors -Some errors have detailed explanations: E0452, E0565. -For more information about an error, try `rustc --explain E0452`. +For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/error-codes/E0452.rs b/tests/ui/error-codes/E0452.rs index 4e5a6c9301467..518d8bd619ef7 100644 --- a/tests/ui/error-codes/E0452.rs +++ b/tests/ui/error-codes/E0452.rs @@ -1,8 +1,8 @@ -#![allow(foo = "")] //~ ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 +#![allow(foo = "")] //~ ERROR expected a lint + //~| ERROR expected a lint + //~| ERROR expected a lint + //~| ERROR expected a lint + //~| ERROR expected a lint + //~| ERROR expected a lint fn main() { } diff --git a/tests/ui/error-codes/E0452.stderr b/tests/ui/error-codes/E0452.stderr index c20429e363dda..99b625379a464 100644 --- a/tests/ui/error-codes/E0452.stderr +++ b/tests/ui/error-codes/E0452.stderr @@ -1,49 +1,55 @@ -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint + | + = help: for example, write `#[allow(dead_code)]` for `dead_code` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/lint/lint-malformed.rs b/tests/ui/lint/lint-malformed.rs index cf5570753d85d..eb034e4064a6e 100644 --- a/tests/ui/lint/lint-malformed.rs +++ b/tests/ui/lint/lint-malformed.rs @@ -1,8 +1,8 @@ #![deny = "foo"] //~ ERROR malformed `deny` attribute input -#![allow(bar = "baz")] //~ ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute +#![allow(bar = "baz")] //~ ERROR expected a lint + //~| ERROR expected a lint + //~| ERROR expected a lint + //~| ERROR expected a lint + //~| ERROR expected a lint + //~| ERROR expected a lint fn main() { } diff --git a/tests/ui/lint/lint-malformed.stderr b/tests/ui/lint/lint-malformed.stderr index 7be928de86985..024213eca84d3 100644 --- a/tests/ui/lint/lint-malformed.stderr +++ b/tests/ui/lint/lint-malformed.stderr @@ -1,31 +1,36 @@ -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[allow(dead_code)]` for `dead_code` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0539]: malformed `deny` attribute input @@ -49,23 +54,24 @@ LL - #![deny = "foo"] LL + #![deny(lint1, lint2, lint3, reason = "...")] | -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 7 previous errors -Some errors have detailed explanations: E0452, E0539. -For more information about an error, try `rustc --explain E0452`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/lint/pre-expansion-parsing.rs b/tests/ui/lint/pre-expansion-parsing.rs index 7cfc57ff4e903..b5be9a5000ea4 100644 --- a/tests/ui/lint/pre-expansion-parsing.rs +++ b/tests/ui/lint/pre-expansion-parsing.rs @@ -3,7 +3,7 @@ #[expect] // OK #[expect[wut]] // OK #[expect(expect)] // OK -#[expect(expect(expect))] //~ ERROR malformed lint attribute input +#[expect(expect(expect))] //~ ERROR expected a lint #[deny(({!}))] // OK #[expect[helix::]] // OK #[cfg(false)] diff --git a/tests/ui/lint/pre-expansion-parsing.stderr b/tests/ui/lint/pre-expansion-parsing.stderr index ecc8b7017d92d..92473bc29286d 100644 --- a/tests/ui/lint/pre-expansion-parsing.stderr +++ b/tests/ui/lint/pre-expansion-parsing.stderr @@ -1,9 +1,10 @@ -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/pre-expansion-parsing.rs:6:10 | LL | #[expect(expect(expect))] - | ^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[expect(dead_code)]` for `dead_code` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs index 38ad00da64cd7..32de70d33ff89 100644 --- a/tests/ui/lint/reasons-erroneous.rs +++ b/tests/ui/lint/reasons-erroneous.rs @@ -8,14 +8,14 @@ //~^ ERROR malformed `warn` attribute input //~| NOTE expected a normal string literal, not a byte string literal #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] -//~^ ERROR malformed lint attribute -//~| NOTE bad attribute argument +//~^ ERROR expected a lint +//~| NOTE not the name of a lint #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] -//~^ ERROR malformed lint attribute -//~| NOTE bad attribute argument +//~^ ERROR expected a lint +//~| NOTE not the name of a lint #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] -//~^ ERROR malformed lint attribute -//~| NOTE bad attribute argument +//~^ ERROR expected a lint +//~| NOTE not the name of a lint #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] //~^ ERROR malformed lint attribute //~| NOTE reason in lint attribute must come last diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr index d771366d6168e..4261d4a21c438 100644 --- a/tests/ui/lint/reasons-erroneous.stderr +++ b/tests/ui/lint/reasons-erroneous.stderr @@ -29,23 +29,29 @@ LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condem | = note: expected a normal string literal, not a byte string literal -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/reasons-erroneous.rs:10:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[warn(dead_code)]` for `dead_code` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/reasons-erroneous.rs:13:22 | LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[warn(dead_code)]` for `dead_code` -error[E0452]: malformed lint attribute input +error: expected a lint --> $DIR/reasons-erroneous.rs:16:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[warn(dead_code)]` for `dead_code` error[E0452]: malformed lint attribute input --> $DIR/reasons-erroneous.rs:19:44 From cdc3205c47cc3a9cff3315c7e1ddd752e3743112 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 3 Nov 2026 09:09:02 +0100 Subject: [PATCH 24/31] Make diagnostic title consistent with other attributes --- .../rustc_attr_parsing/src/attributes/lint.rs | 21 ++++++++++++------- .../rustc_attr_parsing/src/diagnostics.rs | 3 ++- .../unsafe/proc-unsafe-attributes.rs | 6 +++--- .../unsafe/proc-unsafe-attributes.stderr | 6 +++--- ...deduplicate-diagnostics.deduplicate.stderr | 2 +- .../deduplicate-diagnostics.duplicate.stderr | 6 +++--- .../deduplicate-diagnostics.rs | 6 +++--- tests/ui/error-codes/E0452.rs | 12 +++++------ tests/ui/error-codes/E0452.stderr | 12 +++++------ tests/ui/lint/lint-attribute-literals.rs | 12 +++++------ tests/ui/lint/lint-attribute-literals.stderr | 12 +++++------ tests/ui/lint/lint-malformed.rs | 12 +++++------ tests/ui/lint/lint-malformed.stderr | 12 +++++------ tests/ui/lint/pre-expansion-parsing.rs | 2 +- tests/ui/lint/pre-expansion-parsing.stderr | 2 +- tests/ui/lint/reasons-erroneous.rs | 6 +++--- tests/ui/lint/reasons-erroneous.stderr | 6 +++--- 17 files changed, 72 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/lint.rs b/compiler/rustc_attr_parsing/src/attributes/lint.rs index 272675dc44a64..999673db0d179 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint.rs @@ -8,7 +8,7 @@ use thin_vec::ThinVec; use crate::attributes::{AcceptMapping, AttributeParser, AttributeStability}; use crate::context::{AcceptContext, ExpectStringLiteral, FinalizeContext}; -use crate::diagnostics::BadAttributeLitHelp; +use crate::diagnostics::{MalformedLintAttributeInput, MalformedLintAttributeInputHelp}; use crate::parser::{ArgParser, MetaItemOrLitParser}; use crate::target_checking::AllowedTargets; use crate::target_checking::Policy::{Allow, Warn}; @@ -38,9 +38,10 @@ impl LintParser { let nv = p.args().as_name_value()?; if !p.path().word_is(sym::reason) { // FIXME: We should recommend `reason` here - cx.emit_err(diagnostics::ExpectedLint { + cx.emit_err(MalformedLintAttributeInput { span: p.span(), - help: BadAttributeLitHelp::Other { kind: kind.sym() }, + help: MalformedLintAttributeInputHelp::Other { kind: kind.sym() }, + kind: kind.sym(), }); } else { parsers = &parsers[..(parsers.len() - 1)]; @@ -92,24 +93,28 @@ impl LintParser { nv.expect_string_literal(cx); } ArgParser::NameValue(_) | ArgParser::List(_) => { - cx.emit_err(diagnostics::ExpectedLint { + cx.emit_err(MalformedLintAttributeInput { span: p.span(), - help: BadAttributeLitHelp::Other { kind: kind.sym() }, + help: MalformedLintAttributeInputHelp::Other { + kind: kind.sym(), + }, + kind: kind.sym(), }); } } } MetaItemOrLitParser::Lit(lit) => { - cx.emit_err(diagnostics::MalformedLintAttributeInput { + cx.emit_err(MalformedLintAttributeInput { span: item.span(), help: if lit.kind.is_str() { - diagnostics::MalformedLintAttributeInputHelp::StrLit { + MalformedLintAttributeInputHelp::StrLit { sym: lit.symbol, kind: kind.sym(), } } else { - diagnostics::MalformedLintAttributeInputHelp::Other { kind: kind.sym() } + MalformedLintAttributeInputHelp::Other { kind: kind.sym() } }, + kind: kind.sym(), }); } } diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 14484fe2daaea..59dcd7e1535f8 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -2151,11 +2151,12 @@ pub(crate) enum MalformedAttributeKind { } #[derive(Diagnostic)] -#[diag("expected a lint")] +#[diag("malformed `{$kind}` attribute input")] pub(crate) struct MalformedLintAttributeInput { #[primary_span] #[label("not the name of a lint")] pub span: Span, + pub kind: Symbol, #[subdiagnostic] pub help: MalformedLintAttributeInputHelp, } diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs index f0212e4744264..f84f0bcbd34d4 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -33,9 +33,9 @@ pub fn e() {} //~| ERROR: expected identifier, found keyword `unsafe` //~| ERROR: expected identifier, found keyword `unsafe` //~| ERROR: expected identifier, found keyword `unsafe` -//~| ERROR: expected a lint -//~| ERROR: expected a lint -//~| ERROR: expected a lint +//~| ERROR: malformed +//~| ERROR: malformed +//~| ERROR: malformed pub fn f() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index d6ae4d6e2d823..cd73156eff453 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -25,7 +25,7 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error: expected a lint +error: malformed `allow` attribute input --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] @@ -87,7 +87,7 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error: expected a lint +error: malformed `allow` attribute input --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] @@ -179,7 +179,7 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error: expected a lint +error: malformed `allow` attribute input --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr index 8cbfed641d789..ff82a449d83ba 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr @@ -1,4 +1,4 @@ -error: expected a lint +error: malformed `deny` attribute input --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr index 6123e0d1ddbf1..3c7ce1686080c 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr @@ -1,4 +1,4 @@ -error: expected a lint +error: malformed `deny` attribute input --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] @@ -20,7 +20,7 @@ LL | #[derive(Unresolved)] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `deny` attribute input --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] @@ -29,7 +29,7 @@ LL | #[deny("literal")] = help: try using `#[deny(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `deny` attribute input --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs index fb9b8c765bd19..437ed20acbeb9 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs @@ -7,7 +7,7 @@ //[duplicate]~| ERROR cannot find derive macro `Unresolved` in this scope struct S; -#[deny("literal")] //~ ERROR expected a lint - //[duplicate]~| ERROR expected a lint - //[duplicate]~| ERROR expected a lint +#[deny("literal")] //~ ERROR malformed + //[duplicate]~| ERROR malformed + //[duplicate]~| ERROR malformed fn main() {} diff --git a/tests/ui/error-codes/E0452.rs b/tests/ui/error-codes/E0452.rs index 518d8bd619ef7..6a0437df7b14e 100644 --- a/tests/ui/error-codes/E0452.rs +++ b/tests/ui/error-codes/E0452.rs @@ -1,8 +1,8 @@ -#![allow(foo = "")] //~ ERROR expected a lint - //~| ERROR expected a lint - //~| ERROR expected a lint - //~| ERROR expected a lint - //~| ERROR expected a lint - //~| ERROR expected a lint +#![allow(foo = "")] //~ ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed fn main() { } diff --git a/tests/ui/error-codes/E0452.stderr b/tests/ui/error-codes/E0452.stderr index 99b625379a464..c34d9a2a01b28 100644 --- a/tests/ui/error-codes/E0452.stderr +++ b/tests/ui/error-codes/E0452.stderr @@ -1,4 +1,4 @@ -error: expected a lint +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] @@ -6,7 +6,7 @@ LL | #![allow(foo = "")] | = help: for example, write `#[allow(dead_code)]` for `dead_code` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] @@ -15,7 +15,7 @@ LL | #![allow(foo = "")] = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] @@ -24,7 +24,7 @@ LL | #![allow(foo = "")] = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] @@ -33,7 +33,7 @@ LL | #![allow(foo = "")] = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] @@ -42,7 +42,7 @@ LL | #![allow(foo = "")] = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] diff --git a/tests/ui/lint/lint-attribute-literals.rs b/tests/ui/lint/lint-attribute-literals.rs index 0140e64356d06..7adec75210108 100644 --- a/tests/ui/lint/lint-attribute-literals.rs +++ b/tests/ui/lint/lint-attribute-literals.rs @@ -1,11 +1,11 @@ // Checks that lint attributes with literals have an explanatory error #[allow("literal")] -//~^ ERROR expected a lint -//~| ERROR expected a lint -//~| ERROR expected a lint +//~^ ERROR malformed +//~| ERROR malformed +//~| ERROR malformed #[deny(1.0)] -//~^ ERROR expected a lint -//~| ERROR expected a lint -//~| ERROR expected a lint +//~^ ERROR malformed +//~| ERROR malformed +//~| ERROR malformed fn main() {} diff --git a/tests/ui/lint/lint-attribute-literals.stderr b/tests/ui/lint/lint-attribute-literals.stderr index 7cad3ac9c7a33..b06eac094f66d 100644 --- a/tests/ui/lint/lint-attribute-literals.stderr +++ b/tests/ui/lint/lint-attribute-literals.stderr @@ -1,4 +1,4 @@ -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -6,7 +6,7 @@ LL | #[allow("literal")] | = help: try using `#[allow(literal)]` -error: expected a lint +error: malformed `deny` attribute input --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] @@ -14,7 +14,7 @@ LL | #[deny(1.0)] | = help: for example, write `#[deny(dead_code)]` for `dead_code` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -23,7 +23,7 @@ LL | #[allow("literal")] = help: try using `#[allow(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `deny` attribute input --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] @@ -32,7 +32,7 @@ LL | #[deny(1.0)] = help: for example, write `#[deny(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -41,7 +41,7 @@ LL | #[allow("literal")] = help: try using `#[allow(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `deny` attribute input --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] diff --git a/tests/ui/lint/lint-malformed.rs b/tests/ui/lint/lint-malformed.rs index eb034e4064a6e..5fd92170363f0 100644 --- a/tests/ui/lint/lint-malformed.rs +++ b/tests/ui/lint/lint-malformed.rs @@ -1,8 +1,8 @@ #![deny = "foo"] //~ ERROR malformed `deny` attribute input -#![allow(bar = "baz")] //~ ERROR expected a lint - //~| ERROR expected a lint - //~| ERROR expected a lint - //~| ERROR expected a lint - //~| ERROR expected a lint - //~| ERROR expected a lint +#![allow(bar = "baz")] //~ ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed fn main() { } diff --git a/tests/ui/lint/lint-malformed.stderr b/tests/ui/lint/lint-malformed.stderr index 024213eca84d3..ceb7fe105bcd3 100644 --- a/tests/ui/lint/lint-malformed.stderr +++ b/tests/ui/lint/lint-malformed.stderr @@ -1,4 +1,4 @@ -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] @@ -6,7 +6,7 @@ LL | #![allow(bar = "baz")] | = help: for example, write `#[allow(dead_code)]` for `dead_code` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] @@ -15,7 +15,7 @@ LL | #![allow(bar = "baz")] = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] @@ -24,7 +24,7 @@ LL | #![allow(bar = "baz")] = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] @@ -54,7 +54,7 @@ LL - #![deny = "foo"] LL + #![deny(lint1, lint2, lint3, reason = "...")] | -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] @@ -63,7 +63,7 @@ LL | #![allow(bar = "baz")] = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] diff --git a/tests/ui/lint/pre-expansion-parsing.rs b/tests/ui/lint/pre-expansion-parsing.rs index b5be9a5000ea4..11a55beb77d65 100644 --- a/tests/ui/lint/pre-expansion-parsing.rs +++ b/tests/ui/lint/pre-expansion-parsing.rs @@ -3,7 +3,7 @@ #[expect] // OK #[expect[wut]] // OK #[expect(expect)] // OK -#[expect(expect(expect))] //~ ERROR expected a lint +#[expect(expect(expect))] //~ ERROR malformed #[deny(({!}))] // OK #[expect[helix::]] // OK #[cfg(false)] diff --git a/tests/ui/lint/pre-expansion-parsing.stderr b/tests/ui/lint/pre-expansion-parsing.stderr index 92473bc29286d..651fd5d4c8f38 100644 --- a/tests/ui/lint/pre-expansion-parsing.stderr +++ b/tests/ui/lint/pre-expansion-parsing.stderr @@ -1,4 +1,4 @@ -error: expected a lint +error: malformed `expect` attribute input --> $DIR/pre-expansion-parsing.rs:6:10 | LL | #[expect(expect(expect))] diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs index 32de70d33ff89..4a0c458209ee6 100644 --- a/tests/ui/lint/reasons-erroneous.rs +++ b/tests/ui/lint/reasons-erroneous.rs @@ -8,13 +8,13 @@ //~^ ERROR malformed `warn` attribute input //~| NOTE expected a normal string literal, not a byte string literal #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] -//~^ ERROR expected a lint +//~^ ERROR malformed //~| NOTE not the name of a lint #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] -//~^ ERROR expected a lint +//~^ ERROR malformed //~| NOTE not the name of a lint #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] -//~^ ERROR expected a lint +//~^ ERROR malformed //~| NOTE not the name of a lint #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] //~^ ERROR malformed lint attribute diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr index 4261d4a21c438..3c52a0d8e25b4 100644 --- a/tests/ui/lint/reasons-erroneous.stderr +++ b/tests/ui/lint/reasons-erroneous.stderr @@ -29,7 +29,7 @@ LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condem | = note: expected a normal string literal, not a byte string literal -error: expected a lint +error: malformed `warn` attribute input --> $DIR/reasons-erroneous.rs:10:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] @@ -37,7 +37,7 @@ LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides thei | = help: for example, write `#[warn(dead_code)]` for `dead_code` -error: expected a lint +error: malformed `warn` attribute input --> $DIR/reasons-erroneous.rs:13:22 | LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] @@ -45,7 +45,7 @@ LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the s | = help: for example, write `#[warn(dead_code)]` for `dead_code` -error: expected a lint +error: malformed `warn` attribute input --> $DIR/reasons-erroneous.rs:16:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] From 760fc7bf25b3e2f9b0fa2c101410f54c0a4742bf Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 3 Nov 2026 12:16:33 +0300 Subject: [PATCH 25/31] Insert probing adjustments before args check adjustments --- compiler/rustc_hir_typeck/src/callee.rs | 12 ++++- .../adjustments-broken-mir-ice-165171.rs | 40 ++++++++++++++++ .../adjustments-broken-mir-ice-165171.stderr | 48 +++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 tests/ui/delegation/adjustments-broken-mir-ice-165171.rs create mode 100644 tests/ui/delegation/adjustments-broken-mir-ice-165171.stderr diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 98f74e6402b8a..260aca7fe621c 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -784,9 +784,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (prev_type, method_adjustments) = prev_types.remove(&arg.hir_id).expect("must be in a map"); - // Remove any added adjustments for arg expression during `do_check` and replace them with ours. + // Insert adjustments that were obtained when we were probing before adjustments + // that were potentially obtained during arguments check. As when checking arguments we + // change the real arg type with an adjusted one, so new adjustments are created for already + // adjusted type. See #165171, in short if we have `self.0` which is `u8` and the expected input + // is `&dyn Trait`, we would have: + // `adjustments` == [Deref(Builtin) -> u8, Borrow(Ref(Not)) -> &u8, Pointer(Unsize) -> &dyn original_ice::Trait], + // `method_adjustments` == [Borrow(Ref(Not)) -> &u8] + // This makes sense only if `method_adjustments` are inserted before `adjustments`. + // FIXME(fn_delegation): maybe useless adjustments can be optimized away here let adjustments = adjustments.entry(arg.hir_id).or_default(); - *adjustments = method_adjustments; + adjustments.splice(0..0, method_adjustments); // Restore original first provided arg type. results.node_types_mut().insert(arg.hir_id, prev_type); diff --git a/tests/ui/delegation/adjustments-broken-mir-ice-165171.rs b/tests/ui/delegation/adjustments-broken-mir-ice-165171.rs new file mode 100644 index 0000000000000..38485596a931b --- /dev/null +++ b/tests/ui/delegation/adjustments-broken-mir-ice-165171.rs @@ -0,0 +1,40 @@ +#![feature(fn_delegation)] + +mod original_ice { + trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 0 } + fn baz(&self) -> u8 { 0 } + } + + impl Trait for u8 {} + impl Trait for Rc> {} + + struct S(u8); + + use std::rc::Rc; + impl Trait for S { + reuse ::foo { &self.0 } + reuse ::bar { self.0 } + reuse > as Trait>::baz { self.0 } + //~^ ERROR: mismatched types [E0308] + } +} + +mod test_2 { + trait Trait { + fn foo(&self) -> u8 { 0 } + } + + impl Trait for () {} + impl Trait for u8 {} + + struct S(u8); + + impl Trait for S { + reuse <() as Trait>::foo { &self.0 } + //~^ ERROR: mismatched types [E0308] + } +} + +fn main() {} diff --git a/tests/ui/delegation/adjustments-broken-mir-ice-165171.stderr b/tests/ui/delegation/adjustments-broken-mir-ice-165171.stderr new file mode 100644 index 0000000000000..1d10d37ea2624 --- /dev/null +++ b/tests/ui/delegation/adjustments-broken-mir-ice-165171.stderr @@ -0,0 +1,48 @@ +error[E0308]: mismatched types + --> $DIR/adjustments-broken-mir-ice-165171.rs:19:52 + | +LL | reuse > as Trait>::baz { self.0 } + | --- ^^^^^^ expected `&Rc>`, found `&u8` + | | + | arguments to this function are incorrect + | + = note: expected reference `&Rc>` + found reference `&u8` +note: method defined here + --> $DIR/adjustments-broken-mir-ice-165171.rs:7:12 + | +LL | trait Trait { +... +LL | fn baz(&self) -> u8 { 0 } + | ^^^ ----- +note: method provided through this `impl` + --> $DIR/adjustments-broken-mir-ice-165171.rs:11:5 + | +LL | impl Trait for Rc> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/adjustments-broken-mir-ice-165171.rs:35:36 + | +LL | reuse <() as Trait>::foo { &self.0 } + | --- ^^^^^^^ expected `&()`, found `&u8` + | | + | arguments to this function are incorrect + | + = note: expected reference `&()` + found reference `&u8` +note: method defined here + --> $DIR/adjustments-broken-mir-ice-165171.rs:26:12 + | +LL | trait Trait { +LL | fn foo(&self) -> u8 { 0 } + | ^^^ ----- +note: method provided through this `impl` + --> $DIR/adjustments-broken-mir-ice-165171.rs:29:5 + | +LL | impl Trait for () {} + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 86f5fdbe4a6d4a2a1552126ec558e632f2da6552 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 1 Oct 2026 22:25:00 +0200 Subject: [PATCH 26/31] Implement lint helper namespace --- compiler/rustc_attr_ir/src/data_structures.rs | 6 +- .../rustc_attr_ir/src/encode_cross_crate.rs | 4 +- .../src/attributes/lint_helpers.rs | 8 +- compiler/rustc_attr_parsing/src/context.rs | 2 +- .../rustc_attr_parsing/src/diagnostics.rs | 8 + compiler/rustc_attr_parsing/src/interface.rs | 19 +- compiler/rustc_feature/src/builtin_attrs.rs | 1 - compiler/rustc_lint/src/dangling.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_span/src/symbol.rs | 3 +- library/alloc/src/boxed.rs | 6 +- library/alloc/src/lib.rs | 7 +- library/alloc/src/vec/mod.rs | 6 +- library/core/src/cell.rs | 8 +- .../core/src/cell/covariant_unsafe_cell.rs | 2 +- library/core/src/ffi/c_str.rs | 2 +- library/core/src/lib.rs | 5 + library/core/src/mem/maybe_uninit.rs | 4 +- library/core/src/slice/mod.rs | 4 +- library/core/src/str/mod.rs | 4 +- tests/ui/README.md | 4 + tests/ui/attributes/malformed-attrs.rs | 3 +- tests/ui/attributes/malformed-attrs.stderr | 168 +++++++++--------- .../ui/lint_helper_namespace/feature_gates.rs | 8 + .../feature_gates.stderr | 12 ++ .../registered_invalid.rs | 6 + .../registered_invalid.stderr | 8 + .../resolve_as_macro.registered.stderr | 11 ++ .../lint_helper_namespace/resolve_as_macro.rs | 14 ++ .../resolve_as_macro.with.stderr | 11 ++ .../ui/lint_helper_namespace/unregistered.rs | 4 + .../lint_helper_namespace/unregistered.stderr | 9 + 32 files changed, 245 insertions(+), 116 deletions(-) create mode 100644 tests/ui/lint_helper_namespace/feature_gates.rs create mode 100644 tests/ui/lint_helper_namespace/feature_gates.stderr create mode 100644 tests/ui/lint_helper_namespace/registered_invalid.rs create mode 100644 tests/ui/lint_helper_namespace/registered_invalid.stderr create mode 100644 tests/ui/lint_helper_namespace/resolve_as_macro.registered.stderr create mode 100644 tests/ui/lint_helper_namespace/resolve_as_macro.rs create mode 100644 tests/ui/lint_helper_namespace/resolve_as_macro.with.stderr create mode 100644 tests/ui/lint_helper_namespace/unregistered.rs create mode 100644 tests/ui/lint_helper_namespace/unregistered.stderr diff --git a/compiler/rustc_attr_ir/src/data_structures.rs b/compiler/rustc_attr_ir/src/data_structures.rs index ce33e5cba69cc..c3ce6144aa633 100644 --- a/compiler/rustc_attr_ir/src/data_structures.rs +++ b/compiler/rustc_attr_ir/src/data_structures.rs @@ -986,6 +986,9 @@ pub enum AttributeKind { /// Represents `#[linkage]`. Linkage(Linkage, Span), + /// Represents `#[lint::as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). + LintAsPtr, + /// Represents `#[allow]`, `#[warn]`, `#[deny]`, `#[forbid]`, and `#[expect]`. LintCheck(ThinVec), @@ -1199,9 +1202,6 @@ pub enum AttributeKind { /// Represents `#[rustc_allow_lifetime_dependent_specialization]`. RustcAllowLifetimeDependentSpecialization, - /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). - RustcAsPtr, - /// Represents `#[rustc_assert_variance]`. RustcAssertVariance { span: Span, diff --git a/compiler/rustc_attr_ir/src/encode_cross_crate.rs b/compiler/rustc_attr_ir/src/encode_cross_crate.rs index c3019b53822bd..3d50923c6ae5a 100644 --- a/compiler/rustc_attr_ir/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_ir/src/encode_cross_crate.rs @@ -58,6 +58,7 @@ impl AttributeKind { LinkOrdinal { .. } => No, LinkSection { .. } => Yes, // Needed for rustdoc Linkage(..) => No, + LintAsPtr => Yes, LintCheck(..) => No, LoopMatch(..) => No, MacroEscape => No, @@ -109,7 +110,6 @@ impl AttributeKind { RustcAllowConstFnUnstable(..) => No, RustcAllowIncoherentImpl(..) => No, RustcAllowLifetimeDependentSpecialization => No, - RustcAsPtr => Yes, RustcAssertVariance { .. } => No, RustcAutodiff(..) => Yes, RustcBodyStability { .. } => No, @@ -276,6 +276,7 @@ impl AttributeKind { | crate::Linkage::WeakAny | crate::Linkage::WeakODR => true, }, + LintAsPtr => false, LintCheck(_) => false, LoopMatch(..) => false, MacroEscape => false, @@ -327,7 +328,6 @@ impl AttributeKind { RustcAllowConstFnUnstable(..) => false, RustcAllowIncoherentImpl(..) => false, RustcAllowLifetimeDependentSpecialization => false, - RustcAsPtr => false, RustcAssertVariance { .. } => false, RustcAutodiff(..) => false, RustcBodyStability { .. } => false, diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 10e42ced30705..6c1c91eadfb53 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -4,9 +4,9 @@ use rustc_feature::AttributeStability; use super::prelude::*; use crate::diagnostics::RustcPubTransparent; -pub(crate) struct RustcAsPtrParser; -impl NoArgsAttributeParser for RustcAsPtrParser { - const PATH: &[Symbol] = &[sym::rustc_as_ptr]; +pub(crate) struct LintAsPtrParser; +impl NoArgsAttributeParser for LintAsPtrParser { + const PATH: &[Symbol] = &[sym::lint, sym::as_ptr]; const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), @@ -15,7 +15,7 @@ impl NoArgsAttributeParser for RustcAsPtrParser { Allow(Target::Method(MethodKind::TraitImpl)), ]); const STABILITY: AttributeStability = unstable!(rustc_attrs); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAsPtr; + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::LintAsPtr; } pub(crate) struct RustcPubTransparentParser; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8f1c3d1a71f24..8886cef7225e5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -274,6 +274,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -299,7 +300,6 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 4301148075516..6bda279f5d932 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -2241,3 +2241,11 @@ pub(crate) struct DocKeywordAttributeNotAnonConst { pub span: Span, pub attr_name: Symbol, } + +#[derive(Diagnostic)] +#[diag("the `lint::{$unknown}` attribute is not recognized")] +pub(crate) struct UnknownLintHelper { + #[primary_span] + pub span: Span, + pub unknown: Symbol, +} diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 369c095ea7e6f..cc38ec87a3be6 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -24,7 +24,7 @@ use crate::diagnostics::ParsedDescription; use crate::generated::GeneratedAttrState; use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser}; use crate::synthetic::SyntheticAttrState; -use crate::{AttributeTemplate, ShouldEmit}; +use crate::{AttributeTemplate, ShouldEmit, diagnostics}; pub struct EmitAttribute( pub Box< @@ -446,6 +446,23 @@ impl<'sess> AttributeParser<'sess> { } } else if let [sym::diagnostic, _unknown, ..] = &*parts { self.unknown_diagnostic_attr(&n.item.path.segments[1], &mut emit_lint); + } else if let [sym::lint, unknown, ..] = &*parts { + // Avoid cascading errors. If the `lint` tool has not been registered, + // we could be here in the `#[lint::attribute_macro] not found` case, + // which recovers with a `NonMacroAttr` res. + if let Some(tools) = self.attr_tools + && tools.iter().any(|i| i.name == sym::lint) + { + self.emit_err(diagnostics::UnknownLintHelper { + span: n.item.span, + unknown: *unknown, + }); + } else { + self.dcx().span_delayed_bug( + n.item.span, + "encountered `lint` tool attribute but error not reported", + ); + } } else { let attr = AttrItem { path: attr_path.clone(), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index ef508881e9d4c..8ab1601b2b62d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -350,7 +350,6 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ // Internal attributes, Misc: // ========================================================================== sym::lang, - sym::rustc_as_ptr, sym::rustc_should_not_be_called_on_const_items, sym::rustc_pass_by_value, sym::rustc_never_returns_null_ptr, diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index dbe20dbef3c87..8cf1cb926b786 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -269,7 +269,7 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { && let ty = cx.typeck_results().expr_ty(receiver) && owns_allocation(cx.tcx, ty) && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && find_attr!(cx.tcx, fn_id, RustcAsPtr) + && find_attr!(cx.tcx, fn_id, LintAsPtr) { cx.tcx.emit_node_span_lint( DANGLING_POINTERS_FROM_TEMPORARIES, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d34aa0e773b1e..0c5a5a6baf836 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -257,6 +257,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::LinkName { .. } => (), AttributeKind::LinkOrdinal { .. } => (), AttributeKind::LinkSection { .. } => (), + AttributeKind::LintAsPtr => (), AttributeKind::LoopMatch(..) => (), AttributeKind::MacroEscape => (), AttributeKind::MacroExport { .. } => (), @@ -300,7 +301,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllowConstFnUnstable(..) => (), AttributeKind::RustcAllowIncoherentImpl(..) => (), AttributeKind::RustcAllowLifetimeDependentSpecialization => (), - AttributeKind::RustcAsPtr => (), AttributeKind::RustcAutodiff(..) => (), AttributeKind::RustcBodyStability { .. } => (), AttributeKind::RustcBuiltinMacro { .. } => (), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6f078fef4892b..80a6b14d92523 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -449,6 +449,7 @@ symbols! { arm_target_feature, array, as_dash_needed: "as-needed", + as_ptr, as_ref, asm, asm_cfg, @@ -1249,6 +1250,7 @@ symbols! { linker_messages, linkonce, linkonce_odr, + lint, lint_reasons, literal, little, big, @@ -1801,7 +1803,6 @@ symbols! { rustc_allow_lifetime_dependent_specialization, rustc_allowed_through_unstable_modules, rustc_always_gca, - rustc_as_ptr, rustc_assert_variance, rustc_attrs, rustc_autodiff, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 96643d6417f27..b20b15026ab5d 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1914,7 +1914,7 @@ impl Box { #[must_use] #[stable(feature = "box_as_ptr", since = "1.98.0")] #[rustc_never_returns_null_ptr] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline] pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -1963,7 +1963,7 @@ impl Box { #[must_use] #[stable(feature = "box_as_ptr", since = "1.98.0")] #[rustc_never_returns_null_ptr] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline] pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -2006,7 +2006,7 @@ impl Box { /// [`as_non_null`]: Self::as_non_null #[must_use] #[unstable(feature = "box_as_non_null", issue = "157345")] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline] pub fn as_non_null(b: &mut Self) -> NonNull { // SAFETY: `Box` is guaranteed to be non-null. diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 92fa5fdb1f1ec..02fc394ec2e45 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -162,6 +162,7 @@ #![feature(ptr_metadata)] #![feature(random)] #![feature(raw_os_error_ty)] +#![feature(register_tool)] #![feature(rev_into_inner)] #![feature(seek_stream_len)] #![feature(set_ptr_value)] @@ -219,7 +220,11 @@ #![feature(with_negative_coherence)] #![rustc_preserve_ub_checks] // tidy-alphabetical-end -// + +// tidy-alphabetical-start +#![register_tool(lint)] +// tidy-alphabetical-end + // Rustdoc features: #![feature(doc_cfg)] #![feature(doc_notable_trait)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 19e431fe00604..0fb94f2fa7fa2 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1882,7 +1882,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_never_returns_null_ptr] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline] pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through @@ -1967,7 +1967,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_never_returns_null_ptr] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through @@ -2034,7 +2034,7 @@ impl Vec { /// [didn't allocate]: self#memory-layout #[unstable(feature = "vec_as_non_null", issue = "157843")] #[rustc_const_unstable(feature = "vec_as_non_null", issue = "157843")] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline] pub const fn as_non_null(&mut self) -> NonNull { self.buf.non_null() diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index e51bc200089b6..1deb700cd2a72 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -600,7 +600,7 @@ impl Cell { #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")] - #[rustc_as_ptr] + #[lint::as_ptr] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() @@ -1291,7 +1291,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] - #[rustc_as_ptr] + #[lint::as_ptr] #[rustc_never_returns_null_ptr] #[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")] pub const fn as_ptr(&self) -> *mut T { @@ -2430,7 +2430,7 @@ impl UnsafeCell { #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] - #[rustc_as_ptr] + #[lint::as_ptr] #[rustc_never_returns_null_ptr] #[rustc_should_not_be_called_on_const_items] pub const fn get(&self) -> *mut T { @@ -2637,7 +2637,7 @@ impl SyncUnsafeCell { /// when casting to `&mut T`, and ensure that there are no mutations /// or mutable aliases going on when casting to `&T` #[inline] - #[rustc_as_ptr] + #[lint::as_ptr] #[rustc_never_returns_null_ptr] #[rustc_should_not_be_called_on_const_items] pub const fn get(&self) -> *mut T { diff --git a/library/core/src/cell/covariant_unsafe_cell.rs b/library/core/src/cell/covariant_unsafe_cell.rs index bd38fb303d914..ac3f265ce5763 100644 --- a/library/core/src/cell/covariant_unsafe_cell.rs +++ b/library/core/src/cell/covariant_unsafe_cell.rs @@ -83,7 +83,7 @@ impl CovariantUnsafeCell { /// let ptr: NonNull = uc.get(); /// ``` #[inline(always)] - #[rustc_as_ptr] + #[lint::as_ptr] #[rustc_should_not_be_called_on_const_items] #[unstable(feature = "covariant_unsafe_cell", issue = "159735")] #[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 8dcabacd2c7fd..a8347f9dc3182 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -486,7 +486,7 @@ impl CStr { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] - #[rustc_as_ptr] + #[lint::as_ptr] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 36a19f89e58cd..a3dca4c6fdea3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -148,6 +148,7 @@ #![feature(pattern_types)] #![feature(pin_macro_internals)] #![feature(prelude_import)] +#![feature(register_tool)] #![feature(repr_simd)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] @@ -184,6 +185,10 @@ #![feature(x86_amx_intrinsics)] // tidy-alphabetical-end +// tidy-alphabetical-start +#![register_tool(lint)] +// tidy-alphabetical-end + // tidy-alphabetical-start #![expect(clippy::partialeq_ne_impl, reason = "we need to implement ne for a lot of core types")] // tidy-alphabetical-end diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 98afd345eec28..f1815dee1d689 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -612,7 +612,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline(always)] pub const fn as_ptr(&self) -> *const T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. @@ -654,7 +654,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_mut_ptr", since = "1.83.0")] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 7caf8a8046dfd..4c563497ace66 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -724,7 +724,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -755,7 +755,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_never_returns_null_ptr] - #[rustc_as_ptr] + #[lint::as_ptr] #[inline(always)] #[must_use] #[rustc_no_writable] diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 68257bf931926..c5c3cf0a206a1 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -585,7 +585,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] - #[rustc_as_ptr] + #[lint::as_ptr] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -603,7 +603,7 @@ impl str { #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")] #[rustc_never_returns_null_ptr] - #[rustc_as_ptr] + #[lint::as_ptr] #[must_use] #[inline(always)] #[rustc_no_writable] diff --git a/tests/ui/README.md b/tests/ui/README.md index ded2ef7496303..cdebbea240dbf 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -848,6 +848,10 @@ See: - [Lints | The rustc book](https://doc.rust-lang.org/rustc/lints/index.html) - [Lint reasons | Reference](https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-reasons) +## `tests/ui/lint_helper_namespace/` + +Tests for lint helper attributes such as `#[lint::as_ptr]`. + ## `tests/ui/liveness/` Tests exercising analysis for unused variables, unreachable statements, functions which are supposed to return a value but do not, as well as values moved elsewhere before they could be used by a function. diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index e29e9786647b4..6b66f05c03888 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -46,8 +46,9 @@ //~| ERROR attribute cannot be used on #[repr] //~^ ERROR malformed -#[rustc_as_ptr = 5] +#[lint::as_ptr = 5] //~^ ERROR malformed +//~| ERROR cannot find module or crate `lint` in this scope #[inline = 5] //~^ ERROR valid forms for the attribute are //~| WARN this was previously accepted by the compiler diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 8791659658906..b982facaf2abb 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -1,5 +1,5 @@ error[E0539]: malformed `cfg` attribute input - --> $DIR/malformed-attrs.rs:108:3 + --> $DIR/malformed-attrs.rs:109:3 | LL | #[cfg] | ^^^ expected this to be a list @@ -11,7 +11,7 @@ LL | #[cfg(predicate)] | +++++++++++ error[E0539]: malformed `cfg_attr` attribute input - --> $DIR/malformed-attrs.rs:110:3 + --> $DIR/malformed-attrs.rs:111:3 | LL | #[cfg_attr] | ^^^^^^^^ expected this to be a list @@ -23,29 +23,35 @@ LL | #[cfg_attr(predicate, attr1, attr2, ...)] | ++++++++++++++++++++++++++++++ error[E0463]: can't find crate for `wloop` - --> $DIR/malformed-attrs.rs:214:1 + --> $DIR/malformed-attrs.rs:215:1 | LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate error: the `proc_macro` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:105:3 + --> $DIR/malformed-attrs.rs:106:3 | LL | #[proc_macro = 18] | ^^^^^^^^^^ error: the `proc_macro_attribute` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:122:3 + --> $DIR/malformed-attrs.rs:123:3 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^ error: the `proc_macro_derive` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:129:3 + --> $DIR/malformed-attrs.rs:130:3 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^ +error[E0433]: cannot find module or crate `lint` in this scope + --> $DIR/malformed-attrs.rs:49:3 + | +LL | #[lint::as_ptr = 5] + | ^^^^ use of unresolved module or unlinked crate `lint` + error[E0539]: malformed `windows_subsystem` attribute input --> $DIR/malformed-attrs.rs:25:4 | @@ -145,22 +151,22 @@ LL | #[repr] | = note: for more information, visit -error[E0565]: malformed `rustc_as_ptr` attribute input +error[E0565]: malformed `lint::as_ptr` attribute input --> $DIR/malformed-attrs.rs:49:3 | -LL | #[rustc_as_ptr = 5] +LL | #[lint::as_ptr = 5] | ^^^^^^^^^^^^^--- | | | didn't expect any arguments here | help: must be of the form | -LL - #[rustc_as_ptr = 5] -LL + #[rustc_as_ptr] +LL - #[lint::as_ptr = 5] +LL + #[lint::as_ptr] | error[E0539]: malformed `rustc_align` attribute input - --> $DIR/malformed-attrs.rs:54:3 + --> $DIR/malformed-attrs.rs:55:3 | LL | #[rustc_align] | ^^^^^^^^^^^ expected this to be a list @@ -171,7 +177,7 @@ LL | #[rustc_align()] | ++++++++++++++++++++++ error[E0539]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:56:3 + --> $DIR/malformed-attrs.rs:57:3 | LL | #[optimize] | ^^^^^^^^ expected this to be a list @@ -186,7 +192,7 @@ LL | #[optimize(speed)] | +++++++ error[E0805]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:58:3 + --> $DIR/malformed-attrs.rs:59:3 | LL | #[optimize(none, none)] | ^^^^^^^^------------ @@ -206,7 +212,7 @@ LL + #[optimize(speed)] | error[E0805]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:60:3 + --> $DIR/malformed-attrs.rs:61:3 | LL | #[optimize(none, speed)] | ^^^^^^^^------------- @@ -226,7 +232,7 @@ LL + #[optimize(speed)] | error[E0565]: malformed `cold` attribute input - --> $DIR/malformed-attrs.rs:62:3 + --> $DIR/malformed-attrs.rs:63:3 | LL | #[cold = 1] | ^^^^^--- @@ -240,7 +246,7 @@ LL + #[cold] | error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:64:3 + --> $DIR/malformed-attrs.rs:65:3 | LL | #[must_use()] | ^^^^^^^^-- @@ -258,7 +264,7 @@ LL + #[must_use = "reason"] | error[E0565]: malformed `no_mangle` attribute input - --> $DIR/malformed-attrs.rs:66:3 + --> $DIR/malformed-attrs.rs:67:3 | LL | #[no_mangle = 1] | ^^^^^^^^^^--- @@ -272,7 +278,7 @@ LL + #[no_mangle] | error[E0565]: malformed `naked` attribute input - --> $DIR/malformed-attrs.rs:68:3 + --> $DIR/malformed-attrs.rs:69:3 | LL | #[unsafe(naked())] | ^^^^^^^^^^^^--^ @@ -286,7 +292,7 @@ LL + #[unsafe(naked)] | error[E0565]: malformed `track_caller` attribute input - --> $DIR/malformed-attrs.rs:70:3 + --> $DIR/malformed-attrs.rs:71:3 | LL | #[track_caller()] | ^^^^^^^^^^^^-- @@ -300,7 +306,7 @@ LL + #[track_caller] | error[E0539]: malformed `export_name` attribute input - --> $DIR/malformed-attrs.rs:72:3 + --> $DIR/malformed-attrs.rs:73:3 | LL | #[export_name()] | ^^^^^^^^^^^^^ @@ -312,7 +318,7 @@ LL + #[export_name = "name"] | error[E0805]: malformed `used` attribute input - --> $DIR/malformed-attrs.rs:74:3 + --> $DIR/malformed-attrs.rs:75:3 | LL | #[used()] | ^^^^-- @@ -330,7 +336,7 @@ LL | #[used(linker)] | ++++++ error: the `used` attribute cannot be used on functions - --> $DIR/malformed-attrs.rs:74:3 + --> $DIR/malformed-attrs.rs:75:3 | LL | #[used()] | ^^^^ @@ -340,7 +346,7 @@ LL | fn test() { = help: the `used` attribute can only be applied to statics error[E0539]: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:77:3 + --> $DIR/malformed-attrs.rs:78:3 | LL | #[crate_name] | ^^^^^^^^^^ @@ -351,7 +357,7 @@ LL | #[crate_name = "name"] | ++++++++ error[E0539]: malformed `target_feature` attribute input - --> $DIR/malformed-attrs.rs:80:3 + --> $DIR/malformed-attrs.rs:81:3 | LL | #[target_feature] | ^^^^^^^^^^^^^^ expected this to be a list @@ -362,7 +368,7 @@ LL | #[target_feature(enable = "feat1, feat2")] | +++++++++++++++++++++++++ error[E0565]: malformed `export_stable` attribute input - --> $DIR/malformed-attrs.rs:82:3 + --> $DIR/malformed-attrs.rs:83:3 | LL | #[export_stable = 1] | ^^^^^^^^^^^^^^--- @@ -376,7 +382,7 @@ LL + #[export_stable] | error[E0539]: malformed `link` attribute input - --> $DIR/malformed-attrs.rs:84:3 + --> $DIR/malformed-attrs.rs:85:3 | LL | #[link] | ^^^^ expected this to be a list @@ -384,7 +390,7 @@ LL | #[link] = note: for more information, visit error[E0539]: malformed `link_name` attribute input - --> $DIR/malformed-attrs.rs:88:3 + --> $DIR/malformed-attrs.rs:89:3 | LL | #[link_name] | ^^^^^^^^^ @@ -396,7 +402,7 @@ LL | #[link_name = "name"] | ++++++++ error[E0539]: malformed `link_section` attribute input - --> $DIR/malformed-attrs.rs:92:3 + --> $DIR/malformed-attrs.rs:93:3 | LL | #[link_section] | ^^^^^^^^^^^^ @@ -408,7 +414,7 @@ LL | #[link_section = "name"] | ++++++++ error[E0539]: malformed `coverage` attribute input - --> $DIR/malformed-attrs.rs:94:3 + --> $DIR/malformed-attrs.rs:95:3 | LL | #[coverage] | ^^^^^^^^ expected this to be a list @@ -421,13 +427,13 @@ LL | #[coverage(on)] | ++++ error[E0539]: malformed `sanitize` attribute input - --> $DIR/malformed-attrs.rs:96:3 + --> $DIR/malformed-attrs.rs:97:3 | LL | #[sanitize] | ^^^^^^^^ expected this to be a list error[E0565]: malformed `no_implicit_prelude` attribute input - --> $DIR/malformed-attrs.rs:101:3 + --> $DIR/malformed-attrs.rs:102:3 | LL | #[no_implicit_prelude = 23] | ^^^^^^^^^^^^^^^^^^^^---- @@ -441,7 +447,7 @@ LL + #[no_implicit_prelude] | error[E0565]: malformed `proc_macro` attribute input - --> $DIR/malformed-attrs.rs:105:3 + --> $DIR/malformed-attrs.rs:106:3 | LL | #[proc_macro = 18] | ^^^^^^^^^^^---- @@ -455,7 +461,7 @@ LL + #[proc_macro] | error[E0539]: malformed `instruction_set` attribute input - --> $DIR/malformed-attrs.rs:112:3 + --> $DIR/malformed-attrs.rs:113:3 | LL | #[instruction_set] | ^^^^^^^^^^^^^^^ expected this to be a list @@ -467,7 +473,7 @@ LL | #[instruction_set(set)] | +++++ error[E0539]: malformed `patchable_function_entry` attribute input - --> $DIR/malformed-attrs.rs:114:3 + --> $DIR/malformed-attrs.rs:115:3 | LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^ expected this to be a list @@ -490,7 +496,7 @@ LL | | } | |_- not a `const fn` error[E0565]: malformed `coroutine` attribute input - --> $DIR/malformed-attrs.rs:117:7 + --> $DIR/malformed-attrs.rs:118:7 | LL | #[coroutine = 63] || {} | ^^^^^^^^^^---- @@ -504,7 +510,7 @@ LL + #[coroutine] || {} | error[E0565]: malformed `proc_macro_attribute` attribute input - --> $DIR/malformed-attrs.rs:122:3 + --> $DIR/malformed-attrs.rs:123:3 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^---- @@ -518,7 +524,7 @@ LL + #[proc_macro_attribute] | error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:125:3 + --> $DIR/malformed-attrs.rs:126:3 | LL | #[must_use = 1] | ^^^^^^^^^^^- @@ -536,7 +542,7 @@ LL + #[must_use = "reason"] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/malformed-attrs.rs:129:3 + --> $DIR/malformed-attrs.rs:130:3 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^ expected this to be a list @@ -550,7 +556,7 @@ LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | ++++++++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `must_not_suspend` attribute input - --> $DIR/malformed-attrs.rs:134:3 + --> $DIR/malformed-attrs.rs:135:3 | LL | #[must_not_suspend()] | ^^^^^^^^^^^^^^^^-- @@ -566,7 +572,7 @@ LL | #[must_not_suspend(count)] | +++++ error[E0539]: malformed `cfi_encoding` attribute input - --> $DIR/malformed-attrs.rs:136:3 + --> $DIR/malformed-attrs.rs:137:3 | LL | #[cfi_encoding = ""] | ^^^^^^^^^^^^^^^-- @@ -579,7 +585,7 @@ LL | #[cfi_encoding = "encoding"] | ++++++++ error[E0565]: malformed `marker` attribute input - --> $DIR/malformed-attrs.rs:155:3 + --> $DIR/malformed-attrs.rs:156:3 | LL | #[marker = 3] | ^^^^^^^--- @@ -593,7 +599,7 @@ LL + #[marker] | error[E0565]: malformed `fundamental` attribute input - --> $DIR/malformed-attrs.rs:157:3 + --> $DIR/malformed-attrs.rs:158:3 | LL | #[fundamental()] | ^^^^^^^^^^^-- @@ -607,7 +613,7 @@ LL + #[fundamental] | error[E0565]: malformed `ffi_pure` attribute input - --> $DIR/malformed-attrs.rs:165:7 + --> $DIR/malformed-attrs.rs:166:7 | LL | #[unsafe(ffi_pure = 1)] | ^^^^^^^^^^^^^^^^---^ @@ -621,7 +627,7 @@ LL + #[unsafe(ffi_pure)] | error[E0539]: malformed `link_ordinal` attribute input - --> $DIR/malformed-attrs.rs:167:7 + --> $DIR/malformed-attrs.rs:168:7 | LL | #[link_ordinal] | ^^^^^^^^^^^^ expected this to be a list @@ -633,7 +639,7 @@ LL | #[link_ordinal(ordinal)] | +++++++++ error[E0565]: malformed `ffi_const` attribute input - --> $DIR/malformed-attrs.rs:171:7 + --> $DIR/malformed-attrs.rs:172:7 | LL | #[unsafe(ffi_const = 1)] | ^^^^^^^^^^^^^^^^^---^ @@ -647,13 +653,13 @@ LL + #[unsafe(ffi_const)] | error[E0539]: malformed `linkage` attribute input - --> $DIR/malformed-attrs.rs:173:7 + --> $DIR/malformed-attrs.rs:174:7 | LL | #[linkage] | ^^^^^^^ expected this to be of the form `linkage = "..."` error[E0539]: malformed `allow` attribute input - --> $DIR/malformed-attrs.rs:178:3 + --> $DIR/malformed-attrs.rs:179:3 | LL | #[allow] | ^^^^^ expected this to be a list @@ -669,7 +675,7 @@ LL | #[allow(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `expect` attribute input - --> $DIR/malformed-attrs.rs:180:3 + --> $DIR/malformed-attrs.rs:181:3 | LL | #[expect] | ^^^^^^ expected this to be a list @@ -685,7 +691,7 @@ LL | #[expect(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `warn` attribute input - --> $DIR/malformed-attrs.rs:182:3 + --> $DIR/malformed-attrs.rs:183:3 | LL | #[warn] | ^^^^ expected this to be a list @@ -701,7 +707,7 @@ LL | #[warn(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `deny` attribute input - --> $DIR/malformed-attrs.rs:184:3 + --> $DIR/malformed-attrs.rs:185:3 | LL | #[deny] | ^^^^ expected this to be a list @@ -717,7 +723,7 @@ LL | #[deny(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `forbid` attribute input - --> $DIR/malformed-attrs.rs:186:3 + --> $DIR/malformed-attrs.rs:187:3 | LL | #[forbid] | ^^^^^^ expected this to be a list @@ -733,7 +739,7 @@ LL | #[forbid(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `debugger_visualizer` attribute input - --> $DIR/malformed-attrs.rs:188:3 + --> $DIR/malformed-attrs.rs:189:3 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^ expected this to be a list @@ -745,7 +751,7 @@ LL | #[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")] | ++++++++++++++++++++++++++++++++++++++++++++++ error[E0565]: malformed `automatically_derived` attribute input - --> $DIR/malformed-attrs.rs:190:3 + --> $DIR/malformed-attrs.rs:191:3 | LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^^---- @@ -759,7 +765,7 @@ LL + #[automatically_derived] | error[E0565]: malformed `non_exhaustive` attribute input - --> $DIR/malformed-attrs.rs:198:3 + --> $DIR/malformed-attrs.rs:199:3 | LL | #[non_exhaustive = 1] | ^^^^^^^^^^^^^^^--- @@ -773,7 +779,7 @@ LL + #[non_exhaustive] | error[E0565]: malformed `thread_local` attribute input - --> $DIR/malformed-attrs.rs:204:3 + --> $DIR/malformed-attrs.rs:205:3 | LL | #[thread_local()] | ^^^^^^^^^^^^-- @@ -787,7 +793,7 @@ LL + #[thread_local] | error[E0565]: malformed `no_link` attribute input - --> $DIR/malformed-attrs.rs:208:3 + --> $DIR/malformed-attrs.rs:209:3 | LL | #[no_link()] | ^^^^^^^-- @@ -801,7 +807,7 @@ LL + #[no_link] | error[E0539]: malformed `macro_use` attribute input - --> $DIR/malformed-attrs.rs:212:3 + --> $DIR/malformed-attrs.rs:213:3 | LL | #[macro_use = 1] | ^^^^^^^^^^--- @@ -819,7 +825,7 @@ LL + #[macro_use(name1, name2, ...)] | error[E0539]: malformed `macro_export` attribute input - --> $DIR/malformed-attrs.rs:217:3 + --> $DIR/malformed-attrs.rs:218:3 | LL | #[macro_export = 18] | ^^^^^^^^^^^^^---- @@ -836,7 +842,7 @@ LL + #[macro_export(local_inner_macros)] | error[E0658]: the `allow_internal_unsafe` attribute side-steps the `unsafe_code` lint - --> $DIR/malformed-attrs.rs:219:3 + --> $DIR/malformed-attrs.rs:220:3 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^ @@ -845,7 +851,7 @@ LL | #[allow_internal_unsafe = 1] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0565]: malformed `allow_internal_unsafe` attribute input - --> $DIR/malformed-attrs.rs:219:3 + --> $DIR/malformed-attrs.rs:220:3 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^--- @@ -877,7 +883,7 @@ LL | #[doc()] | ^^^^^ error: valid forms for the attribute are `inline`, `inline(always)`, and `inline(never)` - --> $DIR/malformed-attrs.rs:51:3 + --> $DIR/malformed-attrs.rs:52:3 | LL | #[inline = 5] | ^^^^^^^^^^ @@ -887,13 +893,13 @@ LL | #[inline = 5] = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/malformed-attrs.rs:77:1 + --> $DIR/malformed-attrs.rs:78:1 | LL | #[crate_name] | ^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/malformed-attrs.rs:116:1 + --> $DIR/malformed-attrs.rs:117:1 | LL | / fn test() { LL | | #[coroutine = 63] || {} @@ -903,7 +909,7 @@ LL | | } = note: requested on the command line with `-W unused-attributes` warning: the `link` attribute cannot be used on functions - --> $DIR/malformed-attrs.rs:84:3 + --> $DIR/malformed-attrs.rs:85:3 | LL | #[link] | ^^^^ @@ -914,7 +920,7 @@ LL | fn test() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: the `link_name` attribute cannot be used on functions - --> $DIR/malformed-attrs.rs:88:3 + --> $DIR/malformed-attrs.rs:89:3 | LL | #[link_name] | ^^^^^^^^^ @@ -925,7 +931,7 @@ LL | fn test() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: valid forms for the attribute are `ignore` and `ignore = "reason"` - --> $DIR/malformed-attrs.rs:98:3 + --> $DIR/malformed-attrs.rs:99:3 | LL | #[ignore()] | ^^^^^^^^ @@ -934,7 +940,7 @@ LL | #[ignore()] = note: for more information, see issue #57571 warning: the `no_implicit_prelude` attribute cannot be used on functions - --> $DIR/malformed-attrs.rs:101:3 + --> $DIR/malformed-attrs.rs:102:3 | LL | #[no_implicit_prelude = 23] | ^^^^^^^^^^^^^^^^^^^ @@ -945,7 +951,7 @@ LL | fn test() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: missing options for `diagnostic::on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:140:1 + --> $DIR/malformed-attrs.rs:141:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -954,7 +960,7 @@ LL | #[diagnostic::on_unimplemented] = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: malformed `diagnostic::on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:142:1 + --> $DIR/malformed-attrs.rs:143:1 | LL | #[diagnostic::on_unimplemented = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -962,13 +968,13 @@ LL | #[diagnostic::on_unimplemented = 1] = help: only `message`, `note` and `label` are allowed as options warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/malformed-attrs.rs:149:1 + --> $DIR/malformed-attrs.rs:150:1 | LL | #[diagnostic::do_not_recommend()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the `automatically_derived` attribute cannot be used on modules - --> $DIR/malformed-attrs.rs:190:3 + --> $DIR/malformed-attrs.rs:191:3 | LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^ @@ -979,7 +985,7 @@ LL | mod yooo { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: use of deprecated `no_link` attribute - --> $DIR/malformed-attrs.rs:208:1 + --> $DIR/malformed-attrs.rs:209:1 | LL | #[no_link()] | ^^^^^^^^^^^^ @@ -989,7 +995,7 @@ LL | #[no_link()] = note: `#[deny(no_link_attributes)]` (part of `#[deny(future_incompatible)]`) on by default error: valid forms for the attribute are `ignore` and `ignore = "reason"` - --> $DIR/malformed-attrs.rs:226:3 + --> $DIR/malformed-attrs.rs:227:3 | LL | #[ignore = 1] | ^^^^^^^^^^ @@ -998,7 +1004,7 @@ LL | #[ignore = 1] = note: for more information, see issue #57571 error[E0308]: mismatched types - --> $DIR/malformed-attrs.rs:117:23 + --> $DIR/malformed-attrs.rs:118:23 | LL | fn test() { | - help: a return type might be missing here: `-> _` @@ -1006,15 +1012,15 @@ LL | #[coroutine = 63] || {} | ^^^^^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{coroutine@$DIR/malformed-attrs.rs:117:23: 117:25}` + found coroutine `{coroutine@$DIR/malformed-attrs.rs:118:23: 118:25}` -error: aborting due to 75 previous errors; 8 warnings emitted +error: aborting due to 76 previous errors; 8 warnings emitted -Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805. +Some errors have detailed explanations: E0308, E0433, E0463, E0539, E0565, E0658, E0805. For more information about an error, try `rustc --explain E0308`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `inline`, `inline(always)`, and `inline(never)` - --> $DIR/malformed-attrs.rs:51:3 + --> $DIR/malformed-attrs.rs:52:3 | LL | #[inline = 5] | ^^^^^^^^^^ @@ -1025,7 +1031,7 @@ LL | #[inline = 5] Future breakage diagnostic: error: valid forms for the attribute are `ignore` and `ignore = "reason"` - --> $DIR/malformed-attrs.rs:98:3 + --> $DIR/malformed-attrs.rs:99:3 | LL | #[ignore()] | ^^^^^^^^ @@ -1036,7 +1042,7 @@ LL | #[ignore()] Future breakage diagnostic: error: use of deprecated `no_link` attribute - --> $DIR/malformed-attrs.rs:208:1 + --> $DIR/malformed-attrs.rs:209:1 | LL | #[no_link()] | ^^^^^^^^^^^^ @@ -1047,7 +1053,7 @@ LL | #[no_link()] Future breakage diagnostic: error: valid forms for the attribute are `ignore` and `ignore = "reason"` - --> $DIR/malformed-attrs.rs:226:3 + --> $DIR/malformed-attrs.rs:227:3 | LL | #[ignore = 1] | ^^^^^^^^^^ diff --git a/tests/ui/lint_helper_namespace/feature_gates.rs b/tests/ui/lint_helper_namespace/feature_gates.rs new file mode 100644 index 0000000000000..11bb8d91ba43e --- /dev/null +++ b/tests/ui/lint_helper_namespace/feature_gates.rs @@ -0,0 +1,8 @@ +#![crate_type = "lib"] +#![feature(register_tool)] +#![register_tool(lint)] + +#[lint::as_ptr] //~ ERROR use of an internal attribute +fn cast(x: &u8) -> *const u8 { + x +} diff --git a/tests/ui/lint_helper_namespace/feature_gates.stderr b/tests/ui/lint_helper_namespace/feature_gates.stderr new file mode 100644 index 0000000000000..b597afab19442 --- /dev/null +++ b/tests/ui/lint_helper_namespace/feature_gates.stderr @@ -0,0 +1,12 @@ +error[E0658]: use of an internal attribute + --> $DIR/feature_gates.rs:5:3 + | +LL | #[lint::as_ptr] + | ^^^^^^^^^^^^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `lint::as_ptr` attribute is an internal implementation detail that will never be stable + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint_helper_namespace/registered_invalid.rs b/tests/ui/lint_helper_namespace/registered_invalid.rs new file mode 100644 index 0000000000000..9295d74c2519a --- /dev/null +++ b/tests/ui/lint_helper_namespace/registered_invalid.rs @@ -0,0 +1,6 @@ +#![crate_type = "lib"] +#![feature(register_tool)] +#![register_tool(lint)] + +#[lint::bogus] //~ ERROR the `lint::bogus` attribute is not recognized +struct Foo; diff --git a/tests/ui/lint_helper_namespace/registered_invalid.stderr b/tests/ui/lint_helper_namespace/registered_invalid.stderr new file mode 100644 index 0000000000000..216c1659ed21d --- /dev/null +++ b/tests/ui/lint_helper_namespace/registered_invalid.stderr @@ -0,0 +1,8 @@ +error: the `lint::bogus` attribute is not recognized + --> $DIR/registered_invalid.rs:5:3 + | +LL | #[lint::bogus] + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint_helper_namespace/resolve_as_macro.registered.stderr b/tests/ui/lint_helper_namespace/resolve_as_macro.registered.stderr new file mode 100644 index 0000000000000..f871748a3a0dd --- /dev/null +++ b/tests/ui/lint_helper_namespace/resolve_as_macro.registered.stderr @@ -0,0 +1,11 @@ +error: attribute macro `lint::as_ptr` is ambiguous + --> $DIR/resolve_as_macro.rs:9:3 + | +LL | #[lint::as_ptr] + | ^^^^^^^^^^^^ + | + = note: ambiguous because of a name conflict with a tool namespace + = note: `lint` could refer to a tool namespace + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint_helper_namespace/resolve_as_macro.rs b/tests/ui/lint_helper_namespace/resolve_as_macro.rs new file mode 100644 index 0000000000000..f1967112435a0 --- /dev/null +++ b/tests/ui/lint_helper_namespace/resolve_as_macro.rs @@ -0,0 +1,14 @@ +//@revisions: registered unregistered +//@[unregistered] check-pass + +#![crate_type = "lib"] +#![cfg_attr(unregistered, feature(rustc_attrs))] +#![cfg_attr(registered, feature(register_tool))] +#![cfg_attr(registered, register_tool(lint))] + +#[lint::as_ptr] //[registered]~ERROR attribute macro `lint::as_ptr` is ambiguous +fn foo() {} + +mod lint { + pub use std::prelude::v1::test as as_ptr; +} diff --git a/tests/ui/lint_helper_namespace/resolve_as_macro.with.stderr b/tests/ui/lint_helper_namespace/resolve_as_macro.with.stderr new file mode 100644 index 0000000000000..f871748a3a0dd --- /dev/null +++ b/tests/ui/lint_helper_namespace/resolve_as_macro.with.stderr @@ -0,0 +1,11 @@ +error: attribute macro `lint::as_ptr` is ambiguous + --> $DIR/resolve_as_macro.rs:9:3 + | +LL | #[lint::as_ptr] + | ^^^^^^^^^^^^ + | + = note: ambiguous because of a name conflict with a tool namespace + = note: `lint` could refer to a tool namespace + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint_helper_namespace/unregistered.rs b/tests/ui/lint_helper_namespace/unregistered.rs new file mode 100644 index 0000000000000..8c26a9307b476 --- /dev/null +++ b/tests/ui/lint_helper_namespace/unregistered.rs @@ -0,0 +1,4 @@ +#![crate_type = "lib"] + +#[lint::mac] //~ ERROR cannot find module or crate `lint` in this scope +struct Foo; diff --git a/tests/ui/lint_helper_namespace/unregistered.stderr b/tests/ui/lint_helper_namespace/unregistered.stderr new file mode 100644 index 0000000000000..59fc106db6521 --- /dev/null +++ b/tests/ui/lint_helper_namespace/unregistered.stderr @@ -0,0 +1,9 @@ +error[E0433]: cannot find module or crate `lint` in this scope + --> $DIR/unregistered.rs:3:3 + | +LL | #[lint::mac] + | ^^^^ use of unresolved module or unlinked crate `lint` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. From 6c51a7c9059d39766c3afc2b289c19a9e83c8dfd Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 1 Oct 2026 22:28:11 +0200 Subject: [PATCH 27/31] port over `rustc_never_returns_null_ptr` to lint helper namespace --- compiler/rustc_attr_ir/src/data_structures.rs | 6 +++--- compiler/rustc_attr_ir/src/encode_cross_crate.rs | 4 ++-- .../src/attributes/lint_helpers.rs | 16 ++++++++++++++++ .../src/attributes/rustc_internal.rs | 16 ---------------- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 1 - compiler/rustc_lint/src/ptr_nulls.rs | 6 +++--- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- library/alloc/src/boxed.rs | 9 +++++---- library/alloc/src/rcs/arc.rs | 4 ++-- library/alloc/src/rcs/rc.rs | 4 ++-- library/alloc/src/vec/mod.rs | 7 ++++--- library/core/src/cell.rs | 10 +++++----- library/core/src/ffi/c_str.rs | 2 +- library/core/src/ptr/mod.rs | 4 ++-- library/core/src/ptr/non_null.rs | 4 ++-- library/core/src/slice/mod.rs | 6 +++--- library/core/src/str/mod.rs | 8 ++++---- library/core/src/sync/atomic.rs | 6 +++--- tests/ui/lint_helper_namespace/feature_gates.rs | 1 + .../lint_helper_namespace/feature_gates.stderr | 11 ++++++++++- 22 files changed, 71 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_attr_ir/src/data_structures.rs b/compiler/rustc_attr_ir/src/data_structures.rs index c3ce6144aa633..296c0d81d1791 100644 --- a/compiler/rustc_attr_ir/src/data_structures.rs +++ b/compiler/rustc_attr_ir/src/data_structures.rs @@ -992,6 +992,9 @@ pub enum AttributeKind { /// Represents `#[allow]`, `#[warn]`, `#[deny]`, `#[forbid]`, and `#[expect]`. LintCheck(ThinVec), + /// Represents `#[lint::never_returns_null_ptr]` (used by the `useless_ptr_null_checks` lint). + LintNeverReturnsNullPtr, + /// Represents `#[loop_match]`. LoopMatch(Span), @@ -1396,9 +1399,6 @@ pub enum AttributeKind { /// Represents `#[rustc_must_match_exhaustively]` RustcMustMatchExhaustively(Span), - /// Represents `#[rustc_never_returns_null_ptr]` - RustcNeverReturnsNullPtr, - /// Represents `#[rustc_no_implicit_autorefs]` RustcNoImplicitAutorefs, diff --git a/compiler/rustc_attr_ir/src/encode_cross_crate.rs b/compiler/rustc_attr_ir/src/encode_cross_crate.rs index 3d50923c6ae5a..e717b5653b33f 100644 --- a/compiler/rustc_attr_ir/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_ir/src/encode_cross_crate.rs @@ -60,6 +60,7 @@ impl AttributeKind { Linkage(..) => No, LintAsPtr => Yes, LintCheck(..) => No, + LintNeverReturnsNullPtr => Yes, LoopMatch(..) => No, MacroEscape => No, MacroExport { .. } => Yes, @@ -167,7 +168,6 @@ impl AttributeKind { RustcMir(..) => Yes, RustcMustImplementOneOf { .. } => No, RustcMustMatchExhaustively(..) => Yes, - RustcNeverReturnsNullPtr => Yes, RustcNoImplicitAutorefs => Yes, RustcNoImplicitBounds => No, RustcNoMirInline => Yes, @@ -278,6 +278,7 @@ impl AttributeKind { }, LintAsPtr => false, LintCheck(_) => false, + LintNeverReturnsNullPtr => false, LoopMatch(..) => false, MacroEscape => false, MacroExport { .. } => false, @@ -385,7 +386,6 @@ impl AttributeKind { RustcMir(..) => false, RustcMustImplementOneOf { .. } => false, RustcMustMatchExhaustively(..) => false, - RustcNeverReturnsNullPtr => false, RustcNoImplicitAutorefs => false, RustcNoImplicitBounds => false, RustcNoMirInline => false, diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 6c1c91eadfb53..725e458c99c5e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -18,6 +18,22 @@ impl NoArgsAttributeParser for LintAsPtrParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::LintAsPtr; } +pub(crate) struct LintNeverReturnsNullPtrParser; + +impl NoArgsAttributeParser for LintNeverReturnsNullPtrParser { + const PATH: &[Symbol] = &[sym::lint, sym::never_returns_null_ptr]; + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + ]); + const STABILITY: AttributeStability = unstable!(rustc_attrs); + + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::LintNeverReturnsNullPtr; +} + pub(crate) struct RustcPubTransparentParser; impl NoArgsAttributeParser for RustcPubTransparentParser { const PATH: &[Symbol] = &[sym::rustc_pub_transparent]; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index e8bdce0df5b95..d9ce3552138c8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -89,22 +89,6 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser { } } -pub(crate) struct RustcNeverReturnsNullPtrParser; - -impl NoArgsAttributeParser for RustcNeverReturnsNullPtrParser { - const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr]; - const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ - Allow(Target::Fn), - Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: false })), - Allow(Target::Method(MethodKind::Trait { body: true })), - Allow(Target::Method(MethodKind::TraitImpl)), - ]); - const STABILITY: AttributeStability = unstable!(rustc_attrs); - - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPtr; -} - pub(crate) struct RustcPanicsWhenZeroParser; impl NoArgsAttributeParser for RustcPanicsWhenZeroParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8886cef7225e5..64053f76ff498 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -275,6 +275,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -335,7 +336,6 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 8ab1601b2b62d..f022b50d6fdc4 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -352,7 +352,6 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::lang, sym::rustc_should_not_be_called_on_const_items, sym::rustc_pass_by_value, - sym::rustc_never_returns_null_ptr, sym::rustc_no_implicit_autorefs, sym::rustc_coherence_is_core, sym::rustc_coinductive, diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index c231bd4cc3b30..0010022aa4f9d 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -62,7 +62,7 @@ declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS, INVALID_NULL_ARGUM /// This function checks if the expression is from a series of consecutive casts, /// i.e. `(my_fn as *const _ as *mut _).cast_mut()` and whether the original expression is either /// a fn ptr, a reference, or a function call whose definition is -/// annotated with `#![rustc_never_returns_null_ptr]`. +/// annotated with `#[lint::never_returns_null_ptr]`. /// If this situation is present, the function returns the appropriate diagnostic. fn useless_check<'a, 'tcx: 'a>( cx: &'a LateContext<'tcx>, @@ -73,14 +73,14 @@ fn useless_check<'a, 'tcx: 'a>( e = e.peel_blocks(); if let ExprKind::MethodCall(_, _expr, [], _) = e.kind && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) - && find_attr!(cx.tcx, def_id, RustcNeverReturnsNullPtr) + && find_attr!(cx.tcx, def_id, LintNeverReturnsNullPtr) && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { return Some(UselessPtrNullChecksDiag::FnRet { fn_name }); } else if let ExprKind::Call(path, _args) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() - && find_attr!(cx.tcx, def_id, RustcNeverReturnsNullPtr) + && find_attr!(cx.tcx, def_id, LintNeverReturnsNullPtr) && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { return Some(UselessPtrNullChecksDiag::FnRet { fn_name }); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0c5a5a6baf836..ce31013b305f6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -258,6 +258,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::LinkOrdinal { .. } => (), AttributeKind::LinkSection { .. } => (), AttributeKind::LintAsPtr => (), + AttributeKind::LintNeverReturnsNullPtr => (), AttributeKind::LoopMatch(..) => (), AttributeKind::MacroEscape => (), AttributeKind::MacroExport { .. } => (), @@ -356,7 +357,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcMain => (), AttributeKind::RustcMir(_) => (), AttributeKind::RustcMustMatchExhaustively(..) => (), - AttributeKind::RustcNeverReturnsNullPtr => (), AttributeKind::RustcNoImplicitAutorefs => (), AttributeKind::RustcNoImplicitBounds => (), AttributeKind::RustcNoMirInline => (), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 80a6b14d92523..225854861898e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1446,6 +1446,7 @@ symbols! { nested, never, never_patterns, + never_returns_null_ptr, never_type, never_type_fallback, new, @@ -1866,7 +1867,6 @@ symbols! { rustc_mir, rustc_must_implement_one_of, rustc_must_match_exhaustively, - rustc_never_returns_null_ptr, rustc_no_implicit_autorefs, rustc_no_implicit_bounds, rustc_no_mir_inline, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index b20b15026ab5d..76ab66ae0fa2e 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1913,9 +1913,9 @@ impl Box { /// [`as_non_null`]: Self::as_non_null #[must_use] #[stable(feature = "box_as_ptr", since = "1.98.0")] - #[rustc_never_returns_null_ptr] - #[lint::as_ptr] #[inline] + #[lint::as_ptr] + #[lint::never_returns_null_ptr] pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing // any references. @@ -1962,9 +1962,10 @@ impl Box { /// [`as_non_null`]: Self::as_non_null #[must_use] #[stable(feature = "box_as_ptr", since = "1.98.0")] - #[rustc_never_returns_null_ptr] - #[lint::as_ptr] #[inline] + #[lint::as_ptr] + #[lint::never_returns_null_ptr] + pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing // any references. diff --git a/library/alloc/src/rcs/arc.rs b/library/alloc/src/rcs/arc.rs index 505000fcc73eb..59048f9785263 100644 --- a/library/alloc/src/rcs/arc.rs +++ b/library/alloc/src/rcs/arc.rs @@ -1727,7 +1727,7 @@ impl Arc { /// ``` #[must_use = "losing the pointer will leak memory"] #[stable(feature = "rc_raw", since = "1.17.0")] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub fn into_raw(this: Self) -> *const T { let this = ManuallyDrop::new(this); Self::as_ptr(&*this) @@ -1924,7 +1924,7 @@ impl Arc { /// ``` #[must_use] #[stable(feature = "rc_as_ptr", since = "1.45.0")] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); diff --git a/library/alloc/src/rcs/rc.rs b/library/alloc/src/rcs/rc.rs index 9fd04345ab907..bdf965ed076f0 100644 --- a/library/alloc/src/rcs/rc.rs +++ b/library/alloc/src/rcs/rc.rs @@ -1568,7 +1568,7 @@ impl Rc { /// ``` #[must_use = "losing the pointer will leak memory"] #[stable(feature = "rc_raw", since = "1.17.0")] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub fn into_raw(this: Self) -> *const T { let this = ManuallyDrop::new(this); Self::as_ptr(&*this) @@ -1750,7 +1750,7 @@ impl Rc { /// assert_eq!(unsafe { *x_ptr }, 0); /// ``` #[stable(feature = "weak_into_raw", since = "1.45.0")] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut RcInner = NonNull::as_ptr(this.ptr); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 0fb94f2fa7fa2..aa9a1c367041d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1881,9 +1881,10 @@ impl Vec { /// [didn't allocate]: self#memory-layout #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] - #[rustc_never_returns_null_ptr] - #[lint::as_ptr] #[inline] + #[lint::as_ptr] + #[lint::never_returns_null_ptr] + pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through // `deref`, which creates an intermediate reference. @@ -1966,8 +1967,8 @@ impl Vec { /// [didn't allocate]: self#memory-layout #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] - #[rustc_never_returns_null_ptr] #[lint::as_ptr] + #[lint::never_returns_null_ptr] #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 1deb700cd2a72..bf64f6943fe0a 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -601,7 +601,7 @@ impl Cell { #[stable(feature = "cell_as_ptr", since = "1.12.0")] #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")] #[lint::as_ptr] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() } @@ -1291,9 +1291,9 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] - #[lint::as_ptr] - #[rustc_never_returns_null_ptr] #[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")] + #[lint::as_ptr] + #[lint::never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() } @@ -2431,7 +2431,7 @@ impl UnsafeCell { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] #[lint::as_ptr] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] #[rustc_should_not_be_called_on_const_items] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of @@ -2638,7 +2638,7 @@ impl SyncUnsafeCell { /// or mutable aliases going on when casting to `&T` #[inline] #[lint::as_ptr] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] #[rustc_should_not_be_called_on_const_items] pub const fn get(&self) -> *mut T { self.value.get() diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index a8347f9dc3182..9ab47193cf174 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -487,7 +487,7 @@ impl CStr { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] #[lint::as_ptr] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index be3dc5e013b32..bb7a52f3c50d8 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1116,7 +1116,7 @@ pub const fn with_exposed_provenance_mut(addr: usize) -> *mut T { #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] #[rustc_const_stable(feature = "ptr_from_ref", since = "1.76.0")] -#[rustc_never_returns_null_ptr] +#[lint::never_returns_null_ptr] #[rustc_diagnostic_item = "ptr_from_ref"] pub const fn from_ref(r: &T) -> *const T { r @@ -1167,7 +1167,7 @@ pub const fn from_ref(r: &T) -> *const T { #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] #[rustc_const_stable(feature = "ptr_from_ref", since = "1.76.0")] -#[rustc_never_returns_null_ptr] +#[lint::never_returns_null_ptr] pub const fn from_mut(r: &mut T) -> *mut T { r } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 36e4bc2f9286c..ffcab7ff1e84b 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -404,9 +404,9 @@ impl NonNull { /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")] - #[rustc_never_returns_null_ptr] #[must_use] #[inline(always)] + #[lint::never_returns_null_ptr] pub const fn as_ptr(self) -> *mut T { // This is a transmute for the same reasons as `NonZero::get`. @@ -1469,7 +1469,7 @@ impl NonNull<[T]> { #[inline] #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub const fn as_mut_ptr(self) -> *mut T { self.as_non_null_ptr().as_ptr() } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 4c563497ace66..f62dcce8df324 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -723,10 +723,10 @@ impl [T] { /// [`as_mut_ptr`]: slice::as_mut_ptr #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] - #[rustc_never_returns_null_ptr] - #[lint::as_ptr] #[inline(always)] #[must_use] + #[lint::as_ptr] + #[lint::never_returns_null_ptr] pub const fn as_ptr(&self) -> *const T { self as *const [T] as *const T } @@ -754,8 +754,8 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] - #[rustc_never_returns_null_ptr] #[lint::as_ptr] + #[lint::never_returns_null_ptr] #[inline(always)] #[must_use] #[rustc_no_writable] diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index c5c3cf0a206a1..b6c7950901f59 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -584,10 +584,10 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] - #[rustc_never_returns_null_ptr] - #[lint::as_ptr] #[must_use] #[inline(always)] + #[lint::as_ptr] + #[lint::never_returns_null_ptr] pub const fn as_ptr(&self) -> *const u8 { self as *const str as *const u8 } @@ -602,11 +602,11 @@ impl str { /// modified in a way that it remains valid UTF-8. #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")] - #[rustc_never_returns_null_ptr] - #[lint::as_ptr] #[must_use] #[inline(always)] #[rustc_no_writable] + #[lint::as_ptr] + #[lint::never_returns_null_ptr] pub const fn as_mut_ptr(&mut self) -> *mut u8 { self as *mut str as *mut u8 } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 14e33019a45ff..0925659a028ff 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1415,7 +1415,7 @@ impl AtomicBool { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] #[rustc_should_not_be_called_on_const_items] pub const fn as_ptr(&self) -> *mut bool { self.v.get().cast() @@ -2747,7 +2747,7 @@ impl AtomicPtr { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut *mut T { self.v.get().cast() } @@ -4009,7 +4009,7 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] - #[rustc_never_returns_null_ptr] + #[lint::never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut $int_type { self.v.get().cast() } diff --git a/tests/ui/lint_helper_namespace/feature_gates.rs b/tests/ui/lint_helper_namespace/feature_gates.rs index 11bb8d91ba43e..d5e1008f89f57 100644 --- a/tests/ui/lint_helper_namespace/feature_gates.rs +++ b/tests/ui/lint_helper_namespace/feature_gates.rs @@ -3,6 +3,7 @@ #![register_tool(lint)] #[lint::as_ptr] //~ ERROR use of an internal attribute +#[lint::never_returns_null_ptr] //~ ERROR use of an internal attribute fn cast(x: &u8) -> *const u8 { x } diff --git a/tests/ui/lint_helper_namespace/feature_gates.stderr b/tests/ui/lint_helper_namespace/feature_gates.stderr index b597afab19442..0bed2a048ab23 100644 --- a/tests/ui/lint_helper_namespace/feature_gates.stderr +++ b/tests/ui/lint_helper_namespace/feature_gates.stderr @@ -7,6 +7,15 @@ LL | #[lint::as_ptr] = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: the `lint::as_ptr` attribute is an internal implementation detail that will never be stable -error: aborting due to 1 previous error +error[E0658]: use of an internal attribute + --> $DIR/feature_gates.rs:6:3 + | +LL | #[lint::never_returns_null_ptr] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `lint::never_returns_null_ptr` attribute is an internal implementation detail that will never be stable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From a6443cbb93add459b9951e4725cfe279288d1eb5 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 1 Oct 2026 23:08:59 +0200 Subject: [PATCH 28/31] Port over `rustc_should_not_be_called_on_const_items` to lint helper namespace --- compiler/rustc_attr_ir/src/data_structures.rs | 4 + .../rustc_attr_ir/src/encode_cross_crate.rs | 2 + .../src/attributes/lint_helpers.rs | 8 +- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 1 - .../rustc_lint/src/interior_mutable_consts.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/cell.rs | 34 +++---- .../core/src/cell/covariant_unsafe_cell.rs | 2 +- library/core/src/cell/lazy.rs | 2 +- library/core/src/cell/once.rs | 8 +- library/core/src/sync/atomic.rs | 96 +++++++++---------- library/std/src/lib.rs | 5 + library/std/src/sync/lazy_lock.rs | 4 +- library/std/src/sync/once.rs | 8 +- library/std/src/sync/once_lock.rs | 12 +-- library/std/src/sync/poison/condvar.rs | 14 +-- library/std/src/sync/poison/mutex.rs | 10 +- library/std/src/sync/poison/rwlock.rs | 12 +-- .../ui/lint_helper_namespace/feature_gates.rs | 13 ++- .../feature_gates.stderr | 23 +++-- 22 files changed, 145 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_attr_ir/src/data_structures.rs b/compiler/rustc_attr_ir/src/data_structures.rs index 296c0d81d1791..de76768b7a3bc 100644 --- a/compiler/rustc_attr_ir/src/data_structures.rs +++ b/compiler/rustc_attr_ir/src/data_structures.rs @@ -995,6 +995,10 @@ pub enum AttributeKind { /// Represents `#[lint::never_returns_null_ptr]` (used by the `useless_ptr_null_checks` lint). LintNeverReturnsNullPtr, + /// Represents `#[lint::should_not_be_called_on_const_items]` (used by the + /// `const_item_interior_mutations` lint). + LintShouldNotBeCalledOnConstItems, + /// Represents `#[loop_match]`. LoopMatch(Span), diff --git a/compiler/rustc_attr_ir/src/encode_cross_crate.rs b/compiler/rustc_attr_ir/src/encode_cross_crate.rs index e717b5653b33f..ac02373f7d58a 100644 --- a/compiler/rustc_attr_ir/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_ir/src/encode_cross_crate.rs @@ -61,6 +61,7 @@ impl AttributeKind { LintAsPtr => Yes, LintCheck(..) => No, LintNeverReturnsNullPtr => Yes, + LintShouldNotBeCalledOnConstItems => Yes, LoopMatch(..) => No, MacroEscape => No, MacroExport { .. } => Yes, @@ -279,6 +280,7 @@ impl AttributeKind { LintAsPtr => false, LintCheck(_) => false, LintNeverReturnsNullPtr => false, + LintShouldNotBeCalledOnConstItems => false, LoopMatch(..) => false, MacroEscape => false, MacroExport { .. } => false, diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 725e458c99c5e..416f0386c52e2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -69,15 +69,15 @@ impl NoArgsAttributeParser for RustcPassByValueParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPassByValue; } -pub(crate) struct RustcShouldNotBeCalledOnConstItemsParser; -impl NoArgsAttributeParser for RustcShouldNotBeCalledOnConstItemsParser { - const PATH: &[Symbol] = &[sym::rustc_should_not_be_called_on_const_items]; +pub(crate) struct LintShouldNotBeCalledOnConstItemsParser; +impl NoArgsAttributeParser for LintShouldNotBeCalledOnConstItemsParser { + const PATH: &[Symbol] = &[sym::lint, sym::should_not_be_called_on_const_items]; const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::TraitImpl)), ]); const STABILITY: AttributeStability = unstable!(rustc_attrs); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcShouldNotBeCalledOnConstItems; + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::LintShouldNotBeCalledOnConstItems; } pub(crate) struct AutomaticallyDerivedParser; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 64053f76ff498..547649313ac44 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -276,6 +276,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -353,7 +354,6 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index f022b50d6fdc4..52dba353eb24b 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -350,7 +350,6 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ // Internal attributes, Misc: // ========================================================================== sym::lang, - sym::rustc_should_not_be_called_on_const_items, sym::rustc_pass_by_value, sym::rustc_no_implicit_autorefs, sym::rustc_coherence_is_core, diff --git a/compiler/rustc_lint/src/interior_mutable_consts.rs b/compiler/rustc_lint/src/interior_mutable_consts.rs index 4d0557d5e9b54..f006979ab50bc 100644 --- a/compiler/rustc_lint/src/interior_mutable_consts.rs +++ b/compiler/rustc_lint/src/interior_mutable_consts.rs @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InteriorMutableConsts { // Let's do the attribute check after the other checks for perf reasons && find_attr!( cx.tcx, method_did, - RustcShouldNotBeCalledOnConstItems + LintShouldNotBeCalledOnConstItems ) && let Some(method_name) = cx.tcx.opt_item_ident(method_did) && let Some(const_name) = cx.tcx.opt_item_ident(const_did) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ce31013b305f6..41bc7b0a1539f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -259,6 +259,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::LinkSection { .. } => (), AttributeKind::LintAsPtr => (), AttributeKind::LintNeverReturnsNullPtr => (), + AttributeKind::LintShouldNotBeCalledOnConstItems => (), AttributeKind::LoopMatch(..) => (), AttributeKind::MacroEscape => (), AttributeKind::MacroExport { .. } => (), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 225854861898e..d52c181cff141 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1954,6 +1954,7 @@ symbols! { shl, shl_assign, shorter_tail_lifetimes, + should_not_be_called_on_const_items, should_panic, show, shr, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index bf64f6943fe0a..515b68de43bfb 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -434,7 +434,7 @@ impl Cell { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cell_traits", issue = "147787")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn set(&self, val: T) where T: [const] Destruct, @@ -466,7 +466,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "move_cell", since = "1.17.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn swap(&self, other: &Self) { // This function documents that it *will* panic, and intrinsics::is_nonoverlapping doesn't // do the check in const, so trying to use it here would be inviting unnecessary fragility. @@ -511,7 +511,7 @@ impl Cell { #[stable(feature = "move_cell", since = "1.17.0")] #[rustc_const_stable(feature = "const_cell", since = "1.88.0")] #[rustc_confusables("swap")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn replace(&self, val: T) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. @@ -553,7 +553,7 @@ impl Cell { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_cell", since = "1.88.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn get(&self) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. @@ -574,7 +574,7 @@ impl Cell { #[inline] #[stable(feature = "cell_update", since = "1.88.0")] #[rustc_const_unstable(feature = "const_cell_traits", issue = "147787")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn update(&self, f: impl [const] FnOnce(T) -> T) where // FIXME(const-hack): `Copy` should imply `const Destruct` @@ -1026,7 +1026,7 @@ impl RefCell { #[track_caller] #[rustc_confusables("swap")] #[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn replace(&self, t: T) -> T { mem::replace(&mut self.borrow_mut(), t) } @@ -1050,7 +1050,7 @@ impl RefCell { #[inline] #[stable(feature = "refcell_replace_swap", since = "1.35.0")] #[track_caller] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn replace_with T>(&self, f: F) -> T { let mut_borrow = &mut *self.borrow_mut(); let replacement = f(mut_borrow); @@ -1080,7 +1080,7 @@ impl RefCell { #[inline] #[stable(feature = "refcell_swap", since = "1.24.0")] #[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn swap(&self, other: &Self) { mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut()) } @@ -1122,7 +1122,7 @@ impl RefCell { #[inline] #[track_caller] #[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn borrow(&self) -> Ref<'_, T> { match self.try_borrow() { Ok(b) => b, @@ -1159,7 +1159,7 @@ impl RefCell { #[inline] #[cfg_attr(feature = "debug_refcell", track_caller)] #[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn try_borrow(&self) -> Result, BorrowError> { match BorrowRef::new(&self.borrow) { Some(b) => { @@ -1222,7 +1222,7 @@ impl RefCell { #[inline] #[track_caller] #[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn borrow_mut(&self) -> RefMut<'_, T> { match self.try_borrow_mut() { Ok(b) => b, @@ -1256,7 +1256,7 @@ impl RefCell { #[inline] #[cfg_attr(feature = "debug_refcell", track_caller)] #[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn try_borrow_mut(&self) -> Result, BorrowMutError> { match BorrowRefMut::new(&self.borrow) { Some(b) => { @@ -2380,7 +2380,7 @@ impl UnsafeCell { #[inline] #[stable(feature = "unsafe_cell_access", since = "1.100.0")] #[rustc_const_stable(feature = "unsafe_cell_access", since = "1.100.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const unsafe fn replace(&self, value: T) -> T { // SAFETY: pointer comes from `&self` so naturally satisfies invariants. unsafe { ptr::replace(self.get(), value) } @@ -2432,7 +2432,7 @@ impl UnsafeCell { #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] #[lint::as_ptr] #[lint::never_returns_null_ptr] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of // #[repr(transparent)]. @@ -2522,7 +2522,7 @@ impl UnsafeCell { #[inline] #[stable(feature = "unsafe_cell_access", since = "1.100.0")] #[rustc_const_stable(feature = "unsafe_cell_access", since = "1.100.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const unsafe fn as_ref_unchecked(&self) -> &T { // SAFETY: pointer comes from `&self` so naturally satisfies ptr-to-ref invariants. unsafe { self.get().as_ref_unchecked() } @@ -2551,7 +2551,7 @@ impl UnsafeCell { #[stable(feature = "unsafe_cell_access", since = "1.100.0")] #[rustc_const_stable(feature = "unsafe_cell_access", since = "1.100.0")] #[allow(clippy::mut_from_ref)] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const unsafe fn as_mut_unchecked(&self) -> &mut T { // SAFETY: pointer comes from `&self` so naturally satisfies ptr-to-ref invariants. unsafe { self.get().as_mut_unchecked() } @@ -2639,7 +2639,7 @@ impl SyncUnsafeCell { #[inline] #[lint::as_ptr] #[lint::never_returns_null_ptr] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn get(&self) -> *mut T { self.value.get() } diff --git a/library/core/src/cell/covariant_unsafe_cell.rs b/library/core/src/cell/covariant_unsafe_cell.rs index ac3f265ce5763..e34dfef9ba8fe 100644 --- a/library/core/src/cell/covariant_unsafe_cell.rs +++ b/library/core/src/cell/covariant_unsafe_cell.rs @@ -84,7 +84,7 @@ impl CovariantUnsafeCell { /// ``` #[inline(always)] #[lint::as_ptr] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] #[unstable(feature = "covariant_unsafe_cell", issue = "159735")] #[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")] pub const fn get(&self) -> NonNull { diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index fc96376cbe70d..d77abd456beb0 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -137,7 +137,7 @@ impl T> LazyCell { /// ``` #[inline] #[stable(feature = "lazy_cell", since = "1.80.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn force(this: &LazyCell) -> &T { // SAFETY: // This invalidates any mutable references to the data. The resulting diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 6df10de2d5aae..c3b7f845d4fe0 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -113,7 +113,7 @@ impl OnceCell { /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn set(&self, value: T) -> Result<(), T> { match self.try_insert(value) { Ok(_) => Ok(()), @@ -146,7 +146,7 @@ impl OnceCell { /// ``` #[inline] #[unstable(feature = "once_cell_try_insert", issue = "116693")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { if let Some(old) = self.get() { return Err((old, value)); @@ -184,7 +184,7 @@ impl OnceCell { /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> T, @@ -259,7 +259,7 @@ impl OnceCell { /// assert_eq!(cell.get(), Some(&92)) /// ``` #[unstable(feature = "once_cell_try", issue = "109737")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0925659a028ff..d388c9d6cd142 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -831,7 +831,7 @@ impl AtomicBool { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn store(&self, val: bool, order: Ordering) { // SAFETY: any data races are prevented by atomic intrinsics and the raw // pointer passed in is valid because we got it from a reference. @@ -865,7 +865,7 @@ impl AtomicBool { #[unstable(feature = "atomic_volatile", issue = "158947")] #[rustc_const_unstable(feature = "atomic_volatile", issue = "158947")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const unsafe fn store_volatile(self: *const Self, val: bool, order: Ordering) { // SAFETY: follows from our own safety requirements. unsafe { @@ -898,7 +898,7 @@ impl AtomicBool { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn swap(&self, val: bool, order: Ordering) -> bool { if EMULATE_ATOMIC_BOOL { if val { self.fetch_or(true, order) } else { self.fetch_and(false, order) } @@ -967,7 +967,7 @@ impl AtomicBool { )] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -1030,7 +1030,7 @@ impl AtomicBool { #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn compare_exchange( &self, current: bool, @@ -1133,7 +1133,7 @@ impl AtomicBool { #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn compare_exchange_weak( &self, current: bool, @@ -1197,7 +1197,7 @@ impl AtomicBool { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_and(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_and(self.v.get().cast::(), val as u8, order) != 0 } @@ -1241,7 +1241,7 @@ impl AtomicBool { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_nand(&self, val: bool, order: Ordering) -> bool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done @@ -1295,7 +1295,7 @@ impl AtomicBool { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_or(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_or(self.v.get().cast::(), val as u8, order) != 0 } @@ -1338,7 +1338,7 @@ impl AtomicBool { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_xor(&self, val: bool, order: Ordering) -> bool { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_xor(self.v.get().cast::(), val as u8, order) != 0 } @@ -1377,7 +1377,7 @@ impl AtomicBool { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_not(&self, order: Ordering) -> bool { self.fetch_xor(true, order) } @@ -1416,7 +1416,7 @@ impl AtomicBool { #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] #[lint::never_returns_null_ptr] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn as_ptr(&self) -> *mut bool { self.v.get().cast() } @@ -1426,7 +1426,7 @@ impl AtomicBool { #[stable(feature = "atomic_fetch_update", since = "1.53.0")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] #[deprecated( since = "1.99.0", note = "renamed to `try_update` for consistency", @@ -1495,7 +1495,7 @@ impl AtomicBool { #[stable(feature = "atomic_try_update", since = "1.95.0")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn try_update( &self, set_order: Ordering, @@ -1558,7 +1558,7 @@ impl AtomicBool { #[stable(feature = "atomic_try_update", since = "1.95.0")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn update( &self, set_order: Ordering, @@ -1946,7 +1946,7 @@ impl AtomicPtr { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn store(&self, ptr: *mut T, order: Ordering) { // SAFETY: data races are prevented by atomic intrinsics. unsafe { @@ -2007,7 +2007,7 @@ impl AtomicPtr { #[unstable(feature = "atomic_volatile", issue = "158947")] #[rustc_const_unstable(feature = "atomic_volatile", issue = "158947")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const unsafe fn store_volatile(self: *const Self, ptr: *mut T, order: Ordering) { // SAFETY: follows from our own safety requirements. unsafe { @@ -2042,7 +2042,7 @@ impl AtomicPtr { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(target_has_atomic = "ptr")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_swap(self.as_ptr(), ptr, order) } @@ -2105,7 +2105,7 @@ impl AtomicPtr { )] #[cfg(target_has_atomic = "ptr")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -2160,7 +2160,7 @@ impl AtomicPtr { #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn compare_exchange( &self, current: *mut T, @@ -2224,7 +2224,7 @@ impl AtomicPtr { #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn compare_exchange_weak( &self, current: *mut T, @@ -2244,7 +2244,7 @@ impl AtomicPtr { #[stable(feature = "atomic_fetch_update", since = "1.53.0")] #[cfg(target_has_atomic = "ptr")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] #[deprecated( since = "1.99.0", note = "renamed to `try_update` for consistency", @@ -2322,7 +2322,7 @@ impl AtomicPtr { #[stable(feature = "atomic_try_update", since = "1.95.0")] #[cfg(target_has_atomic = "ptr")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn try_update( &self, set_order: Ordering, @@ -2390,7 +2390,7 @@ impl AtomicPtr { #[stable(feature = "atomic_try_update", since = "1.95.0")] #[cfg(target_has_atomic = "ptr")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn update( &self, set_order: Ordering, @@ -2442,7 +2442,7 @@ impl AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_add(val.wrapping_mul(size_of::()), order) } @@ -2487,7 +2487,7 @@ impl AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_sub(val.wrapping_mul(size_of::()), order) } @@ -2522,7 +2522,7 @@ impl AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_add(self.as_ptr(), val, order).cast() } @@ -2558,7 +2558,7 @@ impl AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_sub(self.as_ptr(), val, order).cast() } @@ -2609,7 +2609,7 @@ impl AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_or(self.as_ptr(), val, order).cast() } @@ -2659,7 +2659,7 @@ impl AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_and(self.as_ptr(), val, order).cast() } @@ -2707,7 +2707,7 @@ impl AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_xor(self.as_ptr(), val, order).cast() } @@ -3216,7 +3216,7 @@ macro_rules! atomic_int { #[$stable] #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn store(&self, val: $int_type, order: Ordering) { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_store::<_, /* VOLATILE */ false>(self.as_ptr(), val, order); } @@ -3261,7 +3261,7 @@ macro_rules! atomic_int { #[unstable(feature = "atomic_volatile", issue = "158947")] #[rustc_const_unstable(feature = "atomic_volatile", issue = "158947")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const unsafe fn store_volatile(self: *const Self, val: $int_type, order: Ordering) { // SAFETY: follows from our own safety requirements. unsafe { @@ -3294,7 +3294,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn swap(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_swap(self.as_ptr(), val, order) } @@ -3361,7 +3361,7 @@ macro_rules! atomic_int { ] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn compare_and_swap(&self, current: $int_type, new: $int_type, @@ -3432,7 +3432,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn compare_exchange(&self, current: $int_type, new: $int_type, @@ -3498,7 +3498,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn compare_exchange_weak(&self, current: $int_type, new: $int_type, @@ -3537,7 +3537,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_add(self.as_ptr(), val, order) } @@ -3570,7 +3570,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_sub(self.as_ptr(), val, order) } @@ -3606,7 +3606,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_and(self.as_ptr(), val, order) } @@ -3642,7 +3642,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_nand(self.as_ptr(), val, order) } @@ -3678,7 +3678,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_or(self.as_ptr(), val, order) } @@ -3714,7 +3714,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_xor(self.as_ptr(), val, order) } @@ -3727,7 +3727,7 @@ macro_rules! atomic_int { #[stable(feature = "no_more_cas", since = "1.45.0")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] #[deprecated( since = "1.99.0", note = "renamed to `try_update` for consistency", @@ -3793,7 +3793,7 @@ macro_rules! atomic_int { #[stable(feature = "atomic_try_update", since = "1.95.0")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn try_update( &self, set_order: Ordering, @@ -3860,7 +3860,7 @@ macro_rules! atomic_int { #[stable(feature = "atomic_try_update", since = "1.95.0")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn update( &self, set_order: Ordering, @@ -3918,7 +3918,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { $max_fn(self.as_ptr(), val, order) } @@ -3968,7 +3968,7 @@ macro_rules! atomic_int { #[rustc_const_unstable(feature = "const_atomic", issue = "160078")] #[cfg(any($cfg_cas, doc))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub const fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. unsafe { $min_fn(self.as_ptr(), val, order) } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8ed3a46bf3189..41fb9990b1fa6 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -374,6 +374,7 @@ #![feature(ptr_mask)] #![feature(random)] #![feature(raw_os_error_ty)] +#![feature(register_tool)] #![feature(seek_io_take_position)] #![feature(seek_stream_len)] #![feature(share_trait)] @@ -448,6 +449,10 @@ link = "https://github.com/rust-lang/rust/issues/29599#issuecomment-2986866250", since = "1.90.0" )] +// tidy-alphabetical-start +#![register_tool(lint)] +// tidy-alphabetical-end +// // The Rust prelude // The compiler expects the prelude definition to be defined before its use statement. diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 4462e8f7c193a..920a8596cdd99 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -237,7 +237,7 @@ impl T> LazyLock { /// ``` #[inline] #[stable(feature = "lazy_cell", since = "1.80.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn force(this: &LazyLock) -> &T { this.once.call_once_force(|state| { if state.is_poisoned() { @@ -307,7 +307,7 @@ impl LazyLock { /// ``` #[inline] #[stable(feature = "lazy_get", since = "1.94.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn get(this: &LazyLock) -> Option<&T> { if this.once.is_completed() { // SAFETY: diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 9b7dd3b78eac7..6834b9b486371 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -153,7 +153,7 @@ impl Once { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn call_once(&self, f: F) where F: FnOnce(), @@ -213,7 +213,7 @@ impl Once { /// ``` #[inline] #[stable(feature = "once_poison", since = "1.51.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn call_once_force(&self, f: F) where F: FnOnce(&OnceState), @@ -299,7 +299,7 @@ impl Once { /// if this behavior is not desired. #[inline] #[stable(feature = "once_wait", since = "1.86.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn wait(&self) { if !self.inner.is_completed() { self.inner.wait(false); @@ -313,7 +313,7 @@ impl Once { /// becomes completed, unlike [`Once::wait()`], which panics in this case. #[inline] #[stable(feature = "once_wait", since = "1.86.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn wait_force(&self) { if !self.inner.is_completed() { self.inner.wait(true); diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 3519adab66c4e..d62a3e87557b5 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -180,7 +180,7 @@ impl OnceLock { /// This method never blocks. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn get(&self) -> Option<&T> { if self.initialized() { // Safe b/c checked initialized @@ -228,7 +228,7 @@ impl OnceLock { /// ``` #[inline] #[stable(feature = "once_wait", since = "1.86.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn wait(&self) -> &T { self.once.wait_force(); @@ -263,7 +263,7 @@ impl OnceLock { /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn set(&self, value: T) -> Result<(), T> { match self.try_insert(value) { Ok(_) => Ok(()), @@ -303,7 +303,7 @@ impl OnceLock { /// ``` #[inline] #[unstable(feature = "once_cell_try_insert", issue = "116693")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { let mut value = Some(value); let res = self.get_or_init(|| value.take().unwrap()); @@ -342,7 +342,7 @@ impl OnceLock { /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> T, @@ -423,7 +423,7 @@ impl OnceLock { /// ``` #[inline] #[unstable(feature = "once_cell_try", issue = "109737")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs index fa9e1caada59b..68961ced741ea 100644 --- a/library/std/src/sync/poison/condvar.rs +++ b/library/std/src/sync/poison/condvar.rs @@ -121,7 +121,7 @@ impl Condvar { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult> { let poisoned = unsafe { let lock = mutex::guard_lock(&guard); @@ -178,7 +178,7 @@ impl Condvar { /// let _guard = cvar.wait_while(lock.lock().unwrap(), |pending| { *pending }).unwrap(); /// ``` #[stable(feature = "wait_until", since = "1.42.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn wait_while<'a, T, F>( &self, mut guard: MutexGuard<'a, T>, @@ -247,7 +247,7 @@ impl Condvar { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] #[deprecated(since = "1.6.0", note = "replaced by `std::sync::Condvar::wait_timeout`")] pub fn wait_timeout_ms<'a, T>( &self, @@ -319,7 +319,7 @@ impl Condvar { /// } /// ``` #[stable(feature = "wait_timeout", since = "1.5.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn wait_timeout<'a, T>( &self, guard: MutexGuard<'a, T>, @@ -386,7 +386,7 @@ impl Condvar { /// // access the locked mutex via result.0 /// ``` #[stable(feature = "wait_timeout_until", since = "1.42.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn wait_timeout_while<'a, T, F>( &self, mut guard: MutexGuard<'a, T>, @@ -447,7 +447,7 @@ impl Condvar { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn notify_one(&self) { self.inner.notify_one() } @@ -488,7 +488,7 @@ impl Condvar { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn notify_all(&self) { self.inner.notify_all() } diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 2bb4af20140cd..f641535363cc5 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -407,7 +407,7 @@ impl Mutex { /// assert_eq!(mutex.get_cloned().unwrap(), 11); /// ``` #[unstable(feature = "lock_value_accessors", issue = "133407")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn set(&self, value: T) -> Result<(), PoisonError> { if mem::needs_drop::() { // If the contained value has non-trivial destructor, we @@ -445,7 +445,7 @@ impl Mutex { /// assert_eq!(mutex.get_cloned().unwrap(), 11); /// ``` #[unstable(feature = "lock_value_accessors", issue = "133407")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn replace(&self, value: T) -> LockResult { match self.lock() { Ok(mut guard) => Ok(mem::replace(&mut *guard, value)), @@ -492,7 +492,7 @@ impl Mutex { /// assert_eq!(*mutex.lock().unwrap(), 10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn lock(&self) -> LockResult> { unsafe { self.inner.lock(); @@ -541,7 +541,7 @@ impl Mutex { /// assert_eq!(*mutex.lock().unwrap(), 10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn try_lock(&self) -> TryLockResult> { unsafe { if self.inner.try_lock() { @@ -612,7 +612,7 @@ impl Mutex { /// ``` #[inline] #[stable(feature = "mutex_unpoison", since = "1.77.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn clear_poison(&self) { self.poison.clear(); } diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 686ac71d8227b..d934bc30ac007 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -323,7 +323,7 @@ impl RwLock { /// assert_eq!(lock.get_cloned().unwrap(), 11); /// ``` #[unstable(feature = "lock_value_accessors", issue = "133407")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn set(&self, value: T) -> Result<(), PoisonError> { if mem::needs_drop::() { // If the contained value has non-trivial destructor, we @@ -362,7 +362,7 @@ impl RwLock { /// assert_eq!(lock.get_cloned().unwrap(), 11); /// ``` #[unstable(feature = "lock_value_accessors", issue = "133407")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn replace(&self, value: T) -> LockResult { match self.write() { Ok(mut guard) => Ok(mem::replace(&mut *guard, value)), @@ -416,7 +416,7 @@ impl RwLock { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn read(&self) -> LockResult> { unsafe { self.inner.read(); @@ -463,7 +463,7 @@ impl RwLock { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn try_read(&self) -> TryLockResult> { unsafe { if self.inner.try_read() { @@ -509,7 +509,7 @@ impl RwLock { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn write(&self) -> LockResult> { unsafe { self.inner.write(); @@ -557,7 +557,7 @@ impl RwLock { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_should_not_be_called_on_const_items] + #[lint::should_not_be_called_on_const_items] pub fn try_write(&self) -> TryLockResult> { unsafe { if self.inner.try_write() { diff --git a/tests/ui/lint_helper_namespace/feature_gates.rs b/tests/ui/lint_helper_namespace/feature_gates.rs index d5e1008f89f57..045b75104c68c 100644 --- a/tests/ui/lint_helper_namespace/feature_gates.rs +++ b/tests/ui/lint_helper_namespace/feature_gates.rs @@ -2,8 +2,13 @@ #![feature(register_tool)] #![register_tool(lint)] -#[lint::as_ptr] //~ ERROR use of an internal attribute -#[lint::never_returns_null_ptr] //~ ERROR use of an internal attribute -fn cast(x: &u8) -> *const u8 { - x +struct X; + +impl X { + #[lint::as_ptr] //~ ERROR use of an internal attribute + #[lint::never_returns_null_ptr] //~ ERROR use of an internal attribute + #[lint::should_not_be_called_on_const_items] //~ ERROR use of an internal attribute + fn cast(x: &u8) -> *const u8 { + x + } } diff --git a/tests/ui/lint_helper_namespace/feature_gates.stderr b/tests/ui/lint_helper_namespace/feature_gates.stderr index 0bed2a048ab23..9200a09a93db5 100644 --- a/tests/ui/lint_helper_namespace/feature_gates.stderr +++ b/tests/ui/lint_helper_namespace/feature_gates.stderr @@ -1,21 +1,30 @@ error[E0658]: use of an internal attribute - --> $DIR/feature_gates.rs:5:3 + --> $DIR/feature_gates.rs:8:7 | -LL | #[lint::as_ptr] - | ^^^^^^^^^^^^ +LL | #[lint::as_ptr] + | ^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: the `lint::as_ptr` attribute is an internal implementation detail that will never be stable error[E0658]: use of an internal attribute - --> $DIR/feature_gates.rs:6:3 + --> $DIR/feature_gates.rs:9:7 | -LL | #[lint::never_returns_null_ptr] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[lint::never_returns_null_ptr] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: the `lint::never_returns_null_ptr` attribute is an internal implementation detail that will never be stable -error: aborting due to 2 previous errors +error[E0658]: use of an internal attribute + --> $DIR/feature_gates.rs:10:7 + | +LL | #[lint::should_not_be_called_on_const_items] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `lint::should_not_be_called_on_const_items` attribute is an internal implementation detail that will never be stable + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. From dc85ea8603dc4236136dcc6e2ee511db54f3bf1d Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 29 Oct 2026 00:41:38 +0100 Subject: [PATCH 29/31] Remove duplicate symbol --- src/tools/clippy/clippy_utils/src/sym.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index e7d1e60018a06..11d7ecb2af386 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -158,7 +158,6 @@ generate! { as_mut_ptr, as_mut_slice, as_path, - as_ptr, as_slice, as_str, assert_failed, From ce0826ead59ea81eb4f0ae1586ca36231b8092f9 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 3 Nov 2026 10:48:16 +0100 Subject: [PATCH 30/31] fix formatting --- library/alloc/src/boxed.rs | 1 - library/alloc/src/vec/mod.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 76ab66ae0fa2e..0e85e16eda5b3 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1965,7 +1965,6 @@ impl Box { #[inline] #[lint::as_ptr] #[lint::never_returns_null_ptr] - pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing // any references. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index aa9a1c367041d..b23b328872fc4 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1884,7 +1884,6 @@ impl Vec { #[inline] #[lint::as_ptr] #[lint::never_returns_null_ptr] - pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through // `deref`, which creates an intermediate reference. From 9f004127aabfa6fadd92f6dd108d1d5b78fd4f58 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 3 Nov 2026 13:43:33 +0300 Subject: [PATCH 31/31] Rework parallel reproducibility tests --- src/tools/run-make-support/src/lib.rs | 1 + src/tools/run-make-support/src/parallel.rs | 31 +++++++ .../main.rs} | 0 .../async-fn-issue-162202/rmake.rs | 22 +++++ .../by-move-body/main.rs} | 0 .../by-move-body/rmake.rs | 21 +++++ .../main.rs} | 0 .../derives-issue-129094/rmake.rs | 12 +++ .../main.rs} | 0 .../generics-of-issue-163878/rmake.rs | 21 +++++ .../inline-asm-cookie-issue-150451/main.rs} | 0 .../inline-asm-cookie-issue-150451/rmake.rs | 21 +++++ .../parallel-reproducible-build/rmake.rs | 89 ------------------- .../main.rs} | 0 .../rpit-issue-162202/rmake.rs | 22 +++++ .../main.rs} | 0 .../static-muts-issue-140413/rmake.rs | 12 +++ .../main.rs} | 0 .../static-muts-lib-issue-162203/rmake.rs | 22 +++++ .../rmake.rs | 65 -------------- .../rmake.rs | 44 --------- 21 files changed, 185 insertions(+), 198 deletions(-) create mode 100644 src/tools/run-make-support/src/parallel.rs rename tests/run-make/parallel-reproducible-build/{async-fns-issue-162202.rs => async-fn-issue-162202/main.rs} (100%) create mode 100644 tests/run-make/parallel-reproducible-build/async-fn-issue-162202/rmake.rs rename tests/run-make/{parallel-reproducible-by-move-body/by-move-body.rs => parallel-reproducible-build/by-move-body/main.rs} (100%) create mode 100644 tests/run-make/parallel-reproducible-build/by-move-body/rmake.rs rename tests/run-make/parallel-reproducible-build/{derives-issue-129094.rs => derives-issue-129094/main.rs} (100%) create mode 100644 tests/run-make/parallel-reproducible-build/derives-issue-129094/rmake.rs rename tests/run-make/parallel-reproducible-build/{generics-of-issue-163878.rs => generics-of-issue-163878/main.rs} (100%) create mode 100644 tests/run-make/parallel-reproducible-build/generics-of-issue-163878/rmake.rs rename tests/run-make/{parallel-reproducible-inline-asm-cookie/inline-asm-cookie-issue-150451.rs => parallel-reproducible-build/inline-asm-cookie-issue-150451/main.rs} (100%) create mode 100644 tests/run-make/parallel-reproducible-build/inline-asm-cookie-issue-150451/rmake.rs delete mode 100644 tests/run-make/parallel-reproducible-build/rmake.rs rename tests/run-make/parallel-reproducible-build/{rpit-issue-162202.rs => rpit-issue-162202/main.rs} (100%) create mode 100644 tests/run-make/parallel-reproducible-build/rpit-issue-162202/rmake.rs rename tests/run-make/parallel-reproducible-build/{static-muts-issue-140413.rs => static-muts-issue-140413/main.rs} (100%) create mode 100644 tests/run-make/parallel-reproducible-build/static-muts-issue-140413/rmake.rs rename tests/run-make/parallel-reproducible-build/{static-muts-lib-issue-162203.rs => static-muts-lib-issue-162203/main.rs} (100%) create mode 100644 tests/run-make/parallel-reproducible-build/static-muts-lib-issue-162203/rmake.rs delete mode 100644 tests/run-make/parallel-reproducible-by-move-body/rmake.rs delete mode 100644 tests/run-make/parallel-reproducible-inline-asm-cookie/rmake.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 0d6bdf48dd88d..f93677d80fe6e 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -17,6 +17,7 @@ pub mod env; pub mod external_deps; pub mod linker; pub mod obj; +pub mod parallel; pub mod path_helpers; pub mod run; pub mod scoped_run; diff --git a/src/tools/run-make-support/src/parallel.rs b/src/tools/run-make-support/src/parallel.rs new file mode 100644 index 0000000000000..c07e8660df9f1 --- /dev/null +++ b/src/tools/run-make-support/src/parallel.rs @@ -0,0 +1,31 @@ +use std::rc::Rc; + +use crate::{bin_name, is_windows_msvc, rfs, run_in_tmpdir, rustc}; + +pub fn check_reproducibility(file: &str, args: &[&str]) { + let mut reference = None; + let bin_name = bin_name(file); + + for _ in 0..10 { + // Tmp dir as previous runs affect output binary on windows. + run_in_tmpdir(|| { + let mut rustc = rustc(); + rustc.input(format!("{file}.rs")).output(&bin_name); + + for arg in args { + rustc.arg(arg); + } + + if is_windows_msvc() { + rustc.arg("-Clink-arg=/Brepro"); + } + + rustc.run(); + + let current = Rc::new(rfs::read(&bin_name)); + reference.get_or_insert(Rc::clone(¤t)); + + assert_eq!(Some(current), reference); + }); + } +} diff --git a/tests/run-make/parallel-reproducible-build/async-fns-issue-162202.rs b/tests/run-make/parallel-reproducible-build/async-fn-issue-162202/main.rs similarity index 100% rename from tests/run-make/parallel-reproducible-build/async-fns-issue-162202.rs rename to tests/run-make/parallel-reproducible-build/async-fn-issue-162202/main.rs diff --git a/tests/run-make/parallel-reproducible-build/async-fn-issue-162202/rmake.rs b/tests/run-make/parallel-reproducible-build/async-fn-issue-162202/rmake.rs new file mode 100644 index 0000000000000..1512b258fc741 --- /dev/null +++ b/tests/run-make/parallel-reproducible-build/async-fn-issue-162202/rmake.rs @@ -0,0 +1,22 @@ +//@ needs-target-std +//@ ignore-cross-compile +// FIXME: remove the ignore gcc once fixed. +//@ ignore-backends: gcc +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use run_make_support::parallel::check_reproducibility; + +fn main() { + check_reproducibility( + "main", + &[ + "-Zthreads=30", + "--crate-type=lib", + "--crate-name=test", + "-Ccodegen-units=1", + "-Zremap-cwd-prefix=reproducible_dir", + "--edition=2024", + ], + ); +} diff --git a/tests/run-make/parallel-reproducible-by-move-body/by-move-body.rs b/tests/run-make/parallel-reproducible-build/by-move-body/main.rs similarity index 100% rename from tests/run-make/parallel-reproducible-by-move-body/by-move-body.rs rename to tests/run-make/parallel-reproducible-build/by-move-body/main.rs diff --git a/tests/run-make/parallel-reproducible-build/by-move-body/rmake.rs b/tests/run-make/parallel-reproducible-build/by-move-body/rmake.rs new file mode 100644 index 0000000000000..14d11507d9ec2 --- /dev/null +++ b/tests/run-make/parallel-reproducible-build/by-move-body/rmake.rs @@ -0,0 +1,21 @@ +//@ needs-target-std +//@ ignore-cross-compile +// FIXME: remove the ignore gcc once fixed. +//@ ignore-backends: gcc +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use run_make_support::parallel::check_reproducibility; + +fn main() { + check_reproducibility( + "main", + &[ + "--edition=2021", + "-Zremap-cwd-prefix=reproducible_dir", + "-Ccodegen-units=1", + "-Zthreads=2", + "--crate-type=lib", + ], + ); +} diff --git a/tests/run-make/parallel-reproducible-build/derives-issue-129094.rs b/tests/run-make/parallel-reproducible-build/derives-issue-129094/main.rs similarity index 100% rename from tests/run-make/parallel-reproducible-build/derives-issue-129094.rs rename to tests/run-make/parallel-reproducible-build/derives-issue-129094/main.rs diff --git a/tests/run-make/parallel-reproducible-build/derives-issue-129094/rmake.rs b/tests/run-make/parallel-reproducible-build/derives-issue-129094/rmake.rs new file mode 100644 index 0000000000000..e01d4c08f31d0 --- /dev/null +++ b/tests/run-make/parallel-reproducible-build/derives-issue-129094/rmake.rs @@ -0,0 +1,12 @@ +//@ needs-target-std +//@ ignore-cross-compile +// FIXME: remove the ignore gcc once fixed. +//@ ignore-backends: gcc +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use run_make_support::parallel::check_reproducibility; + +fn main() { + check_reproducibility("main", &["-Zthreads=16", "-Copt-level=3"]); +} diff --git a/tests/run-make/parallel-reproducible-build/generics-of-issue-163878.rs b/tests/run-make/parallel-reproducible-build/generics-of-issue-163878/main.rs similarity index 100% rename from tests/run-make/parallel-reproducible-build/generics-of-issue-163878.rs rename to tests/run-make/parallel-reproducible-build/generics-of-issue-163878/main.rs diff --git a/tests/run-make/parallel-reproducible-build/generics-of-issue-163878/rmake.rs b/tests/run-make/parallel-reproducible-build/generics-of-issue-163878/rmake.rs new file mode 100644 index 0000000000000..4b1cf2e2b5fb1 --- /dev/null +++ b/tests/run-make/parallel-reproducible-build/generics-of-issue-163878/rmake.rs @@ -0,0 +1,21 @@ +//@ needs-target-std +//@ ignore-cross-compile +// FIXME: remove the ignore gcc once fixed. +//@ ignore-backends: gcc +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use run_make_support::parallel::check_reproducibility; + +fn main() { + check_reproducibility( + "main", + &[ + "-Zthreads=2", + "--edition=2024", + "-Zremap-cwd-prefix=reproducible_dir", + "-Ccodegen-units=1", + "--crate-type=lib", + ], + ); +} diff --git a/tests/run-make/parallel-reproducible-inline-asm-cookie/inline-asm-cookie-issue-150451.rs b/tests/run-make/parallel-reproducible-build/inline-asm-cookie-issue-150451/main.rs similarity index 100% rename from tests/run-make/parallel-reproducible-inline-asm-cookie/inline-asm-cookie-issue-150451.rs rename to tests/run-make/parallel-reproducible-build/inline-asm-cookie-issue-150451/main.rs diff --git a/tests/run-make/parallel-reproducible-build/inline-asm-cookie-issue-150451/rmake.rs b/tests/run-make/parallel-reproducible-build/inline-asm-cookie-issue-150451/rmake.rs new file mode 100644 index 0000000000000..bdc8d4c8878e0 --- /dev/null +++ b/tests/run-make/parallel-reproducible-build/inline-asm-cookie-issue-150451/rmake.rs @@ -0,0 +1,21 @@ +//@ needs-target-std +//@ ignore-cross-compile +// FIXME: remove the ignore gcc once fixed. +//@ ignore-backends: gcc +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use run_make_support::parallel::check_reproducibility; + +fn main() { + check_reproducibility( + "main", + &[ + "--crate-type=lib", + "-Zthreads=3", + "-Clink-dead-code=true", + "-Copt-level=0", + "-Cembed-bitcode=true", + ], + ); +} diff --git a/tests/run-make/parallel-reproducible-build/rmake.rs b/tests/run-make/parallel-reproducible-build/rmake.rs deleted file mode 100644 index 24c441aa9bd32..0000000000000 --- a/tests/run-make/parallel-reproducible-build/rmake.rs +++ /dev/null @@ -1,89 +0,0 @@ -//@ needs-target-std -//@ ignore-cross-compile -// FIXME: remove the ignore gcc once fixed. -//@ ignore-backends: gcc -//@ ignore-windows-gnu -// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) - -use std::rc::Rc; - -use run_make_support::{bin_name, is_windows_msvc, rfs, run_in_tmpdir, rustc}; - -/// Test that parallel compiler produces identical artifacts (binaries, metadata). -fn main() { - const TESTS: &[(&str, &[&str])] = &[ - ("static-muts-issue-140413", &["-Zthreads=50"]), - ("derives-issue-129094", &["-Zthreads=16", "-Copt-level=3"]), - ( - "async-fns-issue-162202", - &[ - "-Zthreads=30", - "--crate-type=lib", - "--crate-name=test", - "-Ccodegen-units=1", - "-Zremap-cwd-prefix=reproducible_dir", - "--edition=2024", - ], - ), - ( - "rpit-issue-162202", - &[ - "-Zthreads=30", - "--crate-type=lib", - "--crate-name=test", - "-Ccodegen-units=1", - "-Zremap-cwd-prefix=reproducible_dir", - "--edition=2024", - ], - ), - ( - "static-muts-lib-issue-162203", - &[ - "-Zthreads=30", - "--edition=2024", - "-Zremap-cwd-prefix=reproducible_dir", - "--cap-lints=warn", - "-Ccodegen-units=1", - "-Clink-dead-code=true", - ], - ), - ( - "generics-of-issue-163878", - &[ - "-Zthreads=2", - "--edition=2024", - "-Zremap-cwd-prefix=reproducible_dir", - "-Ccodegen-units=1", - "--crate-type=lib", - ], - ), - ]; - - for (file, args) in TESTS { - let mut reference = None; - let bin_name = bin_name(file); - - for _ in 0..10 { - // Tmp dir as previous runs affect output binary on windows. - run_in_tmpdir(|| { - let mut rustc = rustc(); - rustc.input(format!("{file}.rs")).output(&bin_name); - - for arg in *args { - rustc.arg(arg); - } - - if is_windows_msvc() { - rustc.arg("-Clink-arg=/Brepro"); - } - - rustc.run(); - - let current = Rc::new(rfs::read(&bin_name)); - reference.get_or_insert(Rc::clone(¤t)); - - assert_eq!(Some(current), reference); - }); - } - } -} diff --git a/tests/run-make/parallel-reproducible-build/rpit-issue-162202.rs b/tests/run-make/parallel-reproducible-build/rpit-issue-162202/main.rs similarity index 100% rename from tests/run-make/parallel-reproducible-build/rpit-issue-162202.rs rename to tests/run-make/parallel-reproducible-build/rpit-issue-162202/main.rs diff --git a/tests/run-make/parallel-reproducible-build/rpit-issue-162202/rmake.rs b/tests/run-make/parallel-reproducible-build/rpit-issue-162202/rmake.rs new file mode 100644 index 0000000000000..1512b258fc741 --- /dev/null +++ b/tests/run-make/parallel-reproducible-build/rpit-issue-162202/rmake.rs @@ -0,0 +1,22 @@ +//@ needs-target-std +//@ ignore-cross-compile +// FIXME: remove the ignore gcc once fixed. +//@ ignore-backends: gcc +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use run_make_support::parallel::check_reproducibility; + +fn main() { + check_reproducibility( + "main", + &[ + "-Zthreads=30", + "--crate-type=lib", + "--crate-name=test", + "-Ccodegen-units=1", + "-Zremap-cwd-prefix=reproducible_dir", + "--edition=2024", + ], + ); +} diff --git a/tests/run-make/parallel-reproducible-build/static-muts-issue-140413.rs b/tests/run-make/parallel-reproducible-build/static-muts-issue-140413/main.rs similarity index 100% rename from tests/run-make/parallel-reproducible-build/static-muts-issue-140413.rs rename to tests/run-make/parallel-reproducible-build/static-muts-issue-140413/main.rs diff --git a/tests/run-make/parallel-reproducible-build/static-muts-issue-140413/rmake.rs b/tests/run-make/parallel-reproducible-build/static-muts-issue-140413/rmake.rs new file mode 100644 index 0000000000000..034b22d5bfaa2 --- /dev/null +++ b/tests/run-make/parallel-reproducible-build/static-muts-issue-140413/rmake.rs @@ -0,0 +1,12 @@ +//@ needs-target-std +//@ ignore-cross-compile +// FIXME: remove the ignore gcc once fixed. +//@ ignore-backends: gcc +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use run_make_support::parallel::check_reproducibility; + +fn main() { + check_reproducibility("main", &["-Zthreads=50"]); +} diff --git a/tests/run-make/parallel-reproducible-build/static-muts-lib-issue-162203.rs b/tests/run-make/parallel-reproducible-build/static-muts-lib-issue-162203/main.rs similarity index 100% rename from tests/run-make/parallel-reproducible-build/static-muts-lib-issue-162203.rs rename to tests/run-make/parallel-reproducible-build/static-muts-lib-issue-162203/main.rs diff --git a/tests/run-make/parallel-reproducible-build/static-muts-lib-issue-162203/rmake.rs b/tests/run-make/parallel-reproducible-build/static-muts-lib-issue-162203/rmake.rs new file mode 100644 index 0000000000000..98ab480600474 --- /dev/null +++ b/tests/run-make/parallel-reproducible-build/static-muts-lib-issue-162203/rmake.rs @@ -0,0 +1,22 @@ +//@ needs-target-std +//@ ignore-cross-compile +// FIXME: remove the ignore gcc once fixed. +//@ ignore-backends: gcc +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use run_make_support::parallel::check_reproducibility; + +fn main() { + check_reproducibility( + "main", + &[ + "-Zthreads=30", + "--edition=2024", + "-Zremap-cwd-prefix=reproducible_dir", + "--cap-lints=warn", + "-Ccodegen-units=1", + "-Clink-dead-code=true", + ], + ); +} diff --git a/tests/run-make/parallel-reproducible-by-move-body/rmake.rs b/tests/run-make/parallel-reproducible-by-move-body/rmake.rs deleted file mode 100644 index 3e464c2baa380..0000000000000 --- a/tests/run-make/parallel-reproducible-by-move-body/rmake.rs +++ /dev/null @@ -1,65 +0,0 @@ -//@ needs-target-std -//@ ignore-cross-compile -//@ ignore-windows-gnu -// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) - -use std::rc::Rc; - -use run_make_support::{rfs, run_in_tmpdir, rustc}; - -/// Test that parallel compiler produces identical metadata for the -/// `DefId`s synthesized on demand by `coroutine_by_move_body_def_id` -/// (`DefKind::SyntheticCoroutineBody`), across many async closures that -/// each need one. -fn main() { - const FILE_NAME: &str = "by-move-body"; - let rmeta_name = format!("{FILE_NAME}.rmeta"); - - let mut reference = None; - let mut reference_stderr = None; - - for _ in 0..10 { - // Tmp dir as previous runs affect output binary on windows. - run_in_tmpdir(|| { - let mut rustc = rustc(); - rustc - .input(format!("{FILE_NAME}.rs")) - .arg("--edition=2021") - .arg("-Zremap-cwd-prefix=reproducible_dir") - .arg("-Ccodegen-units=1") - .arg("-Zthreads=2") - .arg("--crate-type=lib") - .emit("metadata") - .output(&rmeta_name); - - let current_stderr = rustc.run().stderr_utf8(); - - let current = Rc::new(rfs::read(&rmeta_name)); - reference.get_or_insert(Rc::clone(¤t)); - let reference_stderr = reference_stderr.get_or_insert_with(|| current_stderr.clone()); - - if Some(current.clone()) != reference { - let reference_bytes = reference.as_ref().unwrap(); - let (pos, (left_byte, right_byte)) = current - .iter() - .zip(reference_bytes.iter()) - .enumerate() - .find(|(_, (c, r))| c != r) - .unwrap(); - let range_start = pos.saturating_sub(1); - let range_end = (pos + 3).min(current.len()).min(reference_bytes.len()); - panic!( - "left: {current:x?}\nright: {reference:x?}\n \ - differs at byte {pos}: left = {left_byte:#x}, right = {right_byte:#x}\n\ - left range [{range_start}..{range_end}]: {:x?}\n\ - right range [{range_start}..{range_end}]: {:x?}\n\ - left stderr:\n{current_stderr}\n\ - right stderr:\n{reference_stderr}", - ¤t[range_start..range_end], - &reference_bytes[range_start..range_end], - ) - } - assert_eq!(Some(current), reference); - }); - } -} diff --git a/tests/run-make/parallel-reproducible-inline-asm-cookie/rmake.rs b/tests/run-make/parallel-reproducible-inline-asm-cookie/rmake.rs deleted file mode 100644 index 5f4be53c6edf5..0000000000000 --- a/tests/run-make/parallel-reproducible-inline-asm-cookie/rmake.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@ needs-target-std -//@ ignore-cross-compile -// FIXME: remove the ignore gcc once fixed. -//@ ignore-backends: gcc -//@ ignore-windows-gnu -// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) - -use std::rc::Rc; - -use run_make_support::{bin_name, is_windows_msvc, rfs, run_in_tmpdir, rustc}; - -/// Test that parallel compiler produces identical binaries. -fn main() { - const FILE_NAME: &str = "inline-asm-cookie-issue-150451"; - let bin_name = bin_name(FILE_NAME); - - let mut reference = None; - - for _ in 0..10 { - // Tmp dir as previous runs affect output binary on windows. - run_in_tmpdir(|| { - let mut rustc = rustc(); - rustc - .input(format!("{FILE_NAME}.rs")) - .arg("--crate-type=lib") - .arg("-Zthreads=3") - .arg("-Clink-dead-code=true") - .arg("-Copt-level=0") - .arg("-Cembed-bitcode=true") - .output(&bin_name); - - if is_windows_msvc() { - rustc.arg("-Clink-arg=/Brepro"); - } - - rustc.run(); - - let current = Rc::new(rfs::read(&bin_name)); - reference.get_or_insert(Rc::clone(¤t)); - - assert_eq!(Some(current), reference); - }); - } -}