From b719a60aea9e03258c03a6562ec9428952445880 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 12 May 2025 18:43:00 +0200 Subject: [PATCH 01/29] Specify that split_ascii_whitespace uses the same definition as is_ascii_whitespace --- core/src/str/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index dafabba645c61..0123e52f5470c 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -1172,6 +1172,7 @@ impl str { /// The iterator returned will return string slices that are sub-slices of /// the original string slice, separated by any amount of ASCII whitespace. /// + /// This uses the same definition as [`char::is_ascii_whitespace`]. /// To split by Unicode `Whitespace` instead, use [`split_whitespace`]. /// /// [`split_whitespace`]: str::split_whitespace @@ -1190,7 +1191,8 @@ impl str { /// assert_eq!(None, iter.next()); /// ``` /// - /// All kinds of ASCII whitespace are considered: + /// Various kinds of ASCII whitespace are considered + /// (see [`char::is_ascii_whitespace`]): /// /// ``` /// let mut iter = " Mary had\ta little \n\t lamb".split_ascii_whitespace(); From 5d7c5189ffb1aca7fe5a411a9316df3bc0e472f6 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 12 May 2025 18:49:36 +1000 Subject: [PATCH 02/29] Fix confusing WTF surrogate safety docs --- std/src/ffi/os_str.rs | 6 +++--- std/src/sys/os_str/wtf8.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index 72bdf03ee61a4..7f0033c196213 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -594,9 +594,9 @@ impl OsString { /// The slice must be valid for the platform encoding (as described in /// [`OsStr::from_encoded_bytes_unchecked`]). /// - /// This bypasses the encoding-dependent surrogate joining, so `self` must - /// not end with a leading surrogate half and `other` must not start with - /// with a trailing surrogate half. + /// This bypasses the encoding-dependent surrogate joining, so either + /// `self` must not end with a leading surrogate half, or `other` must not + /// start with a trailing surrogate half. #[inline] pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { // SAFETY: Guaranteed by caller. diff --git a/std/src/sys/os_str/wtf8.rs b/std/src/sys/os_str/wtf8.rs index 5174ea65d0cd9..892bd2e3de659 100644 --- a/std/src/sys/os_str/wtf8.rs +++ b/std/src/sys/os_str/wtf8.rs @@ -215,9 +215,9 @@ impl Buf { /// The slice must be valid for the platform encoding (as described in /// [`Slice::from_encoded_bytes_unchecked`]). /// - /// This bypasses the WTF-8 surrogate joining, so `self` must not end with a - /// leading surrogate half and `other` must not start with with a trailing - /// surrogate half. + /// This bypasses the WTF-8 surrogate joining, so either `self` must not + /// end with a leading surrogate half, or `other` must not start with a + /// trailing surrogate half. #[inline] pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); From fcfcd6ba752e62d43afe53714235b354f0181552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= <69964857+Sa4dUs@users.noreply.github.com> Date: Tue, 6 May 2025 09:19:33 +0200 Subject: [PATCH 03/29] Split `autodiff` into `autodiff_forward` and `autodiff_reverse` Pending fix. ``` error: cannot find a built-in macro with name `autodiff_forward` --> library\core\src\macros\mod.rs:1542:5 | 1542 | / pub macro autodiff_forward($item:item) { 1543 | | /* compiler built-in */ 1544 | | } | |_____^ error: cannot find a built-in macro with name `autodiff_reverse` --> library\core\src\macros\mod.rs:1549:5 | 1549 | / pub macro autodiff_reverse($item:item) { 1550 | | /* compiler built-in */ 1551 | | } | |_____^ error: could not compile `core` (lib) due to 2 previous errors ``` --- core/src/lib.rs | 2 +- core/src/macros/mod.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index e605d7e0d7844..aaa8c872f985c 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -229,7 +229,7 @@ pub mod assert_matches { /// Unstable module containing the unstable `autodiff` macro. pub mod autodiff { #[unstable(feature = "autodiff", issue = "124509")] - pub use crate::macros::builtin::autodiff; + pub use crate::macros::builtin::{autodiff_forward, autodiff_reverse}; } #[unstable(feature = "contracts", issue = "128044")] diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 7dc8c060cd5bc..dc50ad6a09076 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1536,6 +1536,20 @@ pub(crate) mod builtin { /* compiler built-in */ } + #[unstable(feature = "autodiff", issue = "124509")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + pub macro autodiff_forward($item:item) { + /* compiler built-in */ + } + + #[unstable(feature = "autodiff", issue = "124509")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + pub macro autodiff_reverse($item:item) { + /* compiler built-in */ + } + /// Asserts that a boolean expression is `true` at runtime. /// /// This will invoke the [`panic!`] macro if the provided expression cannot be From 486f309cd3456fa3d26ab0034e6fc9912e0dff04 Mon Sep 17 00:00:00 2001 From: Christopher Berner Date: Tue, 6 May 2025 20:18:06 -0700 Subject: [PATCH 04/29] Remove unnecessary handling of ERROR_IO_PENDING try_lock() and try_lock_shared() do not need to handle these per the discussion in https://github.com/rust-lang/rust/pull/140718#discussion_r2076678485 --- std/src/fs/tests.rs | 22 ++++++++++++++++++++++ std/src/sys/fs/windows.rs | 10 ++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index 46b0d832fec45..49f99351c8aaf 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -366,6 +366,28 @@ fn file_lock_blocking_async() { t.join().unwrap(); } +#[test] +#[cfg(windows)] +fn file_try_lock_async() { + const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; + + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_try_lock_async.txt"); + let f1 = check!(File::create(filename)); + let f2 = + check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(filename)); + + // Check that shared locks block exclusive locks + check!(f1.lock_shared()); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); + check!(f1.unlock()); + + // Check that exclusive locks block all locks + check!(f1.lock()); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); + assert_matches!(f2.try_lock_shared(), Err(TryLockError::WouldBlock)); +} + #[test] fn file_test_io_seek_shakedown() { // 01234567890123 diff --git a/std/src/sys/fs/windows.rs b/std/src/sys/fs/windows.rs index 9039fd00f5d62..d01a572ac7332 100644 --- a/std/src/sys/fs/windows.rs +++ b/std/src/sys/fs/windows.rs @@ -415,10 +415,7 @@ impl File { match result { Ok(_) => Ok(()), - Err(err) - if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) - || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => - { + Err(err) if err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => { Err(TryLockError::WouldBlock) } Err(err) => Err(TryLockError::Error(err)), @@ -440,10 +437,7 @@ impl File { match result { Ok(_) => Ok(()), - Err(err) - if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) - || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => - { + Err(err) if err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => { Err(TryLockError::WouldBlock) } Err(err) => Err(TryLockError::Error(err)), From f4fcacaf16a8574dfa961fadef61176afafb94f5 Mon Sep 17 00:00:00 2001 From: Christopher Berner Date: Tue, 20 May 2025 14:04:38 -0700 Subject: [PATCH 05/29] Add From for io::Error This makes error propagation from try_lock() and try_lock_shared() more convenient --- std/src/fs.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/std/src/fs.rs b/std/src/fs.rs index 11f439b9996de..4be52ac1eb386 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -392,6 +392,16 @@ impl fmt::Display for TryLockError { } } +#[unstable(feature = "file_lock", issue = "130994")] +impl From for io::Error { + fn from(err: TryLockError) -> io::Error { + match err { + TryLockError::Error(err) => err, + TryLockError::WouldBlock => io::ErrorKind::WouldBlock.into(), + } + } +} + impl File { /// Attempts to open a file in read-only mode. /// @@ -821,11 +831,14 @@ impl File { /// /// fn main() -> std::io::Result<()> { /// let f = File::create("foo.txt")?; + /// // Explicit handling of the WouldBlock error /// match f.try_lock() { /// Ok(_) => (), /// Err(TryLockError::WouldBlock) => (), // Lock not acquired /// Err(TryLockError::Error(err)) => return Err(err), /// } + /// // Alternately, propagate the error as an io::Error + /// f.try_lock()?; /// Ok(()) /// } /// ``` @@ -882,11 +895,14 @@ impl File { /// /// fn main() -> std::io::Result<()> { /// let f = File::open("foo.txt")?; + /// // Explicit handling of the WouldBlock error /// match f.try_lock_shared() { /// Ok(_) => (), /// Err(TryLockError::WouldBlock) => (), // Lock not acquired /// Err(TryLockError::Error(err)) => return Err(err), /// } + /// // Alternately, propagate the error as an io::Error + /// f.try_lock_shared()?; /// /// Ok(()) /// } From 87b0fac1be40125c5bab7b9c120fb462bb5bf07a Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 27 Apr 2025 16:18:29 +0200 Subject: [PATCH 06/29] Add data_ptr method to Mutex and RwLock --- std/src/sync/poison/mutex.rs | 6 ++++++ std/src/sync/poison/rwlock.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/std/src/sync/poison/mutex.rs b/std/src/sync/poison/mutex.rs index 1c29c619edc3a..372bf0a302929 100644 --- a/std/src/sync/poison/mutex.rs +++ b/std/src/sync/poison/mutex.rs @@ -608,6 +608,12 @@ impl Mutex { let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |()| data) } + + /// Returns a raw pointer to the underlying data. + #[unstable(feature = "mutex_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } } #[stable(feature = "mutex_from", since = "1.24.0")] diff --git a/std/src/sync/poison/rwlock.rs b/std/src/sync/poison/rwlock.rs index 6976c0a64e23f..0b32a2f1be153 100644 --- a/std/src/sync/poison/rwlock.rs +++ b/std/src/sync/poison/rwlock.rs @@ -634,6 +634,12 @@ impl RwLock { let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |()| data) } + + /// Returns a raw pointer to the underlying data. + #[unstable(feature = "rwlock_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } } #[stable(feature = "rust1", since = "1.0.0")] From fb83dec53fe7c9fafce222322abb5f506ae017d2 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 21 May 2025 08:05:44 +0200 Subject: [PATCH 07/29] Add more docs to new data_ptr methods --- std/src/sync/poison/mutex.rs | 5 +++++ std/src/sync/poison/rwlock.rs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/std/src/sync/poison/mutex.rs b/std/src/sync/poison/mutex.rs index 372bf0a302929..30325be685c32 100644 --- a/std/src/sync/poison/mutex.rs +++ b/std/src/sync/poison/mutex.rs @@ -610,6 +610,11 @@ impl Mutex { } /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads and writes through it + /// are properly synchronized to avoid data races, and that it is not read + /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] pub fn data_ptr(&self) -> *mut T { self.data.get() diff --git a/std/src/sync/poison/rwlock.rs b/std/src/sync/poison/rwlock.rs index 0b32a2f1be153..a060e2ea57a7b 100644 --- a/std/src/sync/poison/rwlock.rs +++ b/std/src/sync/poison/rwlock.rs @@ -636,6 +636,11 @@ impl RwLock { } /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads and writes through it + /// are properly synchronized to avoid data races, and that it is not read + /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] pub fn data_ptr(&self) -> *mut T { self.data.get() From dc6d9708c4416ba1bda38288d428426b2817e878 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 21 May 2025 08:06:04 +0200 Subject: [PATCH 08/29] Add ReentrantLock::data_ptr --- std/src/sync/reentrant_lock.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/std/src/sync/reentrant_lock.rs b/std/src/sync/reentrant_lock.rs index 96a4cf12659cc..727252f03a24e 100644 --- a/std/src/sync/reentrant_lock.rs +++ b/std/src/sync/reentrant_lock.rs @@ -349,6 +349,17 @@ impl ReentrantLock { } } + /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads through it are + /// properly synchronized to avoid data races, and that it is not read + /// through after the lock is dropped. + #[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *const T { + &raw const self.data + } + unsafe fn increment_lock_count(&self) -> Option<()> { unsafe { *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?; From b58a8484ea43a2e8421c57c4b0018618df58abd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 00:11:06 +0000 Subject: [PATCH 09/29] Disable autodiff bootstrapping --- core/src/lib.rs | 1 + core/src/macros/mod.rs | 40 +++++++++++++++++++++++----------------- std/src/lib.rs | 7 +++++-- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index aaa8c872f985c..e1982116994b4 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -226,6 +226,7 @@ pub mod assert_matches { // We don't export this through #[macro_export] for now, to avoid breakage. #[unstable(feature = "autodiff", issue = "124509")] +#[cfg(not(bootstrap))] /// Unstable module containing the unstable `autodiff` macro. pub mod autodiff { #[unstable(feature = "autodiff", issue = "124509")] diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index dc50ad6a09076..99a4ab52b6c57 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1519,33 +1519,39 @@ pub(crate) mod builtin { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } - /// Automatic Differentiation macro which allows generating a new function to compute - /// the derivative of a given function. It may only be applied to a function. - /// The expected usage syntax is - /// `#[autodiff(NAME, MODE, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` - /// where: - /// NAME is a string that represents a valid function name. - /// MODE is any of Forward, Reverse, ForwardFirst, ReverseFirst. - /// INPUT_ACTIVITIES consists of one valid activity for each input parameter. - /// OUTPUT_ACTIVITY must not be set if we implicitly return nothing (or explicitly return - /// `-> ()`). Otherwise it must be set to one of the allowed activities. - #[unstable(feature = "autodiff", issue = "124509")] - #[allow_internal_unstable(rustc_attrs)] - #[rustc_builtin_macro] - pub macro autodiff($item:item) { - /* compiler built-in */ - } - + /// the derivative of a given function in the forward mode of differentiation. + /// It may only be applied to a function. + /// + /// The expected usage syntax is: + /// `#[autodiff_forward(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` + /// + /// - `NAME`: A string that represents a valid function name. + /// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter. + /// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing + /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] + #[cfg(not(bootstrap))] pub macro autodiff_forward($item:item) { /* compiler built-in */ } + /// Automatic Differentiation macro which allows generating a new function to compute + /// the derivative of a given function in the reverse mode of differentiation. + /// It may only be applied to a function. + /// + /// The expected usage syntax is: + /// `#[autodiff_reverse(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` + /// + /// - `NAME`: A string that represents a valid function name. + /// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter. + /// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing + /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] + #[cfg(not(bootstrap))] pub macro autodiff_reverse($item:item) { /* compiler built-in */ } diff --git a/std/src/lib.rs b/std/src/lib.rs index ef41b47384d61..0ac674d989060 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -276,12 +276,12 @@ // tidy-alphabetical-start // stabilization was reverted after it hit beta +#![cfg_attr(not(bootstrap), feature(autodiff))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(asm_experimental_arch)] -#![feature(autodiff)] #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] @@ -636,12 +636,15 @@ pub mod simd { #[doc(inline)] pub use crate::std_float::StdFloat; } + #[unstable(feature = "autodiff", issue = "124509")] +#[cfg(not(bootstrap))] /// This module provides support for automatic differentiation. pub mod autodiff { /// This macro handles automatic differentiation. - pub use core::autodiff::autodiff; + pub use core::autodiff::{autodiff_forward, autodiff_reverse}; } + #[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks. From 2738601da474968eb90ae9df644466fc7ab0386c Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 27 Aug 2024 11:05:45 -0400 Subject: [PATCH 10/29] Add some track_caller info to precondition panics --- core/src/alloc/layout.rs | 1 + core/src/ascii/ascii_char.rs | 1 + core/src/char/convert.rs | 1 + core/src/hint.rs | 2 +- core/src/intrinsics/mod.rs | 2 +- core/src/num/int_macros.rs | 12 ++++++------ core/src/num/nonzero.rs | 2 ++ core/src/num/uint_macros.rs | 10 +++++----- core/src/ops/index_range.rs | 1 + core/src/ptr/alignment.rs | 1 + core/src/ptr/const_ptr.rs | 26 ++++++++++++------------ core/src/ptr/mod.rs | 14 +++++++------ core/src/ptr/mut_ptr.rs | 38 ++++++++++++++++++------------------ core/src/ptr/non_null.rs | 1 + core/src/slice/index.rs | 6 ++++++ core/src/slice/mod.rs | 8 ++++++++ core/src/slice/raw.rs | 3 +++ core/src/str/traits.rs | 4 ++++ core/src/ub_checks.rs | 6 ++++-- 19 files changed, 86 insertions(+), 53 deletions(-) diff --git a/core/src/alloc/layout.rs b/core/src/alloc/layout.rs index e8a03aadc3390..380f67f91f947 100644 --- a/core/src/alloc/layout.rs +++ b/core/src/alloc/layout.rs @@ -126,6 +126,7 @@ impl Layout { #[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")] #[must_use] #[inline] + #[track_caller] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { assert_unsafe_precondition!( check_library_ub, diff --git a/core/src/ascii/ascii_char.rs b/core/src/ascii/ascii_char.rs index 48de4f17b1b3a..0b72b4780f163 100644 --- a/core/src/ascii/ascii_char.rs +++ b/core/src/ascii/ascii_char.rs @@ -503,6 +503,7 @@ impl AsciiChar { /// something useful. It might be tightened before stabilization.) #[unstable(feature = "ascii_char", issue = "110998")] #[inline] + #[track_caller] pub const unsafe fn digit_unchecked(d: u8) -> Self { assert_unsafe_precondition!( check_language_ub, diff --git a/core/src/char/convert.rs b/core/src/char/convert.rs index fd17f92f7be08..78cd89fefae71 100644 --- a/core/src/char/convert.rs +++ b/core/src/char/convert.rs @@ -22,6 +22,7 @@ pub(super) const fn from_u32(i: u32) -> Option { #[inline] #[must_use] #[allow(unnecessary_transmutes)] +#[track_caller] pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the caller must guarantee that `i` is a valid char value. unsafe { diff --git a/core/src/hint.rs b/core/src/hint.rs index 6eefb30468931..435b610feb91a 100644 --- a/core/src/hint.rs +++ b/core/src/hint.rs @@ -98,7 +98,7 @@ use crate::{intrinsics, ub_checks}; #[inline] #[stable(feature = "unreachable", since = "1.27.0")] #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] pub const unsafe fn unreachable_unchecked() -> ! { ub_checks::assert_unsafe_precondition!( check_language_ub, diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 23bafa778bc6b..ca9f4f38bf39a 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -2634,7 +2634,7 @@ pub const fn three_way_compare(lhs: T, rhss: T) -> crate::cmp::Ordering #[rustc_const_unstable(feature = "disjoint_bitor", issue = "135758")] #[rustc_nounwind] #[rustc_intrinsic] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] #[miri::intrinsic_fallback_is_spec] // the fallbacks all `assume` to tell Miri pub const unsafe fn disjoint_bitor(a: T, b: T) -> T { // SAFETY: same preconditions as this function. diff --git a/core/src/num/int_macros.rs b/core/src/num/int_macros.rs index 84e1482ed31db..f320a194271eb 100644 --- a/core/src/num/int_macros.rs +++ b/core/src/num/int_macros.rs @@ -555,7 +555,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -705,7 +705,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -855,7 +855,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1199,7 +1199,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_neg(self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1327,7 +1327,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1448,7 +1448,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { assert_unsafe_precondition!( check_language_ub, diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 8a8b2733d5e88..a279f002772ea 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -388,6 +388,7 @@ where #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] #[must_use] #[inline] + #[track_caller] pub const unsafe fn new_unchecked(n: T) -> Self { match Self::new(n) { Some(n) => n, @@ -428,6 +429,7 @@ where #[unstable(feature = "nonzero_from_mut", issue = "106290")] #[must_use] #[inline] + #[track_caller] pub unsafe fn from_mut_unchecked(n: &mut T) -> &mut Self { match Self::from_mut(n) { Some(n) => n, diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index f38d809c1544b..10597854ff877 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -601,7 +601,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -791,7 +791,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -974,7 +974,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1588,7 +1588,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1709,7 +1709,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { assert_unsafe_precondition!( check_language_ub, diff --git a/core/src/ops/index_range.rs b/core/src/ops/index_range.rs index c645c996eb707..507fa9460bea6 100644 --- a/core/src/ops/index_range.rs +++ b/core/src/ops/index_range.rs @@ -19,6 +19,7 @@ impl IndexRange { /// # Safety /// - `start <= end` #[inline] + #[track_caller] pub(crate) const unsafe fn new_unchecked(start: usize, end: usize) -> Self { ub_checks::assert_unsafe_precondition!( check_library_ub, diff --git a/core/src/ptr/alignment.rs b/core/src/ptr/alignment.rs index 19311e39b454e..3e66e271f03b6 100644 --- a/core/src/ptr/alignment.rs +++ b/core/src/ptr/alignment.rs @@ -73,6 +73,7 @@ impl Alignment { /// It must *not* be zero. #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] + #[track_caller] pub const unsafe fn new_unchecked(align: usize) -> Self { assert_unsafe_precondition!( check_language_ub, diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index f6109cafe86b1..fe4eb48132dea 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -444,7 +444,7 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn offset(self, count: isize) -> *const T where T: Sized, @@ -497,7 +497,7 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { self.cast::().offset(count).with_metadata_of(self) } @@ -796,7 +796,7 @@ impl *const T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize where T: Sized, @@ -841,7 +841,7 @@ impl *const T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_offset_from_unsigned(self, origin: *const U) -> usize { // SAFETY: the caller must uphold the safety contract for `offset_from_unsigned`. unsafe { self.cast::().offset_from_unsigned(origin.cast::()) } @@ -955,7 +955,7 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -1007,7 +1007,7 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. unsafe { self.cast::().add(count).with_metadata_of(self) } @@ -1061,7 +1061,7 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -1119,7 +1119,7 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. unsafe { self.cast::().sub(count).with_metadata_of(self) } @@ -1292,7 +1292,7 @@ impl *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn read(self) -> T where T: Sized, @@ -1313,7 +1313,7 @@ impl *const T { /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1333,7 +1333,7 @@ impl *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1353,7 +1353,7 @@ impl *const T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_to(self, dest: *mut T, count: usize) where T: Sized, @@ -1373,7 +1373,7 @@ impl *const T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) where T: Sized, diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index 35a909f6904cd..99c4211cea862 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -1377,6 +1377,7 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { #[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "1.88.0")] #[rustc_diagnostic_item = "ptr_swap_nonoverlapping"] #[rustc_allow_const_fn_unstable(const_eval_select)] // both implementations behave the same +#[track_caller] pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { ub_checks::assert_unsafe_precondition!( check_library_ub, @@ -1557,6 +1558,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, bytes: NonZero(dst: *mut T, src: T) -> T { // SAFETY: the caller must guarantee that `dst` is valid to be // cast to a mutable reference (valid for writes, aligned, initialized), @@ -1684,7 +1686,7 @@ pub const unsafe fn replace(dst: *mut T, src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] #[rustc_diagnostic_item = "ptr_read"] pub const unsafe fn read(src: *const T) -> T { // It would be semantically correct to implement this via `copy_nonoverlapping` @@ -1802,7 +1804,7 @@ pub const unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] #[rustc_diagnostic_item = "ptr_read_unaligned"] pub const unsafe fn read_unaligned(src: *const T) -> T { let mut tmp = MaybeUninit::::uninit(); @@ -1901,7 +1903,7 @@ pub const unsafe fn read_unaligned(src: *const T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[rustc_diagnostic_item = "ptr_write"] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] pub const unsafe fn write(dst: *mut T, src: T) { // Semantically, it would be fine for this to be implemented as a // `copy_nonoverlapping` and appropriate drop suppression of `src`. @@ -2005,7 +2007,7 @@ pub const unsafe fn write(dst: *mut T, src: T) { #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[rustc_diagnostic_item = "ptr_write_unaligned"] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access @@ -2079,7 +2081,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { /// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] #[rustc_diagnostic_item = "ptr_read_volatile"] pub unsafe fn read_volatile(src: *const T) -> T { // SAFETY: the caller must uphold the safety contract for `volatile_load`. @@ -2160,7 +2162,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { #[inline] #[stable(feature = "volatile", since = "1.9.0")] #[rustc_diagnostic_item = "ptr_write_volatile"] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] pub unsafe fn write_volatile(dst: *mut T, src: T) { // SAFETY: the caller must uphold the safety contract for `volatile_store`. unsafe { diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 2662a4fdc3138..7a0452563f901 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -440,7 +440,7 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn offset(self, count: isize) -> *mut T where T: Sized, @@ -495,7 +495,7 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { self.cast::().offset(count).with_metadata_of(self) } @@ -970,7 +970,7 @@ impl *mut T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize where T: Sized, @@ -992,7 +992,7 @@ impl *mut T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_offset_from_unsigned(self, origin: *mut U) -> usize { // SAFETY: the caller must uphold the safety contract for `byte_offset_from_unsigned`. unsafe { (self as *const T).byte_offset_from_unsigned(origin) } @@ -1046,7 +1046,7 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -1098,7 +1098,7 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. unsafe { self.cast::().add(count).with_metadata_of(self) } @@ -1152,7 +1152,7 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -1210,7 +1210,7 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. unsafe { self.cast::().sub(count).with_metadata_of(self) } @@ -1377,7 +1377,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn read(self) -> T where T: Sized, @@ -1398,7 +1398,7 @@ impl *mut T { /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1418,7 +1418,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1438,7 +1438,7 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_to(self, dest: *mut T, count: usize) where T: Sized, @@ -1458,7 +1458,7 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) where T: Sized, @@ -1478,7 +1478,7 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_from(self, src: *const T, count: usize) where T: Sized, @@ -1498,7 +1498,7 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) where T: Sized, @@ -1528,7 +1528,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn write(self, val: T) where T: Sized, @@ -1547,7 +1547,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn write_bytes(self, val: u8, count: usize) where T: Sized, @@ -1568,7 +1568,7 @@ impl *mut T { /// [`ptr::write_volatile`]: crate::ptr::write_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub unsafe fn write_volatile(self, val: T) where T: Sized, @@ -1588,7 +1588,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn write_unaligned(self, val: T) where T: Sized, diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index bb344c6a0d316..1985526e4c970 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -216,6 +216,7 @@ impl NonNull { #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.25.0")] #[inline] + #[track_caller] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { // SAFETY: the caller must guarantee that `ptr` is non-null. unsafe { diff --git a/core/src/slice/index.rs b/core/src/slice/index.rs index aafa19c0dd3d3..644d22897deb6 100644 --- a/core/src/slice/index.rs +++ b/core/src/slice/index.rs @@ -239,6 +239,7 @@ unsafe impl SliceIndex<[T]> for usize { } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { assert_unsafe_precondition!( check_language_ub, @@ -258,6 +259,7 @@ unsafe impl SliceIndex<[T]> for usize { } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { assert_unsafe_precondition!( check_library_ub, @@ -307,6 +309,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { assert_unsafe_precondition!( check_library_ub, @@ -321,6 +324,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { assert_unsafe_precondition!( check_library_ub, @@ -386,6 +390,7 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { assert_unsafe_precondition!( check_library_ub, @@ -410,6 +415,7 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { assert_unsafe_precondition!( check_library_ub, diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index c9b8231e856c1..3339c71180d37 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -631,6 +631,7 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] + #[track_caller] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output where I: SliceIndex, @@ -674,6 +675,7 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] + #[track_caller] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where I: SliceIndex, @@ -935,6 +937,7 @@ impl [T] { /// [`swap`]: slice::swap /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[unstable(feature = "slice_swap_unchecked", issue = "88539")] + #[track_caller] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { assert_unsafe_precondition!( check_library_ub, @@ -1307,6 +1310,7 @@ impl [T] { #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[must_use] + #[track_caller] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { assert_unsafe_precondition!( check_language_ub, @@ -1502,6 +1506,7 @@ impl [T] { #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[must_use] + #[track_caller] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { assert_unsafe_precondition!( check_language_ub, @@ -2061,6 +2066,7 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")] #[inline] #[must_use] + #[track_caller] pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { // FIXME(const-hack): the const function `from_raw_parts` is used to make this // function const; previously the implementation used @@ -2114,6 +2120,7 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] #[inline] #[must_use] + #[track_caller] pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { let len = self.len(); let ptr = self.as_mut_ptr(); @@ -4642,6 +4649,7 @@ impl [T] { /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[stable(feature = "get_many_mut", since = "1.86.0")] #[inline] + #[track_caller] pub unsafe fn get_disjoint_unchecked_mut( &mut self, indices: [I; N], diff --git a/core/src/slice/raw.rs b/core/src/slice/raw.rs index 3582c7e8b3f38..40da69c15627d 100644 --- a/core/src/slice/raw.rs +++ b/core/src/slice/raw.rs @@ -120,6 +120,7 @@ use crate::{array, ptr, ub_checks}; #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] #[must_use] #[rustc_diagnostic_item = "slice_from_raw_parts"] +#[track_caller] pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { @@ -174,6 +175,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] #[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] #[must_use] #[rustc_diagnostic_item = "slice_from_raw_parts_mut"] +#[track_caller] pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. unsafe { @@ -270,6 +272,7 @@ pub const fn from_mut(s: &mut T) -> &mut [T] { /// [valid]: ptr#safety #[unstable(feature = "slice_from_ptr_range", issue = "89792")] #[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")] +#[track_caller] pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. unsafe { from_raw_parts(range.start, range.end.offset_from_unsigned(range.start)) } diff --git a/core/src/str/traits.rs b/core/src/str/traits.rs index 77c70b978fd15..4baf9aacad7b3 100644 --- a/core/src/str/traits.rs +++ b/core/src/str/traits.rs @@ -186,6 +186,7 @@ unsafe impl SliceIndex for ops::Range { } } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { let slice = slice as *const [u8]; @@ -213,6 +214,7 @@ unsafe impl SliceIndex for ops::Range { } } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { let slice = slice as *mut [u8]; @@ -288,6 +290,7 @@ unsafe impl SliceIndex for range::Range { } } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { let slice = slice as *const [u8]; @@ -315,6 +318,7 @@ unsafe impl SliceIndex for range::Range { } } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { let slice = slice as *mut [u8]; diff --git a/core/src/ub_checks.rs b/core/src/ub_checks.rs index 9eb71922218f3..a7caaeb95cdba 100644 --- a/core/src/ub_checks.rs +++ b/core/src/ub_checks.rs @@ -63,11 +63,13 @@ macro_rules! assert_unsafe_precondition { #[rustc_no_mir_inline] #[inline] #[rustc_nounwind] + #[track_caller] const fn precondition_check($($name:$ty),*) { if !$e { - ::core::panicking::panic_nounwind(concat!("unsafe precondition(s) violated: ", $message, + let msg = concat!("unsafe precondition(s) violated: ", $message, "\n\nThis indicates a bug in the program. \ - This Undefined Behavior check is optional, and cannot be relied on for safety.")); + This Undefined Behavior check is optional, and cannot be relied on for safety."); + ::core::panicking::panic_nounwind_fmt(::core::fmt::Arguments::new_const(&[msg]), false); } } From ea8398bb6c770b84bece212d3efdf23997faad44 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 17 Apr 2025 19:43:56 -0400 Subject: [PATCH 11/29] add CStr::display The implementation delegates to `::fmt`. Link: https://github.com/rust-lang/libs-team/issues/550 Link: https://github.com/rust-lang/rust/issues/139984. --- core/src/ffi/c_str.rs | 24 ++++++++++++++++++++++++ coretests/tests/ffi/cstr.rs | 6 ++++++ coretests/tests/lib.rs | 1 + 3 files changed, 31 insertions(+) diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index ac07c645c0195..c2799fa0b5c14 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -659,6 +659,30 @@ impl CStr { // instead of doing it afterwards. str::from_utf8(self.to_bytes()) } + + /// Returns an object that implements [`Display`] for safely printing a [`CStr`] that may + /// contain non-Unicode data. + /// + /// Behaves as if `self` were first lossily converted to a `str`, with invalid UTF-8 presented + /// as the Unicode replacement character: �. + /// + /// [`Display`]: fmt::Display + /// + /// # Examples + /// + /// ``` + /// #![feature(cstr_display)] + /// + /// let cstr = c"Hello, world!"; + /// println!("{}", cstr.display()); + /// ``` + #[unstable(feature = "cstr_display", issue = "139984")] + #[must_use = "this does not display the `CStr`; \ + it returns an object that can be displayed"] + #[inline] + pub fn display(&self) -> impl fmt::Display { + crate::bstr::ByteStr::from_bytes(self.to_bytes()) + } } // `.to_bytes()` representations are compared instead of the inner `[c_char]`s, diff --git a/coretests/tests/ffi/cstr.rs b/coretests/tests/ffi/cstr.rs index 0d85b22c585a1..dc34240cd99d2 100644 --- a/coretests/tests/ffi/cstr.rs +++ b/coretests/tests/ffi/cstr.rs @@ -19,3 +19,9 @@ fn debug() { let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF"; assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); } + +#[test] +fn display() { + let s = c"\xf0\x28\x8c\xbc"; + assert_eq!(format!("{}", s.display()), "�(��"); +} diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs index b13012009815c..693b14ef76209 100644 --- a/coretests/tests/lib.rs +++ b/coretests/tests/lib.rs @@ -23,6 +23,7 @@ #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] +#![feature(cstr_display)] #![feature(dec2flt)] #![feature(duration_constants)] #![feature(duration_constructors)] From c81153fafe52ca5f118955e920f13e3024cc3fab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 May 2025 15:06:08 +0200 Subject: [PATCH 12/29] intrinsics: reduce references to LLVM and update notes on where the implementations live --- core/src/intrinsics/mod.rs | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 23bafa778bc6b..439c8c1f9a1e6 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -1,7 +1,10 @@ //! Compiler intrinsics. //! -//! The corresponding definitions are in . -//! The corresponding const implementations are in . +//! These are the imports making intrinsics available to Rust code. The actual implementations live in the compiler. +//! Some of these intrinsics are lowered to MIR in . +//! The remaining intrinsics are implemented for the LLVM backend in +//! and , +//! and for const evaluation in . //! //! # Const intrinsics //! @@ -20,28 +23,14 @@ //! //! The volatile intrinsics provide operations intended to act on I/O //! memory, which are guaranteed to not be reordered by the compiler -//! across other volatile intrinsics. See the LLVM documentation on -//! [[volatile]]. -//! -//! [volatile]: https://llvm.org/docs/LangRef.html#volatile-memory-accesses +//! across other volatile intrinsics. See [`read_volatile`][ptr::read_volatile] +//! and [`write_volatile`][ptr::write_volatile]. //! //! # Atomics //! //! The atomic intrinsics provide common atomic operations on machine -//! words, with multiple possible memory orderings. They obey the same -//! semantics as C++11. See the LLVM documentation on [[atomics]]. -//! -//! [atomics]: https://llvm.org/docs/Atomics.html -//! -//! A quick refresher on memory ordering: -//! -//! * Acquire - a barrier for acquiring a lock. Subsequent reads and writes -//! take place after the barrier. -//! * Release - a barrier for releasing a lock. Preceding reads and writes -//! take place before the barrier. -//! * Sequentially consistent - sequentially consistent operations are -//! guaranteed to happen in order. This is the standard mode for working -//! with atomic types and is equivalent to Java's `volatile`. +//! words, with multiple possible memory orderings. See the +//! [atomic types][crate::sync::atomic] docs for details. //! //! # Unwinding //! From cb0eb797aadf64851befa8b43f34a91f0f8a053c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 24 May 2025 22:12:15 +0200 Subject: [PATCH 13/29] Path::with_extension: improve examples --- std/src/path.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/std/src/path.rs b/std/src/path.rs index 7959c63385816..0583ee1eb3274 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -2743,12 +2743,27 @@ impl Path { /// /// let path = Path::new("foo.rs"); /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt")); + /// assert_eq!(path.with_extension(""), PathBuf::from("foo")); + /// ``` + /// + /// Handling multiple extensions: + /// + /// ``` + /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("foo.tar.gz"); - /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar")); /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz")); /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt")); /// ``` + /// + /// Adding an extension where one did not exist: + /// + /// ``` + /// use std::path::{Path, PathBuf}; + /// + /// let path = Path::new("foo"); + /// assert_eq!(path.with_extension("rs"), PathBuf::from("foo.rs")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { self._with_extension(extension.as_ref()) From ffde7048bc4d95d15268df2dd1c34278ef2dfea5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 24 May 2025 22:17:55 +0200 Subject: [PATCH 14/29] reduce clutter... too many imports --- std/src/path.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/std/src/path.rs b/std/src/path.rs index 0583ee1eb3274..87c5d6f0438de 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -2739,30 +2739,30 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo.rs"); - /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt")); - /// assert_eq!(path.with_extension(""), PathBuf::from("foo")); + /// assert_eq!(path.with_extension("txt"), Path::new("foo.txt")); + /// assert_eq!(path.with_extension(""), Path::new("foo")); /// ``` /// /// Handling multiple extensions: /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo.tar.gz"); - /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz")); - /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt")); + /// assert_eq!(path.with_extension("xz"), Path::new("foo.tar.xz")); + /// assert_eq!(path.with_extension("").with_extension("txt"), Path::new("foo.txt")); /// ``` /// /// Adding an extension where one did not exist: /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo"); - /// assert_eq!(path.with_extension("rs"), PathBuf::from("foo.rs")); + /// assert_eq!(path.with_extension("rs"), Path::new("foo.rs")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { From 879762985a1a98ab325a5e5679dff6e1a4a2090f Mon Sep 17 00:00:00 2001 From: Fluid <90795031+fluiderson@users.noreply.github.com> Date: Fri, 23 May 2025 23:57:38 +0300 Subject: [PATCH 15/29] improve the `std::fs::create_dir_all` docs related to atomicity --- std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index 509e673bdb8b9..8047c0c03ad4f 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -2803,8 +2803,8 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// Recursively create a directory and all of its parent components if they /// are missing. /// -/// If this function returns an error, some of the parent components might have -/// been created already. +/// This function is not atomic. If it returns an error, any parent components it was able to create +/// will remain. /// /// If the empty path is passed to this function, it always succeeds without /// creating any directories. From 4c3aa3c42edd54c9e067c34bf462914542a64621 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 May 2025 09:24:28 +0200 Subject: [PATCH 16/29] clean up old rintf leftovers --- core/src/intrinsics/mod.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 23bafa778bc6b..e9fa3b1b3f649 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -2296,12 +2296,6 @@ pub fn round_ties_even_f16(x: f16) -> f16; #[rustc_nounwind] pub fn round_ties_even_f32(x: f32) -> f32; -/// Provided for compatibility with stdarch. DO NOT USE. -#[inline(always)] -pub unsafe fn rintf32(x: f32) -> f32 { - round_ties_even_f32(x) -} - /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number with an even /// least significant digit. /// @@ -2311,12 +2305,6 @@ pub unsafe fn rintf32(x: f32) -> f32 { #[rustc_nounwind] pub fn round_ties_even_f64(x: f64) -> f64; -/// Provided for compatibility with stdarch. DO NOT USE. -#[inline(always)] -pub unsafe fn rintf64(x: f64) -> f64 { - round_ties_even_f64(x) -} - /// Returns the nearest integer to an `f128`. Rounds half-way cases to the number with an even /// least significant digit. /// From d578eff1598c31ee6713bfc51bfc378b04d8058b Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 23 Dec 2024 15:09:51 +0000 Subject: [PATCH 17/29] Implement normalize lexically --- std/src/path.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++++ std/tests/path.rs | 56 +++++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/std/src/path.rs b/std/src/path.rs index 7959c63385816..2cdded1dfcf99 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -2154,6 +2154,13 @@ pub struct Path { #[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); +/// An error returned from [`Path::normalize_lexically`] if a `..` parent reference +/// would escape the path. +#[unstable(feature = "normalize_lexically", issue = "134694")] +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub struct NormalizeError; + impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. @@ -2961,6 +2968,67 @@ impl Path { fs::canonicalize(self) } + /// Normalize a path, including `..` without traversing the filesystem. + /// + /// Returns an error if normalization would leave leading `..` components. + /// + ///
+ /// + /// This function always resolves `..` to the "lexical" parent. + /// That is "a/b/../c" will always resolve to `a/c` which can change the meaning of the path. + /// In particular, `a/c` and `a/b/../c` are distinct on many systems because `b` may be a symbolic link, so its parent isn’t `a`. + /// + ///
+ /// + /// [`path::absolute`](absolute) is an alternative that preserves `..`. + /// Or [`Path::canonicalize`] can be used to resolve any `..` by querying the filesystem. + #[unstable(feature = "normalize_lexically", issue = "134694")] + pub fn normalize_lexically(&self) -> Result { + let mut lexical = PathBuf::new(); + let mut iter = self.components().peekable(); + + // Find the root, if any, and add it to the lexical path. + // Here we treat the Windows path "C:\" as a single "root" even though + // `components` splits it into two: (Prefix, RootDir). + let root = match iter.peek() { + Some(Component::ParentDir) => return Err(NormalizeError), + Some(p @ Component::RootDir) | Some(p @ Component::CurDir) => { + lexical.push(p); + iter.next(); + lexical.as_os_str().len() + } + Some(Component::Prefix(prefix)) => { + lexical.push(prefix.as_os_str()); + iter.next(); + if let Some(p @ Component::RootDir) = iter.peek() { + lexical.push(p); + iter.next(); + } + lexical.as_os_str().len() + } + None => return Ok(PathBuf::new()), + Some(Component::Normal(_)) => 0, + }; + + for component in iter { + match component { + Component::RootDir => unreachable!(), + Component::Prefix(_) => return Err(NormalizeError), + Component::CurDir => continue, + Component::ParentDir => { + // It's an error if ParentDir causes us to go above the "root". + if lexical.as_os_str().len() == root { + return Err(NormalizeError); + } else { + lexical.pop(); + } + } + Component::Normal(path) => lexical.push(path), + } + } + Ok(lexical) + } + /// Reads a symbolic link, returning the file that the link points to. /// /// This is an alias to [`fs::read_link`]. @@ -3502,6 +3570,15 @@ impl Error for StripPrefixError { } } +#[unstable(feature = "normalize_lexically", issue = "134694")] +impl fmt::Display for NormalizeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("parent reference `..` points outside of base directory") + } +} +#[unstable(feature = "normalize_lexically", issue = "134694")] +impl Error for NormalizeError {} + /// Makes the path absolute without accessing the filesystem. /// /// If the path is relative, the current directory is used as the base directory. diff --git a/std/tests/path.rs b/std/tests/path.rs index 87e0d226cbd31..781855a2d14aa 100644 --- a/std/tests/path.rs +++ b/std/tests/path.rs @@ -3,7 +3,8 @@ path_add_extension, path_file_prefix, maybe_uninit_slice, - os_string_pathbuf_leak + os_string_pathbuf_leak, + normalize_lexically )] use std::clone::CloneToUninit; @@ -2007,3 +2008,56 @@ fn test_embedded_newline() { assert_eq!(path.file_name(), Some(OsStr::new("foo\nbar"))); assert_eq!(path.to_str(), Some("foo\nbar")); } + +#[test] +fn normalize_lexically() { + #[track_caller] + fn check_ok(a: &str, b: &str) { + assert_eq!(Path::new(a).normalize_lexically().unwrap(), PathBuf::from(b)); + } + + #[track_caller] + fn check_err(a: &str) { + assert!(Path::new(a).normalize_lexically().is_err()); + } + + // Relative paths + check_ok("a", "a"); + check_ok("./a", "./a"); + check_ok("a/b/c", "a/b/c"); + check_ok("a/././b/./c/.", "a/b/c"); + check_ok("a/../c", "c"); + check_ok("./a/b", "./a/b"); + check_ok("a/../b/c/..", "b"); + + check_err(".."); + check_err("../.."); + check_err("a/../.."); + check_err("a/../../b"); + check_err("a/../../b/c"); + check_err("a/../b/../.."); + + // Check we don't escape the root or prefix + #[cfg(unix)] + { + check_err("/.."); + check_err("/a/../.."); + } + #[cfg(windows)] + { + check_err(r"C:\.."); + check_err(r"C:\a\..\.."); + + check_err(r"C:.."); + check_err(r"C:a\..\.."); + + check_err(r"\\server\share\.."); + check_err(r"\\server\share\a\..\.."); + + check_err(r"\.."); + check_err(r"\a\..\.."); + + check_err(r"\\?\UNC\server\share\.."); + check_err(r"\\?\UNC\server\share\a\..\.."); + } +} From 001989431e8b6cfe66bf5dfc1989bcb6b057002b Mon Sep 17 00:00:00 2001 From: bendn Date: Sun, 25 May 2025 02:01:04 +0700 Subject: [PATCH 18/29] increase perf of charsearcher for single ascii characters --- core/src/str/iter.rs | 2 +- core/src/str/pattern.rs | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/core/src/str/iter.rs b/core/src/str/iter.rs index 425c4eaee28ee..49c581f352eb3 100644 --- a/core/src/str/iter.rs +++ b/core/src/str/iter.rs @@ -656,7 +656,7 @@ impl<'a, P: Pattern> SplitInternal<'a, P> { None } - #[inline] + #[inline(always)] fn next(&mut self) -> Option<&'a str> { if self.finished { return None; diff --git a/core/src/str/pattern.rs b/core/src/str/pattern.rs index bcbbb11c83b2f..e8189a2187b63 100644 --- a/core/src/str/pattern.rs +++ b/core/src/str/pattern.rs @@ -429,8 +429,23 @@ unsafe impl<'a> Searcher<'a> for CharSearcher<'a> { SearchStep::Done } } - #[inline] + #[inline(always)] fn next_match(&mut self) -> Option<(usize, usize)> { + if self.utf8_size == 1 { + return match self + .haystack + .as_bytes() + .get(self.finger..self.finger_back)? + .iter() + .position(|x| *x == self.utf8_encoded[0]) + { + Some(x) => { + self.finger += x + 1; + Some((self.finger - 1, self.finger)) + } + None => None, + }; + } loop { // get the haystack after the last character found let bytes = self.haystack.as_bytes().get(self.finger..self.finger_back)?; @@ -498,6 +513,21 @@ unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> { } #[inline] fn next_match_back(&mut self) -> Option<(usize, usize)> { + if self.utf8_size == 1 { + return match self + .haystack + .get(self.finger..self.finger_back)? + .as_bytes() + .iter() + .rposition(|&x| x == self.utf8_encoded[0]) + { + Some(x) => { + self.finger_back = self.finger + x; + Some((self.finger_back, self.finger_back + 1)) + } + None => None, + }; + } let haystack = self.haystack.as_bytes(); loop { // get the haystack up to but not including the last character searched From 6e70eb64ba3fd168d156dbc749b2efba121cd4d1 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 26 May 2025 15:06:36 -0400 Subject: [PATCH 19/29] Call out possibility of invariant result --- core/src/marker/variance.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/marker/variance.rs b/core/src/marker/variance.rs index 235f8a3bb79f2..f9638fea225b7 100644 --- a/core/src/marker/variance.rs +++ b/core/src/marker/variance.rs @@ -131,6 +131,8 @@ phantom_lifetime! { /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// + /// Note: If `'a` is otherwise contravariant or invariant, the resulting type is invariant. + /// /// ## Layout /// /// For all `'a`, the following are guaranteed: @@ -146,6 +148,8 @@ phantom_lifetime! { /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// + /// Note: If `'a` is otherwise covariant or invariant, the resulting type is invariant. + /// /// ## Layout /// /// For all `'a`, the following are guaranteed: @@ -180,6 +184,8 @@ phantom_type! { /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// + /// Note: If `T` is otherwise contravariant or invariant, the resulting type is invariant. + /// /// ## Layout /// /// For all `T`, the following are guaranteed: @@ -196,6 +202,8 @@ phantom_type! { /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// + /// Note: If `T` is otherwise covariant or invariant, the resulting type is invariant. + /// /// ## Layout /// /// For all `T`, the following are guaranteed: From 556facc5c668ad1cf12116d133b973ae25376cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Mon, 26 May 2025 19:47:42 +0000 Subject: [PATCH 20/29] Minor macro docs fixes --- core/src/macros/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 99a4ab52b6c57..fac1b1ae6123a 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1519,8 +1519,9 @@ pub(crate) mod builtin { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } - /// the derivative of a given function in the forward mode of differentiation. - /// It may only be applied to a function. + /// This macro uses forward-mode automatic differentiation to generate a new function. + /// It may only be applied to a function. The new function will compute the derivative + /// of the function to which the macro was applied. /// /// The expected usage syntax is: /// `#[autodiff_forward(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` @@ -1537,9 +1538,9 @@ pub(crate) mod builtin { /* compiler built-in */ } - /// Automatic Differentiation macro which allows generating a new function to compute - /// the derivative of a given function in the reverse mode of differentiation. - /// It may only be applied to a function. + /// This macro uses reverse-mode automatic differentiation to generate a new function. + /// It may only be applied to a function. The new function will compute the derivative + /// of the function to which the macro was applied. /// /// The expected usage syntax is: /// `#[autodiff_reverse(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` From 8a60737f2b6702118ea37f4a33420c7ae4b23865 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 27 May 2025 10:30:47 +0000 Subject: [PATCH 21/29] Do not get proc_macro from the sysroot in rustc With the stage0 refactor the proc_macro version found in the sysroot will no longer always match the proc_macro version that proc-macros get compiled with by the rustc executable that uses this proc_macro. This will cause problems as soon as the ABI of the bridge gets changed to implement new features or change the way existing features work. To fix this, this commit changes rustc crates to depend directly on the local version of proc_macro which will also be used in the sysroot that rustc will build. --- proc_macro/Cargo.toml | 4 ++++ proc_macro/src/lib.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/proc_macro/Cargo.toml b/proc_macro/Cargo.toml index b8bc2a3af4cd4..1d79246356a35 100644 --- a/proc_macro/Cargo.toml +++ b/proc_macro/Cargo.toml @@ -10,3 +10,7 @@ std = { path = "../std" } # loaded from sysroot causing duplicate lang items and other similar errors. core = { path = "../core" } rustc-literal-escaper = { version = "0.0.2", features = ["rustc-dep-of-std"] } + +[features] +default = ["rustc-dep-of-std"] +rustc-dep-of-std = [] diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index b4fd20c0c176a..32c306be94ecd 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -32,6 +32,7 @@ #![recursion_limit = "256"] #![allow(internal_features)] #![deny(ffi_unwind_calls)] +#![allow(rustc::internal)] // Can't use FxHashMap when compiled as part of the standard library #![warn(rustdoc::unescaped_backticks)] #![warn(unreachable_pub)] #![deny(unsafe_op_in_unsafe_fn)] @@ -95,7 +96,7 @@ pub fn is_available() -> bool { /// /// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` /// and `#[proc_macro_derive]` definitions. -#[rustc_diagnostic_item = "TokenStream"] +#[cfg_attr(feature = "rustc-dep-of-std", rustc_diagnostic_item = "TokenStream")] #[stable(feature = "proc_macro_lib", since = "1.15.0")] #[derive(Clone)] pub struct TokenStream(Option); From de64acac5b5483435386b97ea09a386a024f507d Mon Sep 17 00:00:00 2001 From: tk <49250442+tkr-sh@users.noreply.github.com> Date: Tue, 27 May 2025 19:47:14 +0200 Subject: [PATCH 22/29] =?UTF-8?q?=E2=9C=A8=20feat:=20map=5For=5Fdefault=20?= =?UTF-8?q?for=20result=20and=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/option.rs | 30 ++++++++++++++++++++++++++++++ core/src/result.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/core/src/option.rs b/core/src/option.rs index 1d264b260767e..675556b07a838 100644 --- a/core/src/option.rs +++ b/core/src/option.rs @@ -1253,6 +1253,36 @@ impl Option { } } + /// Maps an `Option` to a `U` by applying function `f` to the contained + /// value if the option is [`Some`], otherwise if [`None`], returns the + /// [default value] for the type `U`. + /// + /// # Examples + /// + /// ``` + /// #![feature(result_option_map_or_default)] + /// + /// let x: Option<&str> = Some("hi"); + /// let y: Option<&str> = None; + /// + /// assert_eq!(x.map_or_default(|x| x.len()), 2); + /// assert_eq!(y.map_or_default(|y| y.len()), 0); + /// ``` + /// + /// [default value]: Default::default + #[inline] + #[unstable(feature = "result_option_map_or_default", issue = "138099")] + pub fn map_or_default(self, f: F) -> U + where + U: Default, + F: FnOnce(T) -> U, + { + match self { + Some(t) => f(t), + None => U::default(), + } + } + /// Transforms the `Option` into a [`Result`], mapping [`Some(v)`] to /// [`Ok(v)`] and [`None`] to [`Err(err)`]. /// diff --git a/core/src/result.rs b/core/src/result.rs index 736ffb7d0caf3..ef2da5e8fbf41 100644 --- a/core/src/result.rs +++ b/core/src/result.rs @@ -858,6 +858,36 @@ impl Result { } } + /// Maps a `Result` to a `U` by applying function `f` to the contained + /// value if the result is [`Ok`], otherwise if [`Err`], returns the + /// [default value] for the type `U`. + /// + /// # Examples + /// + /// ``` + /// #![feature(result_option_map_or_default)] + /// + /// let x: Result<_, &str> = Ok("foo"); + /// let y: Result<&str, _> = Err("bar"); + /// + /// assert_eq!(x.map_or_default(|x| x.len()), 3); + /// assert_eq!(y.map_or_default(|y| y.len()), 0); + /// ``` + /// + /// [default value]: Default::default + #[inline] + #[unstable(feature = "result_option_map_or_default", issue = "138099")] + pub fn map_or_default(self, f: F) -> U + where + U: Default, + F: FnOnce(T) -> U, + { + match self { + Ok(t) => f(t), + Err(_) => U::default(), + } + } + /// Maps a `Result` to `Result` by applying a function to a /// contained [`Err`] value, leaving an [`Ok`] value untouched. /// From b43d1845a9ee1d8a2abe73a1c5da99be39ef68e8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 May 2025 08:37:45 +0200 Subject: [PATCH 23/29] coretests: simplify test_float macro to derive more things from the type name --- coretests/tests/num/mod.rs | 236 ++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 134 deletions(-) diff --git a/coretests/tests/num/mod.rs b/coretests/tests/num/mod.rs index a6b75f7026604..cdde5b883aa9f 100644 --- a/coretests/tests/num/mod.rs +++ b/coretests/tests/num/mod.rs @@ -732,7 +732,7 @@ assume_usize_width! { } macro_rules! test_float { - ($modname: ident, $fassert: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { + ($modname: ident, $fassert: ident, $fty: ty) => { mod $modname { #[test] fn min() { @@ -747,19 +747,19 @@ macro_rules! test_float { $fassert!((-0.0 as $fty).min(9.0), -0.0); $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); $fassert!((-0.0 as $fty).min(-9.0), -9.0); - $fassert!(($inf as $fty).min(9.0), 9.0); - $fassert!((9.0 as $fty).min($inf), 9.0); - $fassert!(($inf as $fty).min(-9.0), -9.0); - $fassert!((-9.0 as $fty).min($inf), -9.0); - $fassert!(($neginf as $fty).min(9.0), $neginf); - $fassert!((9.0 as $fty).min($neginf), $neginf); - $fassert!(($neginf as $fty).min(-9.0), $neginf); - $fassert!((-9.0 as $fty).min($neginf), $neginf); - $fassert!(($nan as $fty).min(9.0), 9.0); - $fassert!(($nan as $fty).min(-9.0), -9.0); - $fassert!((9.0 as $fty).min($nan), 9.0); - $fassert!((-9.0 as $fty).min($nan), -9.0); - $fassert!(($nan as $fty).min($nan).is_nan()); + $fassert!((<$fty>::INFINITY as $fty).min(9.0), 9.0); + $fassert!((9.0 as $fty).min(<$fty>::INFINITY), 9.0); + $fassert!((<$fty>::INFINITY as $fty).min(-9.0), -9.0); + $fassert!((-9.0 as $fty).min(<$fty>::INFINITY), -9.0); + $fassert!((<$fty>::NEG_INFINITY as $fty).min(9.0), <$fty>::NEG_INFINITY); + $fassert!((9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); + $fassert!((<$fty>::NEG_INFINITY as $fty).min(-9.0), <$fty>::NEG_INFINITY); + $fassert!((-9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); + $fassert!((<$fty>::NAN as $fty).min(9.0), 9.0); + $fassert!((<$fty>::NAN as $fty).min(-9.0), -9.0); + $fassert!((9.0 as $fty).min(<$fty>::NAN), 9.0); + $fassert!((-9.0 as $fty).min(<$fty>::NAN), -9.0); + $fassert!((<$fty>::NAN as $fty).min(<$fty>::NAN).is_nan()); } #[test] fn max() { @@ -777,19 +777,19 @@ macro_rules! test_float { $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); $fassert!((-0.0 as $fty).max(-9.0), -0.0); $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - $fassert!(($inf as $fty).max(9.0), $inf); - $fassert!((9.0 as $fty).max($inf), $inf); - $fassert!(($inf as $fty).max(-9.0), $inf); - $fassert!((-9.0 as $fty).max($inf), $inf); - $fassert!(($neginf as $fty).max(9.0), 9.0); - $fassert!((9.0 as $fty).max($neginf), 9.0); - $fassert!(($neginf as $fty).max(-9.0), -9.0); - $fassert!((-9.0 as $fty).max($neginf), -9.0); - $fassert!(($nan as $fty).max(9.0), 9.0); - $fassert!(($nan as $fty).max(-9.0), -9.0); - $fassert!((9.0 as $fty).max($nan), 9.0); - $fassert!((-9.0 as $fty).max($nan), -9.0); - $fassert!(($nan as $fty).max($nan).is_nan()); + $fassert!((<$fty>::INFINITY as $fty).max(9.0), <$fty>::INFINITY); + $fassert!((9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!((<$fty>::INFINITY as $fty).max(-9.0), <$fty>::INFINITY); + $fassert!((-9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!((<$fty>::NEG_INFINITY as $fty).max(9.0), 9.0); + $fassert!((9.0 as $fty).max(<$fty>::NEG_INFINITY), 9.0); + $fassert!((<$fty>::NEG_INFINITY as $fty).max(-9.0), -9.0); + $fassert!((-9.0 as $fty).max(<$fty>::NEG_INFINITY), -9.0); + $fassert!((<$fty>::NAN as $fty).max(9.0), 9.0); + $fassert!((<$fty>::NAN as $fty).max(-9.0), -9.0); + $fassert!((9.0 as $fty).max(<$fty>::NAN), 9.0); + $fassert!((-9.0 as $fty).max(<$fty>::NAN), -9.0); + $fassert!((<$fty>::NAN as $fty).max(<$fty>::NAN).is_nan()); } #[test] fn minimum() { @@ -806,19 +806,19 @@ macro_rules! test_float { $fassert!((-0.0 as $fty).minimum(9.0), -0.0); $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); - $fassert!(($inf as $fty).minimum(9.0), 9.0); - $fassert!((9.0 as $fty).minimum($inf), 9.0); - $fassert!(($inf as $fty).minimum(-9.0), -9.0); - $fassert!((-9.0 as $fty).minimum($inf), -9.0); - $fassert!(($neginf as $fty).minimum(9.0), $neginf); - $fassert!((9.0 as $fty).minimum($neginf), $neginf); - $fassert!(($neginf as $fty).minimum(-9.0), $neginf); - $fassert!((-9.0 as $fty).minimum($neginf), $neginf); - $fassert!(($nan as $fty).minimum(9.0).is_nan()); - $fassert!(($nan as $fty).minimum(-9.0).is_nan()); - $fassert!((9.0 as $fty).minimum($nan).is_nan()); - $fassert!((-9.0 as $fty).minimum($nan).is_nan()); - $fassert!(($nan as $fty).minimum($nan).is_nan()); + $fassert!((<$fty>::INFINITY as $fty).minimum(9.0), 9.0); + $fassert!((9.0 as $fty).minimum(<$fty>::INFINITY), 9.0); + $fassert!((<$fty>::INFINITY as $fty).minimum(-9.0), -9.0); + $fassert!((-9.0 as $fty).minimum(<$fty>::INFINITY), -9.0); + $fassert!((<$fty>::NEG_INFINITY as $fty).minimum(9.0), <$fty>::NEG_INFINITY); + $fassert!((9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); + $fassert!((<$fty>::NEG_INFINITY as $fty).minimum(-9.0), <$fty>::NEG_INFINITY); + $fassert!((-9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); + $fassert!((<$fty>::NAN as $fty).minimum(9.0).is_nan()); + $fassert!((<$fty>::NAN as $fty).minimum(-9.0).is_nan()); + $fassert!((9.0 as $fty).minimum(<$fty>::NAN).is_nan()); + $fassert!((-9.0 as $fty).minimum(<$fty>::NAN).is_nan()); + $fassert!((<$fty>::NAN as $fty).minimum(<$fty>::NAN).is_nan()); } #[test] fn maximum() { @@ -838,19 +838,19 @@ macro_rules! test_float { $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - $fassert!(($inf as $fty).maximum(9.0), $inf); - $fassert!((9.0 as $fty).maximum($inf), $inf); - $fassert!(($inf as $fty).maximum(-9.0), $inf); - $fassert!((-9.0 as $fty).maximum($inf), $inf); - $fassert!(($neginf as $fty).maximum(9.0), 9.0); - $fassert!((9.0 as $fty).maximum($neginf), 9.0); - $fassert!(($neginf as $fty).maximum(-9.0), -9.0); - $fassert!((-9.0 as $fty).maximum($neginf), -9.0); - $fassert!(($nan as $fty).maximum(9.0).is_nan()); - $fassert!(($nan as $fty).maximum(-9.0).is_nan()); - $fassert!((9.0 as $fty).maximum($nan).is_nan()); - $fassert!((-9.0 as $fty).maximum($nan).is_nan()); - $fassert!(($nan as $fty).maximum($nan).is_nan()); + $fassert!((<$fty>::INFINITY as $fty).maximum(9.0), <$fty>::INFINITY); + $fassert!((9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!((<$fty>::INFINITY as $fty).maximum(-9.0), <$fty>::INFINITY); + $fassert!((-9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!((<$fty>::NEG_INFINITY as $fty).maximum(9.0), 9.0); + $fassert!((9.0 as $fty).maximum(<$fty>::NEG_INFINITY), 9.0); + $fassert!((<$fty>::NEG_INFINITY as $fty).maximum(-9.0), -9.0); + $fassert!((-9.0 as $fty).maximum(<$fty>::NEG_INFINITY), -9.0); + $fassert!((<$fty>::NAN as $fty).maximum(9.0).is_nan()); + $fassert!((<$fty>::NAN as $fty).maximum(-9.0).is_nan()); + $fassert!((9.0 as $fty).maximum(<$fty>::NAN).is_nan()); + $fassert!((-9.0 as $fty).maximum(<$fty>::NAN).is_nan()); + $fassert!((<$fty>::NAN as $fty).maximum(<$fty>::NAN).is_nan()); } #[test] fn midpoint() { @@ -863,38 +863,50 @@ macro_rules! test_float { $fassert!((0.0 as $fty).midpoint(0.0), 0.0); $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); - $fassert!(($max as $fty).midpoint($min), 0.0); - $fassert!(($min as $fty).midpoint($max), -0.0); - $fassert!(($max as $fty).midpoint($min_pos), $max / 2.); - $fassert!((-$max as $fty).midpoint($min_pos), -$max / 2.); - $fassert!(($max as $fty).midpoint(-$min_pos), $max / 2.); - $fassert!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); - $fassert!(($min_pos as $fty).midpoint($max), $max / 2.); - $fassert!(($min_pos as $fty).midpoint(-$max), -$max / 2.); - $fassert!((-$min_pos as $fty).midpoint($max), $max / 2.); - $fassert!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); - $fassert!(($max as $fty).midpoint($max), $max); - $fassert!(($min_pos as $fty).midpoint($min_pos), $min_pos); - $fassert!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); - $fassert!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); - $fassert!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); - $fassert!(($inf as $fty).midpoint($inf), $inf); - $fassert!(($neginf as $fty).midpoint($neginf), $neginf); - $fassert!(($nan as $fty).midpoint(1.0).is_nan()); - $fassert!((1.0 as $fty).midpoint($nan).is_nan()); - $fassert!(($nan as $fty).midpoint($nan).is_nan()); + $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MIN), 0.0); + $fassert!((<$fty>::MIN as $fty).midpoint(<$fty>::MAX), -0.0); + $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); + $fassert!((-<$fty>::MAX as $fty).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); + $fassert!((<$fty>::MAX as $fty).midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); + $fassert!( + (-<$fty>::MAX as $fty).midpoint(-<$fty>::MIN_POSITIVE), + -<$fty>::MAX / 2. + ); + $fassert!((<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); + $fassert!((<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); + $fassert!((-<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); + $fassert!((-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); + $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MAX), <$fty>::MAX); + $fassert!( + (<$fty>::MIN_POSITIVE).midpoint(<$fty>::MIN_POSITIVE), + <$fty>::MIN_POSITIVE + ); + $fassert!( + (-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MIN_POSITIVE), + -<$fty>::MIN_POSITIVE + ); + $fassert!((<$fty>::MAX as $fty).midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); + $fassert!((<$fty>::MAX as $fty).midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); + $fassert!((<$fty>::INFINITY as $fty).midpoint(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!( + (<$fty>::NEG_INFINITY as $fty).midpoint(<$fty>::NEG_INFINITY), + <$fty>::NEG_INFINITY + ); + $fassert!((<$fty>::NAN as $fty).midpoint(1.0).is_nan()); + $fassert!((1.0 as $fty).midpoint(<$fty>::NAN).is_nan()); + $fassert!((<$fty>::NAN as $fty).midpoint(<$fty>::NAN).is_nan()); // test if large differences in magnitude are still correctly computed. // NOTE: that because of how small x and y are, x + y can never overflow // so (x + y) / 2.0 is always correct // in particular, `2.pow(i)` will never be at the max exponent, so it could // be safely doubled, while j is significantly smaller. - for i in $max_exp.saturating_sub(64)..$max_exp { + for i in <$fty>::MAX_EXP.saturating_sub(64)..<$fty>::MAX_EXP { for j in 0..64u8 { let large = <$fty>::from(2.0f32).powi(i); // a much smaller number, such that there is no chance of overflow to test // potential double rounding in midpoint's implementation. - let small = <$fty>::from(2.0f32).powi($max_exp - 1) + let small = (2.0 as $fty).powi(<$fty>::MAX_EXP - 1) * <$fty>::EPSILON * <$fty>::from(j); @@ -908,21 +920,21 @@ macro_rules! test_float { #[test] fn rem_euclid() { // FIXME: Use $fassert when rem_euclid becomes const - assert!($inf.rem_euclid((42.0 as $fty)).is_nan()); - assert_eq!((42.0 as $fty).rem_euclid($inf), (42.0 as $fty)); - assert!((42.0 as $fty).rem_euclid($nan).is_nan()); - assert!($inf.rem_euclid($inf).is_nan()); - assert!($inf.rem_euclid($nan).is_nan()); - assert!($nan.rem_euclid($inf).is_nan()); + assert!(<$fty>::INFINITY.rem_euclid((42.0 as $fty)).is_nan()); + assert_eq!((42.0 as $fty).rem_euclid(<$fty>::INFINITY), (42.0 as $fty)); + assert!((42.0 as $fty).rem_euclid(<$fty>::NAN).is_nan()); + assert!(<$fty>::INFINITY.rem_euclid(<$fty>::INFINITY).is_nan()); + assert!(<$fty>::INFINITY.rem_euclid(<$fty>::NAN).is_nan()); + assert!(<$fty>::NAN.rem_euclid(<$fty>::INFINITY).is_nan()); } #[test] fn div_euclid() { // FIXME: Use $fassert when div_euclid becomes const - assert_eq!((42.0 as $fty).div_euclid($inf), 0.0); - assert!((42.0 as $fty).div_euclid($nan).is_nan()); - assert!($inf.div_euclid($inf).is_nan()); - assert!($inf.div_euclid($nan).is_nan()); - assert!($nan.div_euclid($inf).is_nan()); + assert_eq!((42.0 as $fty).div_euclid(<$fty>::INFINITY), 0.0); + assert!((42.0 as $fty).div_euclid(<$fty>::NAN).is_nan()); + assert!(<$fty>::INFINITY.div_euclid(<$fty>::INFINITY).is_nan()); + assert!(<$fty>::INFINITY.div_euclid(<$fty>::NAN).is_nan()); + assert!(<$fty>::NAN.div_euclid(<$fty>::INFINITY).is_nan()); } } }; @@ -948,51 +960,7 @@ macro_rules! float_const_assert { }; } -test_float!( - f32, - float_assert, - f32, - f32::INFINITY, - f32::NEG_INFINITY, - f32::NAN, - f32::MIN, - f32::MAX, - f32::MIN_POSITIVE, - f32::MAX_EXP -); -test_float!( - f32_const, - float_const_assert, - f32, - f32::INFINITY, - f32::NEG_INFINITY, - f32::NAN, - f32::MIN, - f32::MAX, - f32::MIN_POSITIVE, - f32::MAX_EXP -); -test_float!( - f64, - float_assert, - f64, - f64::INFINITY, - f64::NEG_INFINITY, - f64::NAN, - f64::MIN, - f64::MAX, - f64::MIN_POSITIVE, - f64::MAX_EXP -); -test_float!( - f64_const, - float_const_assert, - f64, - f64::INFINITY, - f64::NEG_INFINITY, - f64::NAN, - f64::MIN, - f64::MAX, - f64::MIN_POSITIVE, - f64::MAX_EXP -); +test_float!(f32, float_assert, f32); +test_float!(f32_const, float_const_assert, f32); +test_float!(f64, float_assert, f64); +test_float!(f64_const, float_const_assert, f64); From 2303f50494d9f10161fd35a02ac71fccd80d6127 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 May 2025 08:42:36 +0200 Subject: [PATCH 24/29] coretests: add abs() and copysign() tests, and remove now-unnecessary ui test --- coretests/tests/num/mod.rs | 101 ++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/coretests/tests/num/mod.rs b/coretests/tests/num/mod.rs index cdde5b883aa9f..1212d36a1b15c 100644 --- a/coretests/tests/num/mod.rs +++ b/coretests/tests/num/mod.rs @@ -747,19 +747,19 @@ macro_rules! test_float { $fassert!((-0.0 as $fty).min(9.0), -0.0); $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); $fassert!((-0.0 as $fty).min(-9.0), -9.0); - $fassert!((<$fty>::INFINITY as $fty).min(9.0), 9.0); + $fassert!(<$fty>::INFINITY.min(9.0), 9.0); $fassert!((9.0 as $fty).min(<$fty>::INFINITY), 9.0); - $fassert!((<$fty>::INFINITY as $fty).min(-9.0), -9.0); + $fassert!(<$fty>::INFINITY.min(-9.0), -9.0); $fassert!((-9.0 as $fty).min(<$fty>::INFINITY), -9.0); - $fassert!((<$fty>::NEG_INFINITY as $fty).min(9.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.min(9.0), <$fty>::NEG_INFINITY); $fassert!((9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!((<$fty>::NEG_INFINITY as $fty).min(-9.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.min(-9.0), <$fty>::NEG_INFINITY); $fassert!((-9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!((<$fty>::NAN as $fty).min(9.0), 9.0); - $fassert!((<$fty>::NAN as $fty).min(-9.0), -9.0); + $fassert!(<$fty>::NAN.min(9.0), 9.0); + $fassert!(<$fty>::NAN.min(-9.0), -9.0); $fassert!((9.0 as $fty).min(<$fty>::NAN), 9.0); $fassert!((-9.0 as $fty).min(<$fty>::NAN), -9.0); - $fassert!((<$fty>::NAN as $fty).min(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.min(<$fty>::NAN).is_nan()); } #[test] fn max() { @@ -777,19 +777,19 @@ macro_rules! test_float { $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); $fassert!((-0.0 as $fty).max(-9.0), -0.0); $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - $fassert!((<$fty>::INFINITY as $fty).max(9.0), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.max(9.0), <$fty>::INFINITY); $fassert!((9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!((<$fty>::INFINITY as $fty).max(-9.0), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.max(-9.0), <$fty>::INFINITY); $fassert!((-9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!((<$fty>::NEG_INFINITY as $fty).max(9.0), 9.0); + $fassert!(<$fty>::NEG_INFINITY.max(9.0), 9.0); $fassert!((9.0 as $fty).max(<$fty>::NEG_INFINITY), 9.0); - $fassert!((<$fty>::NEG_INFINITY as $fty).max(-9.0), -9.0); + $fassert!(<$fty>::NEG_INFINITY.max(-9.0), -9.0); $fassert!((-9.0 as $fty).max(<$fty>::NEG_INFINITY), -9.0); - $fassert!((<$fty>::NAN as $fty).max(9.0), 9.0); - $fassert!((<$fty>::NAN as $fty).max(-9.0), -9.0); + $fassert!(<$fty>::NAN.max(9.0), 9.0); + $fassert!(<$fty>::NAN.max(-9.0), -9.0); $fassert!((9.0 as $fty).max(<$fty>::NAN), 9.0); $fassert!((-9.0 as $fty).max(<$fty>::NAN), -9.0); - $fassert!((<$fty>::NAN as $fty).max(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.max(<$fty>::NAN).is_nan()); } #[test] fn minimum() { @@ -806,19 +806,19 @@ macro_rules! test_float { $fassert!((-0.0 as $fty).minimum(9.0), -0.0); $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); - $fassert!((<$fty>::INFINITY as $fty).minimum(9.0), 9.0); + $fassert!(<$fty>::INFINITY.minimum(9.0), 9.0); $fassert!((9.0 as $fty).minimum(<$fty>::INFINITY), 9.0); - $fassert!((<$fty>::INFINITY as $fty).minimum(-9.0), -9.0); + $fassert!(<$fty>::INFINITY.minimum(-9.0), -9.0); $fassert!((-9.0 as $fty).minimum(<$fty>::INFINITY), -9.0); - $fassert!((<$fty>::NEG_INFINITY as $fty).minimum(9.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.minimum(9.0), <$fty>::NEG_INFINITY); $fassert!((9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!((<$fty>::NEG_INFINITY as $fty).minimum(-9.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.minimum(-9.0), <$fty>::NEG_INFINITY); $fassert!((-9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!((<$fty>::NAN as $fty).minimum(9.0).is_nan()); - $fassert!((<$fty>::NAN as $fty).minimum(-9.0).is_nan()); + $fassert!(<$fty>::NAN.minimum(9.0).is_nan()); + $fassert!(<$fty>::NAN.minimum(-9.0).is_nan()); $fassert!((9.0 as $fty).minimum(<$fty>::NAN).is_nan()); $fassert!((-9.0 as $fty).minimum(<$fty>::NAN).is_nan()); - $fassert!((<$fty>::NAN as $fty).minimum(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.minimum(<$fty>::NAN).is_nan()); } #[test] fn maximum() { @@ -838,19 +838,19 @@ macro_rules! test_float { $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - $fassert!((<$fty>::INFINITY as $fty).maximum(9.0), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.maximum(9.0), <$fty>::INFINITY); $fassert!((9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!((<$fty>::INFINITY as $fty).maximum(-9.0), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.maximum(-9.0), <$fty>::INFINITY); $fassert!((-9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!((<$fty>::NEG_INFINITY as $fty).maximum(9.0), 9.0); + $fassert!(<$fty>::NEG_INFINITY.maximum(9.0), 9.0); $fassert!((9.0 as $fty).maximum(<$fty>::NEG_INFINITY), 9.0); - $fassert!((<$fty>::NEG_INFINITY as $fty).maximum(-9.0), -9.0); + $fassert!(<$fty>::NEG_INFINITY.maximum(-9.0), -9.0); $fassert!((-9.0 as $fty).maximum(<$fty>::NEG_INFINITY), -9.0); - $fassert!((<$fty>::NAN as $fty).maximum(9.0).is_nan()); - $fassert!((<$fty>::NAN as $fty).maximum(-9.0).is_nan()); + $fassert!(<$fty>::NAN.maximum(9.0).is_nan()); + $fassert!(<$fty>::NAN.maximum(-9.0).is_nan()); $fassert!((9.0 as $fty).maximum(<$fty>::NAN).is_nan()); $fassert!((-9.0 as $fty).maximum(<$fty>::NAN).is_nan()); - $fassert!((<$fty>::NAN as $fty).maximum(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.maximum(<$fty>::NAN).is_nan()); } #[test] fn midpoint() { @@ -863,20 +863,17 @@ macro_rules! test_float { $fassert!((0.0 as $fty).midpoint(0.0), 0.0); $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); - $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MIN), 0.0); - $fassert!((<$fty>::MIN as $fty).midpoint(<$fty>::MAX), -0.0); - $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MAX as $fty).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); - $fassert!((<$fty>::MAX as $fty).midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!( - (-<$fty>::MAX as $fty).midpoint(-<$fty>::MIN_POSITIVE), - -<$fty>::MAX / 2. - ); + $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN), 0.0); + $fassert!(<$fty>::MIN.midpoint(<$fty>::MAX), -0.0); + $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); + $fassert!((-<$fty>::MAX).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); + $fassert!(<$fty>::MAX.midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); + $fassert!((-<$fty>::MAX).midpoint(-<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); $fassert!((<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); $fassert!((<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); $fassert!((-<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); $fassert!((-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); - $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MAX), <$fty>::MAX); + $fassert!(<$fty>::MAX.midpoint(<$fty>::MAX), <$fty>::MAX); $fassert!( (<$fty>::MIN_POSITIVE).midpoint(<$fty>::MIN_POSITIVE), <$fty>::MIN_POSITIVE @@ -885,16 +882,16 @@ macro_rules! test_float { (-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MIN_POSITIVE), -<$fty>::MIN_POSITIVE ); - $fassert!((<$fty>::MAX as $fty).midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); - $fassert!((<$fty>::MAX as $fty).midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); - $fassert!((<$fty>::INFINITY as $fty).midpoint(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!(<$fty>::MAX.midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); + $fassert!(<$fty>::MAX.midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); + $fassert!(<$fty>::INFINITY.midpoint(<$fty>::INFINITY), <$fty>::INFINITY); $fassert!( - (<$fty>::NEG_INFINITY as $fty).midpoint(<$fty>::NEG_INFINITY), + <$fty>::NEG_INFINITY.midpoint(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY ); - $fassert!((<$fty>::NAN as $fty).midpoint(1.0).is_nan()); + $fassert!(<$fty>::NAN.midpoint(1.0).is_nan()); $fassert!((1.0 as $fty).midpoint(<$fty>::NAN).is_nan()); - $fassert!((<$fty>::NAN as $fty).midpoint(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.midpoint(<$fty>::NAN).is_nan()); // test if large differences in magnitude are still correctly computed. // NOTE: that because of how small x and y are, x + y can never overflow @@ -903,7 +900,7 @@ macro_rules! test_float { // be safely doubled, while j is significantly smaller. for i in <$fty>::MAX_EXP.saturating_sub(64)..<$fty>::MAX_EXP { for j in 0..64u8 { - let large = <$fty>::from(2.0f32).powi(i); + let large = (2.0 as $fty).powi(i); // a much smaller number, such that there is no chance of overflow to test // potential double rounding in midpoint's implementation. let small = (2.0 as $fty).powi(<$fty>::MAX_EXP - 1) @@ -918,6 +915,20 @@ macro_rules! test_float { } } #[test] + fn abs() { + $fassert!((-1.0 as $fty).abs(), 1.0); + $fassert!((1.0 as $fty).abs(), 1.0); + $fassert!(<$fty>::NEG_INFINITY.abs(), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.abs(), <$fty>::INFINITY); + } + #[test] + fn copysign() { + $fassert!((1.0 as $fty).copysign(-2.0), -1.0); + $fassert!((-1.0 as $fty).copysign(2.0), 1.0); + $fassert!(<$fty>::INFINITY.copysign(-0.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.copysign(0.0), <$fty>::INFINITY); + } + #[test] fn rem_euclid() { // FIXME: Use $fassert when rem_euclid becomes const assert!(<$fty>::INFINITY.rem_euclid((42.0 as $fty)).is_nan()); From 4ad0897533dfc25391c2016d68f57a5eb9886ee1 Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Fri, 16 May 2025 22:49:00 +0200 Subject: [PATCH 25/29] Test(fs): Fix test_eq_windows_file_type for Windows 7 Would otherwise fail on: ``` thread 'fs::tests::test_eq_windows_file_type' panicked at library/std/src/test_helpers.rs:53:20: called `Result::unwrap()` on an `Err` value: Os { code: 5, kind: PermissionDenied, message: "Access is denied." } ``` This came from the read-only attribute set on the test file. In order to fix this, instead of simply disabling the test, the attribute is reset before the test's end so it may still run successfully. Signed-off-by: Paul Mabileau --- std/src/fs/tests.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index 8da6d75b73e17..c81e3af2f0d4c 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -1782,8 +1782,30 @@ fn test_eq_windows_file_type() { // Change the readonly attribute of one file. let mut perms = file1.metadata().unwrap().permissions(); perms.set_readonly(true); - file1.set_permissions(perms).unwrap(); + file1.set_permissions(perms.clone()).unwrap(); + #[cfg(target_vendor = "win7")] + let _g = ReadonlyGuard { file: &file1, perms }; assert_eq!(file1.metadata().unwrap().file_type(), file2.metadata().unwrap().file_type()); + + // Reset the attribute before the `TmpDir`'s drop that removes the + // associated directory, which fails with a `PermissionDenied` error when + // running under Windows 7. + #[cfg(target_vendor = "win7")] + struct ReadonlyGuard<'f> { + file: &'f File, + perms: fs::Permissions, + } + #[cfg(target_vendor = "win7")] + impl<'f> Drop for ReadonlyGuard<'f> { + fn drop(&mut self) { + self.perms.set_readonly(false); + let res = self.file.set_permissions(self.perms.clone()); + + if !thread::panicking() { + res.unwrap(); + } + } + } } /// Regression test for https://github.com/rust-lang/rust/issues/50619. From 33bd15e3b072c734f455f92953ba1138d872a194 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 28 May 2025 15:12:56 +0200 Subject: [PATCH 26/29] Add diagnostic items to sys::Mutex --- std/src/sys/sync/mutex/futex.rs | 3 +++ std/src/sys/sync/mutex/pthread.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/std/src/sys/sync/mutex/futex.rs b/std/src/sys/sync/mutex/futex.rs index ce9b2daa5f808..01e91a6294a45 100644 --- a/std/src/sys/sync/mutex/futex.rs +++ b/std/src/sys/sync/mutex/futex.rs @@ -19,11 +19,13 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")] pub fn try_lock(&self) -> bool { self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_ok() } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")] pub fn lock(&self) { if self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_err() { self.lock_contended(); @@ -80,6 +82,7 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")] pub unsafe fn unlock(&self) { if self.futex.swap(UNLOCKED, Release) == CONTENDED { // We only wake up one thread. When that thread locks the mutex, it diff --git a/std/src/sys/sync/mutex/pthread.rs b/std/src/sys/sync/mutex/pthread.rs index 75b4b9c6dad9b..52588a7899a73 100644 --- a/std/src/sys/sync/mutex/pthread.rs +++ b/std/src/sys/sync/mutex/pthread.rs @@ -28,6 +28,7 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")] pub fn lock(&self) { // SAFETY: we call `init` above, therefore reentrant locking is safe. // In `drop` we ensure that the mutex is not destroyed while locked. @@ -35,6 +36,7 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")] pub unsafe fn unlock(&self) { // SAFETY: the mutex can only be locked if it is already initialized // and we observed this initialization since we observed the locking. @@ -42,6 +44,7 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")] pub fn try_lock(&self) -> bool { // SAFETY: we call `init` above, therefore reentrant locking is safe. // In `drop` we ensure that the mutex is not destroyed while locked. From f5e3a6be8b08451c4277a670fd5e2a920e1e0143 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 28 May 2025 15:13:38 +0200 Subject: [PATCH 27/29] Make pthread Mutex internals less public --- std/src/sys/sync/mutex/pthread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/sys/sync/mutex/pthread.rs b/std/src/sys/sync/mutex/pthread.rs index 52588a7899a73..1d442248374d5 100644 --- a/std/src/sys/sync/mutex/pthread.rs +++ b/std/src/sys/sync/mutex/pthread.rs @@ -6,7 +6,7 @@ use crate::sys::pal::sync as pal; use crate::sys::sync::OnceBox; pub struct Mutex { - pub pal: OnceBox, + pub(in crate::sys::sync) pal: OnceBox, } impl Mutex { From e2a7b41a58658378a229168ec8703c9211816d14 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 May 2025 15:06:08 +0200 Subject: [PATCH 28/29] core: unstably expose atomic_compare_exchange so stdarch can use it --- core/src/sync/atomic.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index bd5a58d74ba0d..6bc6bee682df6 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -3885,10 +3885,13 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { } } +/// Publicly exposed for stdarch; nobody else should use this. #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn atomic_compare_exchange( +#[unstable(feature = "core_intrinsics", issue = "none")] +#[doc(hidden)] +pub unsafe fn atomic_compare_exchange( dst: *mut T, old: T, new: T, From 6662b01491f188ece2fe29b459cc627938da3dee Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 28 May 2025 17:05:45 +0200 Subject: [PATCH 29/29] Add comments to diagnostic items --- std/src/sys/sync/mutex/futex.rs | 3 +++ std/src/sys/sync/mutex/pthread.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/std/src/sys/sync/mutex/futex.rs b/std/src/sys/sync/mutex/futex.rs index 01e91a6294a45..70e2ea9f60586 100644 --- a/std/src/sys/sync/mutex/futex.rs +++ b/std/src/sys/sync/mutex/futex.rs @@ -19,12 +19,14 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")] pub fn try_lock(&self) -> bool { self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_ok() } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")] pub fn lock(&self) { if self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_err() { @@ -82,6 +84,7 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")] pub unsafe fn unlock(&self) { if self.futex.swap(UNLOCKED, Release) == CONTENDED { diff --git a/std/src/sys/sync/mutex/pthread.rs b/std/src/sys/sync/mutex/pthread.rs index 1d442248374d5..a7a3b47d0ec62 100644 --- a/std/src/sys/sync/mutex/pthread.rs +++ b/std/src/sys/sync/mutex/pthread.rs @@ -28,6 +28,7 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")] pub fn lock(&self) { // SAFETY: we call `init` above, therefore reentrant locking is safe. @@ -36,6 +37,7 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")] pub unsafe fn unlock(&self) { // SAFETY: the mutex can only be locked if it is already initialized @@ -44,6 +46,7 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")] pub fn try_lock(&self) -> bool { // SAFETY: we call `init` above, therefore reentrant locking is safe.