From 716c6af923e1d2daf14aa437483a30af772c9afa Mon Sep 17 00:00:00 2001 From: rahulku Date: Wed, 27 Nov 2024 09:27:12 -0800 Subject: [PATCH 01/13] Add two more reviewers (#190) Add two more reviewers to our list. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --- .github/pull_requests.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/pull_requests.toml b/.github/pull_requests.toml index a83cebe76609e..6c11ebfeb3691 100644 --- a/.github/pull_requests.toml +++ b/.github/pull_requests.toml @@ -16,5 +16,7 @@ members = [ "robdockins", "HuStmpHrrr", "Eh2406", - "jswrenn" + "jswrenn", + "havelund", + "jorajeev" ] From 014965a3b54c056d8cd1d08e3aebc5d5c61356b9 Mon Sep 17 00:00:00 2001 From: stogaru <143449212+stogaru@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:55:57 -0800 Subject: [PATCH 02/13] Contracts and Harnesses for `<*mut T>::add`, `sub` and `offset` (#113) Towards #76 ### Changes * Adds contracts for `<*mut T>::add`, `<*mut T>::sub` and `<*mut T>::offset` * Adds proofs for contracts of the above functions verifying the pointee types: * All integer types * Tuples (composite type) * Unit Type * Defines a macro for add and sub and another for offset. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Co-authored-by: Yifei Wang <1277495324@qq.com> Co-authored-by: MayureshJoshi25 Co-authored-by: Yifei Wang <40480373+xsxszab@users.noreply.github.com> --- library/core/src/ptr/mut_ptr.rs | 177 ++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 7aa6a309a06b5..34ab472735915 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -3,6 +3,10 @@ use crate::cmp::Ordering::{Equal, Greater, Less}; use crate::intrinsics::const_eval_select; use crate::mem::SizedTypeProperties; use crate::slice::{self, SliceIndex}; +use safety::{ensures, requires}; + +#[cfg(kani)] +use crate::kani; impl *mut T { /// Returns `true` if the pointer is null. @@ -400,6 +404,22 @@ impl *mut T { #[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 + // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned. + // These conditions are not verified as part of the preconditions. + #[requires( + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize` + count.checked_mul(core::mem::size_of::() as isize).is_some() && + // Precondition 2: adding the computed offset to `self` does not cause overflow + (self as isize).checked_add((count * core::mem::size_of::() as isize)).is_some() && + // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. + // Otherwise, for non-unit types, `self` and `self.wrapping_offset(count)` should point to the same allocated object, + // restricting `count` to prevent crossing allocation boundaries. + ((core::mem::size_of::() == 0) || (kani::mem::same_allocation(self, self.wrapping_offset(count)))) + )] + // Postcondition: If `T` is a unit type (`size_of::() == 0`), no allocation check is needed. + // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object, + // verifying that the result remains within the same allocation as `self`. + #[ensures(|result| (core::mem::size_of::() == 0) || kani::mem::same_allocation(self as *const T, *result as *const T))] pub const unsafe fn offset(self, count: isize) -> *mut T where T: Sized, @@ -998,6 +1018,23 @@ impl *mut T { #[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 + // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned. + // These conditions are not verified as part of the preconditions. + #[requires( + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize` + count.checked_mul(core::mem::size_of::()).is_some() && + count * core::mem::size_of::() <= isize::MAX as usize && + // Precondition 2: adding the computed offset to `self` does not cause overflow + (self as isize).checked_add((count * core::mem::size_of::()) as isize).is_some() && + // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. + // Otherwise, for non-unit types, `self` and `self.wrapping_add(count)` should point to the same allocated object, + // restricting `count` to prevent crossing allocation boundaries. + ((core::mem::size_of::() == 0) || (kani::mem::same_allocation(self, self.wrapping_add(count)))) + )] + // Postcondition: If `T` is a unit type (`size_of::() == 0`), no allocation check is needed. + // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object, + // verifying that the result remains within the same allocation as `self`. + #[ensures(|result| (core::mem::size_of::() == 0) || kani::mem::same_allocation(self as *const T, *result as *const T))] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -1107,6 +1144,23 @@ impl *mut T { #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_neg))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned. + // These conditions are not verified as part of the preconditions. + #[requires( + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize` + count.checked_mul(core::mem::size_of::()).is_some() && + count * core::mem::size_of::() <= isize::MAX as usize && + // Precondition 2: subtracting the computed offset from `self` does not cause overflow + (self as isize).checked_sub((count * core::mem::size_of::()) as isize).is_some() && + // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. + // Otherwise, for non-unit types, `self` and `self.wrapping_sub(count)` should point to the same allocated object, + // restricting `count` to prevent crossing allocation boundaries. + ((core::mem::size_of::() == 0) || (kani::mem::same_allocation(self, self.wrapping_sub(count)))) + )] + // Postcondition: If `T` is a unit type (`size_of::() == 0`), no allocation check is needed. + // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object, + // verifying that the result remains within the same allocation as `self`. + #[ensures(|result| (core::mem::size_of::() == 0) || kani::mem::same_allocation(self as *const T, *result as *const T))] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -2302,3 +2356,126 @@ impl PartialOrd for *mut T { *self >= *other } } + +#[cfg(kani)] +#[unstable(feature = "kani", issue = "none")] +mod verify { + use crate::kani; + + /// This macro generates proofs for contracts on `add`, `sub`, and `offset` + /// operations for pointers to integer, composite, and unit types. + /// - `$type`: Specifies the pointee type. + /// - `$proof_name`: Specifies the name of the generated proof for contract. + macro_rules! generate_mut_arithmetic_harness { + ($type:ty, $proof_name:ident, add) => { + #[kani::proof_for_contract(<*mut $type>::add)] + pub fn $proof_name() { + // 200 bytes are large enough to cover all pointee types used for testing + const BUF_SIZE: usize = 200; + let mut generator = kani::PointerGenerator::::new(); + let test_ptr: *mut $type = generator.any_in_bounds().ptr; + let count: usize = kani::any(); + unsafe { + test_ptr.add(count); + } + } + }; + ($type:ty, $proof_name:ident, sub) => { + #[kani::proof_for_contract(<*mut $type>::sub)] + pub fn $proof_name() { + // 200 bytes are large enough to cover all pointee types used for testing + const BUF_SIZE: usize = 200; + let mut generator = kani::PointerGenerator::::new(); + let test_ptr: *mut $type = generator.any_in_bounds().ptr; + let count: usize = kani::any(); + unsafe { + test_ptr.sub(count); + } + } + }; + ($type:ty, $proof_name:ident, offset) => { + #[kani::proof_for_contract(<*mut $type>::offset)] + pub fn $proof_name() { + // 200 bytes are large enough to cover all pointee types used for testing + const BUF_SIZE: usize = 200; + let mut generator = kani::PointerGenerator::::new(); + let test_ptr: *mut $type = generator.any_in_bounds().ptr; + let count: isize = kani::any(); + unsafe { + test_ptr.offset(count); + } + } + }; + } + + // <*mut T>:: add() integer types verification + generate_mut_arithmetic_harness!(i8, check_mut_add_i8, add); + generate_mut_arithmetic_harness!(i16, check_mut_add_i16, add); + generate_mut_arithmetic_harness!(i32, check_mut_add_i32, add); + generate_mut_arithmetic_harness!(i64, check_mut_add_i64, add); + generate_mut_arithmetic_harness!(i128, check_mut_add_i128, add); + generate_mut_arithmetic_harness!(isize, check_mut_add_isize, add); + // Due to a bug of kani this test case is malfunctioning for now. + // Tracking issue: https://github.com/model-checking/kani/issues/3743 + // generate_mut_arithmetic_harness!(u8, check_mut_add_u8, add); + generate_mut_arithmetic_harness!(u16, check_mut_add_u16, add); + generate_mut_arithmetic_harness!(u32, check_mut_add_u32, add); + generate_mut_arithmetic_harness!(u64, check_mut_add_u64, add); + generate_mut_arithmetic_harness!(u128, check_mut_add_u128, add); + generate_mut_arithmetic_harness!(usize, check_mut_add_usize, add); + + // <*mut T>:: add() unit type verification + generate_mut_arithmetic_harness!((), check_mut_add_unit, add); + + // <*mut T>:: add() composite types verification + generate_mut_arithmetic_harness!((i8, i8), check_mut_add_tuple_1, add); + generate_mut_arithmetic_harness!((f64, bool), check_mut_add_tuple_2, add); + generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_add_tuple_3, add); + generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_add_tuple_4, add); + + // <*mut T>:: sub() integer types verification + generate_mut_arithmetic_harness!(i8, check_mut_sub_i8, sub); + generate_mut_arithmetic_harness!(i16, check_mut_sub_i16, sub); + generate_mut_arithmetic_harness!(i32, check_mut_sub_i32, sub); + generate_mut_arithmetic_harness!(i64, check_mut_sub_i64, sub); + generate_mut_arithmetic_harness!(i128, check_mut_sub_i128, sub); + generate_mut_arithmetic_harness!(isize, check_mut_sub_isize, sub); + generate_mut_arithmetic_harness!(u8, check_mut_sub_u8, sub); + generate_mut_arithmetic_harness!(u16, check_mut_sub_u16, sub); + generate_mut_arithmetic_harness!(u32, check_mut_sub_u32, sub); + generate_mut_arithmetic_harness!(u64, check_mut_sub_u64, sub); + generate_mut_arithmetic_harness!(u128, check_mut_sub_u128, sub); + generate_mut_arithmetic_harness!(usize, check_mut_sub_usize, sub); + + // <*mut T>:: sub() unit type verification + generate_mut_arithmetic_harness!((), check_mut_sub_unit, sub); + + // <*mut T>:: sub() composite types verification + generate_mut_arithmetic_harness!((i8, i8), check_mut_sub_tuple_1, sub); + generate_mut_arithmetic_harness!((f64, bool), check_mut_sub_tuple_2, sub); + generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_sub_tuple_3, sub); + generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_sub_tuple_4, sub); + + // fn <*mut T>::offset() integer types verification + generate_mut_arithmetic_harness!(i8, check_mut_offset_i8, offset); + generate_mut_arithmetic_harness!(i16, check_mut_offset_i16, offset); + generate_mut_arithmetic_harness!(i32, check_mut_offset_i32, offset); + generate_mut_arithmetic_harness!(i64, check_mut_offset_i64, offset); + generate_mut_arithmetic_harness!(i128, check_mut_offset_i128, offset); + generate_mut_arithmetic_harness!(isize, check_mut_offset_isize, offset); + generate_mut_arithmetic_harness!(u8, check_mut_offset_u8, offset); + generate_mut_arithmetic_harness!(u16, check_mut_offset_u16, offset); + generate_mut_arithmetic_harness!(u32, check_mut_offset_u32, offset); + generate_mut_arithmetic_harness!(u64, check_mut_offset_u64, offset); + generate_mut_arithmetic_harness!(u128, check_mut_offset_u128, offset); + generate_mut_arithmetic_harness!(usize, check_mut_offset_usize, offset); + + // fn <*mut T>::offset() unit type verification + generate_mut_arithmetic_harness!((), check_mut_offset_unit, offset); + + // fn <*mut T>::offset() composite type verification + generate_mut_arithmetic_harness!((i8, i8), check_mut_offset_tuple_1, offset); + generate_mut_arithmetic_harness!((f64, bool), check_mut_offset_tuple_2, offset); + generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_offset_tuple_3, offset); + generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_offset_tuple_4, offset); +} From f87b1aec2b0489b90c719ddb8b63caa19d2305d1 Mon Sep 17 00:00:00 2001 From: MWDZ <101102544+MWDZ@users.noreply.github.com> Date: Thu, 28 Nov 2024 03:00:49 -0800 Subject: [PATCH 03/13] Harnesses for `count_bytes` (#191) Towards #150 Changes Added harnesses for count_bytes Verification Result ``` Checking harness ffi::c_str::verify::check_count_bytes... VERIFICATION RESULT: ** 0 of 241 failed (5 unreachable) VERIFICATION:- SUCCESSFUL Verification Time: 5.377671s ``` --- library/core/src/ffi/c_str.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 2a65b2415f7d3..05506aa4fb19d 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -875,4 +875,27 @@ mod verify { assert!(c_str.is_safe()); } } + + #[kani::proof] + #[kani::unwind(32)] + fn check_count_bytes() { + const MAX_SIZE: usize = 32; + let mut bytes: [u8; MAX_SIZE] = kani::any(); + + // Non-deterministically generate a length within the valid range [0, MAX_SIZE] + let mut len: usize = kani::any_where(|&x| x < MAX_SIZE); + + // If a null byte exists before the generated length + // adjust len to its position + if let Some(pos) = bytes[..len].iter().position(|&x| x == 0) { + len = pos; + } else { + // If no null byte, insert one at the chosen length + bytes[len] = 0; + } + + let c_str = CStr::from_bytes_until_nul(&bytes).unwrap(); + // Verify that count_bytes matches the adjusted length + assert_eq!(c_str.count_bytes(), len); + } } \ No newline at end of file From 7174196b983d3a7188acc0495828a3ca47a61078 Mon Sep 17 00:00:00 2001 From: Yenyun035 <57857379+Yenyun035@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:07:55 -0800 Subject: [PATCH 04/13] Harnesses for `to_bytes` and `to_bytes_with_nul` (#189) Towards #150 ### Changes * Added harnesses for `to_bytes` and `to_bytes_with_nul` * Added a small fix to `count_bytes` Verification Result: ``` Checking harness ffi::c_str::verify::check_to_bytes_with_nul... VERIFICATION RESULT: ** 0 of 179 failed (5 unreachable) VERIFICATION:- SUCCESSFUL Verification Time: 88.397385s Checking harness ffi::c_str::verify::check_to_bytes... VERIFICATION RESULT: ** 0 of 180 failed (5 unreachable) VERIFICATION:- SUCCESSFUL Verification Time: 79.66312s Checking harness ffi::c_str::verify::check_from_bytes_until_nul... VERIFICATION RESULT: ** 0 of 132 failed (5 unreachable) VERIFICATION:- SUCCESSFUL Verification Time: 28.593569s Complete - 3 successfully verified harnesses, 0 failures, 3 total. ``` --- library/core/src/ffi/c_str.rs | 45 ++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 05506aa4fb19d..2e4fcbcafe6cf 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -859,6 +859,15 @@ impl FusedIterator for Bytes<'_> {} #[unstable(feature = "kani", issue = "none")] mod verify { use super::*; + + // Helper function + fn arbitrary_cstr(slice: &[u8]) -> &CStr { + let result = CStr::from_bytes_until_nul(&slice); + kani::assume(result.is_ok()); + let c_str = result.unwrap(); + assert!(c_str.is_safe()); + c_str + } // pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> #[kani::proof] @@ -875,7 +884,8 @@ mod verify { assert!(c_str.is_safe()); } } - + + // pub const fn count_bytes(&self) -> usize #[kani::proof] #[kani::unwind(32)] fn check_count_bytes() { @@ -897,5 +907,38 @@ mod verify { let c_str = CStr::from_bytes_until_nul(&bytes).unwrap(); // Verify that count_bytes matches the adjusted length assert_eq!(c_str.count_bytes(), len); + assert!(c_str.is_safe()); + } + + // pub const fn to_bytes(&self) -> &[u8] + #[kani::proof] + #[kani::unwind(32)] + fn check_to_bytes() { + const MAX_SIZE: usize = 32; + let string: [u8; MAX_SIZE] = kani::any(); + let slice = kani::slice::any_slice_of_array(&string); + let c_str = arbitrary_cstr(slice); + + let bytes = c_str.to_bytes(); + let end_idx = bytes.len(); + // Comparison does not include the null byte + assert_eq!(bytes, &slice[..end_idx]); + assert!(c_str.is_safe()); + } + + // pub const fn to_bytes_with_nul(&self) -> &[u8] + #[kani::proof] + #[kani::unwind(33)] + fn check_to_bytes_with_nul() { + const MAX_SIZE: usize = 32; + let string: [u8; MAX_SIZE] = kani::any(); + let slice = kani::slice::any_slice_of_array(&string); + let c_str = arbitrary_cstr(slice); + + let bytes = c_str.to_bytes_with_nul(); + let end_idx = bytes.len(); + // Comparison includes the null byte + assert_eq!(bytes, &slice[..end_idx]); + assert!(c_str.is_safe()); } } \ No newline at end of file From 8fe8f562171f4b696234c1313a25418878c1b885 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 29 Nov 2024 11:00:10 -0800 Subject: [PATCH 05/13] Squashed 'library/' changes from 771d77c7cfa..78fc550584d MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 78fc550584d Auto merge of #133247 - GuillaumeGomez:reduce-integer-display-impl, r=workingjubilee db5c2c6a18f Rollup merge of #132982 - suaviloquence:2-doc-changed-alloc-methods, r=Mark-Simulacrum 117ad4f17b0 Rollup merge of #132533 - SUPERCILEX:patch-4, r=Mark-Simulacrum e2aa7c108dc fix `Allocator` method names in `alloc` free function docs 6b141ee1007 Rollup merge of #133298 - n0toose:remove-dir-all-but-not-paths, r=Noratrieb e3691db3d70 Rollup merge of #133260 - compiler-errors:deref, r=fee1-dead 895f290b058 Rollup merge of #132730 - joboet:after_main_sync, r=Noratrieb 6ffa4556f46 Rollup merge of #133389 - eduardosm:stabilize-const_float_methods, r=RalfJung f4139353bf6 Rollup merge of #133301 - GuillaumeGomez:add-example-wrapping-neg, r=workingjubilee 6112cfd51ba Auto merge of #132611 - compiler-errors:async-prelude, r=ibraheemdev 23a5a0e1f54 Auto merge of #132597 - lukas-code:btree-plug-leak, r=jhpratt f0b0942f402 Constify Deref and DerefMut d05e8e8e9fb Auto merge of #133379 - jieyouxu:rollup-00jxo71, r=jieyouxu 641c1ae3978 Stabilize `const_float_methods` 256c54db000 Auto merge of #133377 - jieyouxu:rollup-n536hzq, r=jieyouxu dff533fc1d3 Improve code by using `unsigned_abs` a850f7c8760 Rollup merge of #133237 - fee1-dead-contrib:constadd, r=compiler-errors 99741dd6dcb Rollup merge of #133332 - bjoernager:const-array-as-mut-slice, r=jhpratt 9a152e2565f Rollup merge of #131505 - madsmtm:darwin_user_temp_dir, r=dtolnay a12c8386f5b Auto merge of #132994 - clubby789:cc-bisect, r=Kobzol 6548ad8c627 Auto merge of #133360 - compiler-errors:rollup-a2o38tq, r=compiler-errors a4f797ed7de Rollup merge of #133264 - lolbinarycat:os-string-truncate, r=joboet a9398015dc4 Auto merge of #132329 - compiler-errors:fn-and-destruct, r=lcnr 30aa6db150e Add code example for `wrapping_neg` method for signed integers bc77567dc6b Deduplicate checking drop terminator 6f3ec5caf86 Gate const drop behind const_destruct feature, and fix const_precise_live_drops post-drop-elaboration check fb6f0c2e982 Auto merge of #133339 - jieyouxu:rollup-gav0nvr, r=jieyouxu c792ef3e01a Rollup merge of #133337 - ColinFinck:thread-scoped-fix-typo, r=joboet cfed1c696dd Rollup merge of #133330 - RalfJung:close, r=the8472 e26edf01cab Rollup merge of #133313 - thesummer:fix-arc4random, r=cuviper 90a85ef0042 Rollup merge of #133288 - bjoernager:const-array-each-ref, r=jhpratt 4e6f154dba6 Rollup merge of #133238 - heiher:loong-stdarch-rexport, r=Amanieu 23a1b31cfa4 Auto merge of #130867 - michirakara:steps_between, r=dtolnay 9693572a6e3 Fix typo in `std::thread::Scope::spawn` documentation. b4a50679016 Mark '<[T; N]>::as_mut_slice' as 'const'; b6b40efcac5 library: update comment around close() 6ce7e79948e Don't try to use confstr in Miri 40d6e2ca941 Auto merge of #129238 - umgefahren:stabilize-ipv6-unique-local, r=dtolnay 276c0fc3fd1 distinguish overflow and unimplemented in Step::steps_between 8be952bbbdf Use arc4random of libc for RTEMS target 4583ddef0cd Mention that std::fs::remove_dir_all fails on files 4f6ca37539a Mark and implement 'each_ref' and 'each_mut' in '[T; N]' as const; ec220b6b368 constify `Add` 3c558bf870d Rollup merge of #131736 - hoodmane:emscripten-wasm-bigint, r=workingjubilee 38d4c11c3ff implement OsString::truncate 4fd2c8db81e Rollup merge of #133226 - compiler-errors:opt-in-pointer-like, r=lcnr 3f03a0f3fcd Rollup merge of #130800 - bjoernager:const-mut-cursor, r=joshtriplett eea7e230c2b Rollup merge of #129838 - Ayush1325:uefi-process-args, r=joboet 8b4995aad87 Make PointerLike opt-in as a trait f74b38aa2b1 Reduce integer `Display` implementation size 2f179d1a7c9 Stabilize const_pin_2 b2dc297e863 re-export `is_loongarch_feature_detected` e26c298e75c Rollup merge of #132732 - gavincrawford:as_ptr_attribute, r=Urgau d6ee9dbe8b0 Rollup merge of #133183 - n0toose:improve-remove-dir-docs, r=joboet 40735d31322 Rollup merge of #125405 - m-ou-se:thread-add-spawn-hook, r=WaffleLapkin 6c20348f356 Rollup merge of #123947 - zopsicle:vec_deque-Iter-as_slices, r=Amanieu 2089cb3188c Update doc comments for spawn hook. c02090d6a3a Address review comments. 79bffa90cfe Fix tracking issue. 3eff64c78b0 Add tracking issue. 15bac4f115e Use Send + Sync for spawn hooks. a42af062212 Add thread Builder::no_hooks(). 49ac15b192b Update thread spawn hooks. 2cc4b2ef6d9 Use add_spawn_hook for libtest's output capturing. 24a0765dd03 Add std::thread::add_spawn_hook. 50ac72542be Correct comments concerning updated dangling pointer lint cdf54869ec6 Auto merge of #133205 - matthiaskrgr:rollup-xhhhp5u, r=matthiaskrgr 543667a49e3 Rollup merge of #133200 - RalfJung:miri-rwlock-test, r=tgross35 7430eb407e2 ignore an occasionally-failing test in Miri 607b493008b Rollup merge of #133182 - RalfJung:const-panic-inline, r=tgross35 e6cd122d981 Rollup merge of #132758 - nnethercote:improve-get_key_value-docs, r=cuviper a3c95972a3b Mention std::fs::remove_dir_all in std::fs::remove_dir bd5c1426568 Bump `stdarch` to the latest master e84f865601d const_panic: inline in bootstrap builds to avoid f16/f128 crashes 05fecb95df2 std: allow after-main use of synchronization primitives c1beb25002a Auto merge of #133160 - jhpratt:rollup-wzj9q15, r=jhpratt ce80c9f20de Rollup merge of #133145 - kornelski:static-mutex, r=traviscross f385ac21fee Auto merge of #128219 - connortsui20:rwlock-downgrade, r=tgross35 86151abcc67 rename rustc_const_stable_intrinsic -> rustc_intrinsic_const_stable_indirect a33f889e959 Improve `{BTreeMap,HashMap}::get_key_value` docs. 15e6fc0a5db Document alternatives to `static mut` 1cd1dd7c56f Auto merge of #120370 - x17jiri:likely_unlikely_fix, r=saethlin e475f40115f Likely unlikely fix ddcabfe85ff Rollup merge of #133126 - ohno418:fix-String-doc, r=jhpratt e4eff6a5a78 Rollup merge of #133116 - RalfJung:const-null-ptr, r=dtolnay 16e6d209ccb alloc: fix `String`'s doc e4fb96229e0 clean up const stability around UB checks ee78601c3ce stabilize const_ptr_is_null 1e4a9ee22cd Rollup merge of #132449 - RalfJung:is_val_statically_known, r=compiler-errors 1dfe94c308a Rollup merge of #131717 - tgross35:stabilize-const_atomic_from_ptr, r=RalfJung 70326e8f708 reduce threads in downgrade test d58e4f2d08c fix `DOWNGRADED` bit unpreserved 5d683160ada fix memory ordering bug + bad test 0604b8ffc1d add safety comments for queue implementation 00255e627b7 add `downgrade` to `queue` implementation 40256c63003 modify queue implementation documentation f8041644f07 add `downgrade` to `futex` implementation 572adedb6a0 add simple `downgrade` implementations 48bcf09d8d7 add `downgrade` method onto `RwLockWriteGuard` 5416aef6a86 add `RwLock` `downgrade` tests 40109807569 Rollup merge of #133050 - tgross35:inline-f16-f128, r=saethlin 2ee4159af2a Rollup merge of #133048 - cyrgani:ptr-doc-update, r=Amanieu e1448dee6d0 Rollup merge of #133019 - sorairolake:add-missing-period-and-colon, r=tgross35 b1d31d297f2 Rollup merge of #132984 - sunshowers:pipe2, r=tgross35 8cef1ef708e Rollup merge of #132977 - cberner:fix_solaris, r=tgross35 daa9c433370 Rollup merge of #132790 - aDotInTheVoid:ioslice-asslice-rides-again, r=cuviper cdb5ff5f6fe Pass `f16` and `f128` by value in `const_assert!` 60ef4797595 use `&raw` in `{read, write}_unaligned` documentation d2983fffb15 Auto merge of #132709 - programmerjake:optimize-charto_digit, r=joshtriplett 918cc8d59c8 Rollup merge of #133027 - no1wudi:master, r=jhpratt 25f55123bf2 Auto merge of #133026 - workingjubilee:rollup-q8ig6ah, r=workingjubilee d8de2ccfc55 Fix a copy-paste issue in the NuttX raw type definition c06bb349936 Rollup merge of #133008 - onur-ozkan:update-outdated-comment, r=jieyouxu 8eaea39049a Rollup merge of #133004 - cuviper:unrecover-btree, r=ibraheemdev 81a191a826e Rollup merge of #133003 - zachs18:clonetouninit-dyn-compat-u8, r=dtolnay e3e5e358c71 Rollup merge of #132907 - BLANKatGITHUB:intrinsic, r=saethlin f57853bc421 Rollup merge of #131304 - RalfJung:float-core, r=tgross35 7bc04367d32 Auto merge of #122770 - iximeow:ixi/int-formatting-optimization, r=workingjubilee ce2e318c5d1 docs: Fix missing colon in methods for primitive types 1870e9269bf docs: Fix missing period in methods for integer types 64397743828 Auto merge of #133006 - matthiaskrgr:rollup-dz6oiq5, r=matthiaskrgr 98dad0baf9a update outdated comment about test-float-parse 520d4fdff72 Rollup merge of #126046 - davidzeng0:mixed_integer_ops_unsigned_sub, r=Amanieu e3c425b74bb Auto merge of #132662 - RalfJung:const-panic-inlining, r=tgross35 c4b77cf11ef Update core CloneToUninit tests d4e21f55ec3 btree: simplify the backdoor between set and map 5d61cf9a7ea Bump `cc` 44f376ba0c7 Fix compilation error on Solaris due to flock usage 75609d6d329 Auto merge of #132556 - clubby789:cargo-update, r=Mark-Simulacrum 5ba28a4d89a Run `cargo update` and update licenses 08200043034 const_panic: don't wrap it in a separate function d30e2c0963b [illumos] use pipe2 to create anonymous pipes 7e12686e222 Auto merge of #132883 - LaihoE:vectorized_is_sorted, r=thomcc 02e32d70d61 Auto merge of #132972 - matthiaskrgr:rollup-456osr7, r=matthiaskrgr 157eb1c94be Rollup merge of #132970 - tyilo:nonzero-u-div-ceil-issue, r=tgross35 03e52a50ac8 Rollup merge of #132966 - RalfJung:const_option_ext, r=jhpratt 2f615a1c410 Rollup merge of #132948 - RalfJung:const_unicode_case_lookup, r=Noratrieb f00e0913f63 Rollup merge of #132851 - chansuke:update-comment, r=thomcc 656009854a3 Auto merge of #132870 - Noratrieb:inline-int-parsing, r=tgross35 a0c0c40eafd Add tracking issue number to unsigned_nonzero_div_ceil feature c2296662624 Make `CloneToUninit` dyn-compatible 6ab50dd1c97 stabilize const_option_ext 27fe6c7ca46 Rollup merge of #132541 - RalfJung:const-stable-extern-crate, r=compiler-errors 7fafe990a8b stabilize const_unicode_case_lookup c5ed62506ae Stabilize `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local` e0452c9af5e adds new declaration to codegen 33fa8701b27 Auto merge of #132943 - matthiaskrgr:rollup-164l3ej, r=matthiaskrgr 7f12f02c6ec Rollup merge of #132914 - rcorre:cell-grammar, r=tgross35 300a2664117 Rollup merge of #132895 - scottmcm:generalize-nonnull-from-raw-parts, r=ibraheemdev a461cf9310e remove no-longer-needed abs_private 170e993a781 allow rustc_private feature in force-unstable-if-unmarked crates 4a20245f4ad Rollup merge of #132929 - cuviper:check-alloc_zeroed, r=tgross35 992bbf7c46c Rollup merge of #132869 - lolbinarycat:library-fix-too_long_first_doc_paragraph, r=tgross35 e3925fa3b42 Rollup merge of #132847 - RalfJung:addr-dont-expose, r=Mark-Simulacrum 327a0d7814e Auto merge of #132919 - matthiaskrgr:rollup-ogghyvp, r=matthiaskrgr 67c3c9f8bb7 Check for null in the `alloc_zeroed` example 068537aeb72 new intrinsic declaration b689951272e new intrinsic declaration 16fa12ebd98 Rollup merge of #132144 - adetaylor:receiver-trait-itself, r=wesleywiser 54f699d3ee9 Rollup merge of #120077 - SUPERCILEX:set-entry, r=Amanieu e541a4f8204 Update dangling pointer tests 7707584415a Tag relevant functions with #[rustc_as_ptr] attribute b541c5aebc8 Auto merge of #132902 - matthiaskrgr:rollup-43qgg3t, r=matthiaskrgr 2d676d49a6e Update grammar in std::cell docs. 7325f33701c Emscripten: link with -sWASM_BIGINT 1c482c93dbd Rollup merge of #130999 - cberner:flock_pr, r=joboet 4dd22707d54 Auto merge of #127589 - notriddle:notriddle/search-sem-3, r=GuillaumeGomez 0af64b63ced Generalize `NonNull::from_raw_parts` per ACP362 2fd9ac4a7ba vectorize slice::is_sorted 737521c21f5 `#[inline]` integer parsing functions b9be1ddefcb split up the first paragraph of doc comments for better summaries f9063ff15cf Update the doc comment of `ASCII_CASE_MASK` 57c7b80414a elem_offset / subslice_range: use addr() instead of 'as usize' d19aa692d4e Rollup merge of #132136 - RalfJung:target-feature-abi-compat, r=Mark-Simulacrum 6b0bd5a6630 honor rustc_const_stable_indirect in non-staged_api crate with -Zforce-unstable-if-unmarked 070baf4fab5 Add as_slice/into_slice for IoSlice/IoSliceMut. 978a5535d35 Rollup merge of #132778 - lolbinarycat:io-Error-into_inner-docs, r=cuviper 6d54bfe5925 update io::Error::into_inner to acknowlage io::Error::other 7c0a90c3ead Address review comments ac66068ca8b Update library/std/src/sys/pal/windows/fs.rs d90f8668e45 Auto merge of #132717 - RalfJung:rustc_safe_intrinsic, r=compiler-errors f2bf9e65116 remove support for rustc_safe_intrinsic attribute; use rustc_intrinsic functions instead 2391b4b2a0d Rollup merge of #132738 - cuviper:channel-heap-init, r=ibraheemdev 086cfefa97e mark is_val_statically_known intrinsic as stably const-callable dffc5e73119 Rollup merge of #132696 - fortanix:raoul/rte-235-fix_fmodl_missing_symbol_issue, r=tgross35 f14fc562a82 Rollup merge of #132639 - RalfJung:intrinsics, r=workingjubilee,Amanieu 6d63012a62e Initialize channel `Block`s directly on the heap 7ff251b9793 core: move intrinsics.rs into intrinsics folder 6244f4816fe Auto merge of #132714 - mati865:update-memchr, r=tgross35 a2eaef75de6 Rollup merge of #132715 - tabokie:fix-lazy-lock-doc, r=Noratrieb 6a77b2121f1 Rollup merge of #132665 - tyilo:nonzero-u-div-ceil, r=joboet 79d2063e0b6 Separate f128 `%` operation to deal with missing `fmodl` symbol 8022523cc73 Auto merge of #132705 - kornelski:inline-repeat, r=tgross35 df9f5db19d7 fix lazylock comment 7a82eb5b610 Auto merge of #131888 - ChrisDenton:deopt, r=ibraheemdev 75b9ce3b0be unpin and update memchr 4d1c7d9526a optimize char::to_digit and assert radix is at least 2 95bff3e6b5c Inline str::repeat 52c2a459546 Rollup merge of #132617 - uellenberg:fix-rendered-doc, r=cuviper 28f7e7bbbd9 Auto merge of #131721 - okaneco:const_eq_ignore_ascii_case, r=m-ou-se 41b7e5f7705 Auto merge of #132500 - RalfJung:char-is-whitespace-const, r=jhpratt 4ed08bd2262 Add new unstable feature `const_eq_ignore_ascii_case` f4e9fe4ec00 Auto merge of #132664 - matthiaskrgr:rollup-i27nr7i, r=matthiaskrgr afc66fe29e2 Change some code blocks to quotes in rendered std doc 2e63cbdb695 Rollup merge of #131261 - clarfonthey:unsafe-cell-from-mut, r=m-ou-se ab6f663ed6a Auto merge of #132661 - matthiaskrgr:rollup-npytbl6, r=matthiaskrgr 8b165db1e5c Implement div_ceil for NonZero 6bc1b1b449e Rollup merge of #132571 - RalfJung:const_eval_select_macro, r=oli-obk c12f4d12055 Rollup merge of #132473 - ZhekaS:core_fmt_radix_no_panic, r=joboet bbb927540c8 Rollup merge of #132153 - bjoernager:const-char-encode-utf16, r=dtolnay 919de701b02 add const_eval_select macro to reduce redundancy 538f5b4cd2b Rollup merge of #132609 - NotWearingPants:patch-1, r=Amanieu 86c6f276b21 Rollup merge of #132606 - eduardosm:char-slice-str-pattern-doc, r=tgross35 4660d7ebef9 most const intrinsics don't need an explicit rustc_const_unstable any more 8eb30fe4b09 add new rustc_const_stable_intrinsic attribute for const-stable intrinsics 792d1646c7c convert all const-callable intrinsics into the new form (without extern block) fad7d68d1c2 docs: fix grammar in doc comment at unix/process.rs 92bb77993bd Improve example of `impl Pattern for &[char]` 553bb181dad Add AsyncFn* to to the prelude in all editions 2ae24bf3e15 Fixed typo, rebased 47f60d7ad0d Updated SAFETY comment to address underflow 581aa8d587f Replace checked slice indexing by unchecked to support panic-free code c5a0f6c60aa Rollup merge of #132579 - RalfJung:rustc-std-workspace-crates, r=Amanieu 9cdbf39ba56 btree: don't leak value if destructor of key panics 4caff135a74 Stabilise 'const_char_encode_utf16'; 84fae7ebfee Auto merge of #132586 - workingjubilee:rollup-qrmn49a, r=workingjubilee 95b4127a6c8 update rustc-std-workspace crates 082b98d885c Rollup merge of #132423 - RalfJung:const-eval-align-offset, r=dtolnay 3b40634d007 Auto merge of #132434 - tgross35:f128-tests, r=workingjubilee 5dea8b2e41f Enable `f128` tests on all non-buggy platforms 🎉 2bb8ea389a4 Auto merge of #132581 - workingjubilee:rollup-4wj318p, r=workingjubilee 83bd286345b Update `compiler_builtins` to 0.1.138 and pin it 699702f2a6c Rollup merge of #132563 - frectonz:master, r=Amanieu 4390c35bcce Auto merge of #123723 - madsmtm:apple-std-os, r=dtolnay 1e8ed9064ee Auto merge of #132479 - compiler-errors:fx-feat-yeet, r=fee1-dead 9a3b7c0f20b Rename the FIXMEs, remove a few that dont matter anymore ed4f110b101 Auto merge of #132542 - RalfJung:const_panic, r=tgross35 d8bca01fc2b remove const-support for align_offset 76b866c7156 Modify `NonZero` documentation to reference the underlying integer type 9e579641927 Rollup merge of #132511 - RalfJung:const_arguments_as_str, r=dtolnay bfeeb7450fd Rollup merge of #132503 - RalfJung:const-hash-map, r=Amanieu a42fc213104 Rollup merge of #132499 - RalfJung:unicode_data.rs, r=tgross35 0278cab1fcc Rollup merge of #132393 - zedddie16:issue-131865-fix, r=tgross35 714115abfb6 Rollup merge of #131377 - rick-de-water:nonzero-exp, r=dtolnay 9789c548b8c Rollup merge of #129329 - eduardosm:rc-from-mut-slice, r=dtolnay ff9178b1a6a add const_panic macro to make it easier to fall back to non-formatting panic in const 9ef483bbbb0 stabilize const_arguments_as_str 4c6593fe8f8 Auto merge of #132458 - RalfJung:rustc-const-unstable, r=Amanieu 81b20e0a3dd Rustdoc: added brief colon explanation 73d9f4da9a9 Add Set entry API e883a6074c2 Add BorrowedBuf::into_filled{,_mut} methods to allow returning buffer with original lifetime 261c5b998ad remove const_hash feature leftovers d515da6678b const_with_hasher test: actually construct a usable HashMap 11dc6c388d9 make char::is_whitespace unstably const 1a481fd9e01 unicode_data.rs: show command for generating file 3a5b026c04a get rid of a whole bunch of unnecessary rustc_const_unstable attributes 2e24b7fba4b remove no-longer-needed attribute ffbcba08e7f add missing safety comments 768d0cd7fe4 adjust test gating for f16/f128 6335056119f float types: move copysign, abs, signum to libcore c353337b8d0 rustdoc-search: simplify rules for generics and type params 9d10ab71105 Implement `From<&mut {slice}>` for `Box/Rc/Arc<{slice}>` 34329c06529 Stabilize `const_atomic_from_ptr` a2e1edf18f6 Arbitrary self types v2: (unused) Receiver trait 2d26681057c ABI compatibility: remove section on target features f1c99041c25 Support lock() and lock_shared() on async IO Files 7f6af4dd882 Revert using `HEAP` static in Windows alloc 541bda102a0 Implement file_lock feature d7a7b0a361b uefi: process: Add args support 14aef3d76cf Use with_capacity(0) because we're reading the capacity later on 5b16abea8d5 Prefer `target_vendor = "apple"` on confstr bc6398107f8 use `confstr(_CS_DARWIN_USER_TEMP_DIR, ...)` as a `TMPDIR` fallback on darwin f8dc879fa96 Add LowerExp and UpperExp implementations 50afc521a17 Stabilize UnsafeCell::from_mut aa74e934264 Mark 'get_mut' and 'set_position' in 'std::io::Cursor' as const; c370665e88b Make `std::os::darwin` public 797c2498600 Implement `mixed_integer_ops_unsigned_sub` ff1212e6a22 Add vec_deque::Iter::as_slices and friends e938deaf0f1 try adding a test that LowerHex and friends don't panic, but it doesn't work c6d2bb7445c improve codegen of fmt_num to delete unreachable panic git-subtree-dir: library git-subtree-split: 78fc550584dcdf3f917cc399f8ae1f1001887f09 --- Cargo.lock | 29 +- alloc/Cargo.toml | 2 +- alloc/src/alloc.rs | 13 +- alloc/src/boxed.rs | 11 +- alloc/src/boxed/convert.rs | 45 + alloc/src/collections/btree/map.rs | 86 +- alloc/src/collections/btree/map/tests.rs | 48 + alloc/src/collections/btree/mod.rs | 8 - alloc/src/collections/btree/node.rs | 18 +- alloc/src/collections/btree/set.rs | 7 +- alloc/src/collections/btree/set_val.rs | 4 +- alloc/src/collections/vec_deque/iter.rs | 34 + alloc/src/collections/vec_deque/iter_mut.rs | 107 + alloc/src/ffi/c_str.rs | 31 + alloc/src/fmt.rs | 10 + alloc/src/lib.rs | 2 + alloc/src/rc.rs | 47 +- alloc/src/str.rs | 1 + alloc/src/string.rs | 2 +- alloc/src/sync.rs | 47 +- alloc/src/task.rs | 8 +- alloc/src/vec/mod.rs | 2 + core/benches/fmt.rs | 14 + core/src/array/iter.rs | 2 - core/src/array/mod.rs | 37 +- core/src/cell.rs | 14 +- core/src/char/methods.rs | 106 +- core/src/clone.rs | 29 +- core/src/ffi/c_str.rs | 102 +- core/src/fmt/float.rs | 2 +- core/src/fmt/mod.rs | 3 +- core/src/fmt/num.rs | 93 +- core/src/future/future.rs | 1 + core/src/hash/sip.rs | 12 +- core/src/intrinsics.rs | 3747 --------------- core/src/intrinsics/mod.rs | 4528 +++++++++++++++++++ core/src/io/borrowed_buf.rs | 20 + core/src/iter/range.rs | 128 +- core/src/lib.rs | 22 +- core/src/marker.rs | 14 +- core/src/mem/maybe_uninit.rs | 8 +- core/src/net/ip_addr.rs | 11 +- core/src/num/dec2flt/mod.rs | 2 +- core/src/num/f128.rs | 142 +- core/src/num/f16.rs | 139 +- core/src/num/f32.rs | 131 +- core/src/num/f64.rs | 131 +- core/src/num/int_macros.rs | 29 +- core/src/num/mod.rs | 34 +- core/src/num/nonzero.rs | 86 +- core/src/num/uint_macros.rs | 145 +- core/src/ops/arith.rs | 13 + core/src/ops/deref.rs | 135 +- core/src/ops/drop.rs | 2 +- core/src/ops/function.rs | 6 +- core/src/ops/mod.rs | 3 + core/src/option.rs | 9 +- core/src/panic.rs | 57 + core/src/panic/panic_info.rs | 3 +- core/src/panicking.rs | 62 +- core/src/pin.rs | 6 +- core/src/primitive_docs.rs | 32 +- core/src/ptr/const_ptr.rs | 331 +- core/src/ptr/mod.rs | 40 +- core/src/ptr/mut_ptr.rs | 277 +- core/src/ptr/non_null.rs | 181 +- core/src/result.rs | 1 + core/src/slice/ascii.rs | 183 +- core/src/slice/index.rs | 68 +- core/src/slice/memchr.rs | 101 +- core/src/slice/mod.rs | 28 +- core/src/slice/raw.rs | 4 +- core/src/slice/sort/shared/smallsort.rs | 2 +- core/src/str/converts.rs | 3 - core/src/str/mod.rs | 7 +- core/src/str/pattern.rs | 4 +- core/src/str/validations.rs | 23 +- core/src/sync/atomic.rs | 6 +- core/src/sync/exclusive.rs | 2 - core/src/task/wake.rs | 7 - core/src/time.rs | 2 - core/src/ub_checks.rs | 87 +- core/src/unicode/unicode_data.rs | 10 +- core/tests/clone.rs | 12 +- core/tests/iter/traits/step.rs | 35 +- core/tests/lib.rs | 9 +- core/tests/nonzero.rs | 11 + core/tests/ptr.rs | 257 -- profiler_builtins/Cargo.toml | 2 +- rustc-std-workspace-core/README.md | 3 + std/Cargo.toml | 8 +- std/build.rs | 19 +- std/src/collections/hash/map.rs | 40 +- std/src/collections/hash/map/tests.rs | 26 +- std/src/collections/hash/set.rs | 449 ++ std/src/env.rs | 15 +- std/src/f128.rs | 98 - std/src/f128/tests.rs | 22 +- std/src/f16.rs | 97 - std/src/f32.rs | 84 - std/src/f64.rs | 84 - std/src/ffi/os_str.rs | 47 +- std/src/ffi/os_str/tests.rs | 4 +- std/src/fs.rs | 224 +- std/src/fs/tests.rs | 146 + std/src/hash/random.rs | 3 +- std/src/io/cursor.rs | 6 +- std/src/io/error.rs | 6 +- std/src/io/mod.rs | 45 + std/src/io/tests.rs | 14 + std/src/keyword_docs.rs | 6 + std/src/lib.rs | 18 +- std/src/os/darwin/fs.rs | 17 +- std/src/os/darwin/mod.rs | 5 +- std/src/os/fd/owned.rs | 21 +- std/src/os/ios/mod.rs | 2 - std/src/os/macos/mod.rs | 2 - std/src/os/mod.rs | 24 +- std/src/os/nuttx/raw.rs | 2 +- std/src/os/unix/mod.rs | 2 +- std/src/os/unix/process.rs | 2 +- std/src/path.rs | 36 +- std/src/path/tests.rs | 4 +- std/src/prelude/common.rs | 3 + std/src/sync/lazy_lock.rs | 4 +- std/src/sync/mpmc/array.rs | 6 +- std/src/sync/mpmc/context.rs | 13 +- std/src/sync/mpmc/list.rs | 11 +- std/src/sync/mpmc/mod.rs | 2 + std/src/sync/mpmc/zero.rs | 6 +- std/src/sync/mpsc/mod.rs | 2 + std/src/sync/rwlock.rs | 74 +- std/src/sync/rwlock/tests.rs | 108 + std/src/sys/alloc/windows.rs | 69 +- std/src/sys/os_str/bytes.rs | 6 +- std/src/sys/os_str/wtf8.rs | 6 +- std/src/sys/pal/hermit/fs.rs | 20 + std/src/sys/pal/hermit/io.rs | 7 +- std/src/sys/pal/solid/fs.rs | 20 + std/src/sys/pal/solid/io.rs | 7 +- std/src/sys/pal/uefi/process.rs | 68 +- std/src/sys/pal/unix/fs.rs | 117 + std/src/sys/pal/unix/io.rs | 7 +- std/src/sys/pal/unix/os.rs | 78 +- std/src/sys/pal/unix/os/tests.rs | 25 + std/src/sys/pal/unix/pipe.rs | 1 + std/src/sys/pal/unsupported/fs.rs | 20 + std/src/sys/pal/unsupported/io.rs | 7 +- std/src/sys/pal/wasi/fs.rs | 20 + std/src/sys/pal/wasi/io.rs | 7 +- std/src/sys/pal/windows/c/bindings.txt | 4 + std/src/sys/pal/windows/c/windows_sys.rs | 5 + std/src/sys/pal/windows/fs.rs | 114 + std/src/sys/pal/windows/io.rs | 7 +- std/src/sys/random/arc4random.rs | 2 - std/src/sys/sync/once/queue.rs | 9 +- std/src/sys/sync/rwlock/futex.rs | 52 +- std/src/sys/sync/rwlock/no_threads.rs | 5 + std/src/sys/sync/rwlock/queue.rs | 681 +-- std/src/sys/sync/rwlock/solid.rs | 6 + std/src/sys/sync/rwlock/teeos.rs | 6 + std/src/sys_common/wtf8.rs | 6 +- std/src/thread/current.rs | 17 + std/src/thread/mod.rs | 49 +- std/src/thread/scoped.rs | 9 +- std/src/thread/spawnhook.rs | 148 + stdarch | 2 +- test/src/lib.rs | 11 + 168 files changed, 9266 insertions(+), 6477 deletions(-) delete mode 100644 core/src/intrinsics.rs create mode 100644 core/src/intrinsics/mod.rs create mode 100644 std/src/thread/spawnhook.rs diff --git a/Cargo.lock b/Cargo.lock index 5defd2950e8ea..55851daaf2a80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,9 +42,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "cc" -version = "1.1.22" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" dependencies = [ "shlex", ] @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.136" +version = "0.1.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ccee9dd499d7ada4c81533382ce87e88c52b0676c7320b2e617d29e1bb3a3f" +checksum = "53f0ea7fff95b51f84371588f06062557e96bbe363d2b36218ddb806f3ca8611" dependencies = [ "cc", "rustc-std-workspace-core", @@ -79,9 +79,9 @@ dependencies = [ [[package]] name = "dlmalloc" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d" +checksum = "d9b5e0d321d61de16390ed273b647ce51605b575916d3c25e6ddf27a1e140035" dependencies = [ "cfg-if", "compiler_builtins", @@ -158,18 +158,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" dependencies = [ "rustc-std-workspace-core", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "compiler_builtins", "memchr", @@ -335,7 +335,6 @@ dependencies = [ "hashbrown", "hermit-abi", "libc", - "memchr", "miniz_oxide", "object", "panic_abort", @@ -428,9 +427,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] diff --git a/alloc/Cargo.toml b/alloc/Cargo.toml index a9c375b62bda9..3464047d4ee9e 100644 --- a/alloc/Cargo.toml +++ b/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.136", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.138", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/alloc/src/alloc.rs b/alloc/src/alloc.rs index a91659b6de5ad..04b7315e650a2 100644 --- a/alloc/src/alloc.rs +++ b/alloc/src/alloc.rs @@ -61,7 +61,7 @@ pub use std::alloc::Global; /// of the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. /// -/// This function is expected to be deprecated in favor of the `alloc` method +/// This function is expected to be deprecated in favor of the `allocate` method /// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety @@ -106,7 +106,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// of the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. /// -/// This function is expected to be deprecated in favor of the `dealloc` method +/// This function is expected to be deprecated in favor of the `deallocate` method /// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety @@ -125,7 +125,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { /// of the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. /// -/// This function is expected to be deprecated in favor of the `realloc` method +/// This function is expected to be deprecated in favor of the `grow` and `shrink` methods /// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety @@ -145,7 +145,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 /// of the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. /// -/// This function is expected to be deprecated in favor of the `alloc_zeroed` method +/// This function is expected to be deprecated in favor of the `allocate_zeroed` method /// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety @@ -155,11 +155,14 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 /// # Examples /// /// ``` -/// use std::alloc::{alloc_zeroed, dealloc, Layout}; +/// use std::alloc::{alloc_zeroed, dealloc, handle_alloc_error, Layout}; /// /// unsafe { /// let layout = Layout::new::(); /// let ptr = alloc_zeroed(layout); +/// if ptr.is_null() { +/// handle_alloc_error(layout); +/// } /// /// assert_eq!(*(ptr as *mut u16), 0); /// diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index e4956c7c53c8d..ee60ec0fbacbe 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -191,6 +191,8 @@ use core::error::{self, Error}; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; +#[cfg(not(bootstrap))] +use core::marker::PointerLike; use core::marker::{Tuple, Unsize}; use core::mem::{self, SizedTypeProperties}; use core::ops::{ @@ -225,6 +227,7 @@ pub use thin::ThinBox; #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] +#[cfg_attr(not(bootstrap), doc(search_unbox))] // The declaration of the `Box` struct must be kept in sync with the // compiler or ICEs will happen. pub struct Box< @@ -1499,6 +1502,7 @@ impl Box { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -1547,6 +1551,7 @@ impl Box { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -1734,7 +1739,7 @@ impl Clone for Box { // Pre-allocate memory to allow writing the cloned value directly. let mut boxed = Self::new_uninit_in(self.1.clone()); unsafe { - (**self).clone_to_uninit(boxed.as_mut_ptr()); + (**self).clone_to_uninit(boxed.as_mut_ptr().cast()); boxed.assume_init() } } @@ -2128,3 +2133,7 @@ impl Error for Box { Error::provide(&**self, request); } } + +#[cfg(not(bootstrap))] +#[unstable(feature = "pointer_like_trait", issue = "none")] +impl PointerLike for Box {} diff --git a/alloc/src/boxed/convert.rs b/alloc/src/boxed/convert.rs index 19a583ca546e4..4430fff66775c 100644 --- a/alloc/src/boxed/convert.rs +++ b/alloc/src/boxed/convert.rs @@ -109,6 +109,29 @@ impl From<&[T]> for Box<[T]> { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut [T]> for Box<[T]> { + /// Converts a `&mut [T]` into a `Box<[T]>` + /// + /// This conversion allocates on the heap + /// and performs a copy of `slice` and its contents. + /// + /// # Examples + /// ```rust + /// // create a &mut [u8] which will be used to create a Box<[u8]> + /// let mut array = [104, 101, 108, 108, 111]; + /// let slice: &mut [u8] = &mut array; + /// let boxed_slice: Box<[u8]> = Box::from(slice); + /// + /// println!("{boxed_slice:?}"); + /// ``` + #[inline] + fn from(slice: &mut [T]) -> Box<[T]> { + Self::from(&*slice) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box<[T]> { @@ -147,6 +170,28 @@ impl From<&str> for Box { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut str> for Box { + /// Converts a `&mut str` into a `Box` + /// + /// This conversion allocates on the heap + /// and performs a copy of `s`. + /// + /// # Examples + /// + /// ```rust + /// let mut original = String::from("hello"); + /// let original: &mut str = &mut original; + /// let boxed: Box = Box::from(original); + /// println!("{boxed}"); + /// ``` + #[inline] + fn from(s: &mut str) -> Box { + Self::from(&*s) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { diff --git a/alloc/src/collections/btree/map.rs b/alloc/src/collections/btree/map.rs index 55649d865fc63..213924d1d0203 100644 --- a/alloc/src/collections/btree/map.rs +++ b/alloc/src/collections/btree/map.rs @@ -289,40 +289,12 @@ impl Clone for BTreeMap { } } -impl super::Recover for BTreeMap -where - K: Borrow + Ord, - Q: Ord, -{ - type Key = K; - - fn get(&self, key: &Q) -> Option<&K> { - let root_node = self.root.as_ref()?.reborrow(); - match root_node.search_tree(key) { - Found(handle) => Some(handle.into_kv().0), - GoDown(_) => None, - } - } - - fn take(&mut self, key: &Q) -> Option { - let (map, dormant_map) = DormantMutRef::new(self); - let root_node = map.root.as_mut()?.borrow_mut(); - match root_node.search_tree(key) { - Found(handle) => Some( - OccupiedEntry { - handle, - dormant_map, - alloc: (*map.alloc).clone(), - _marker: PhantomData, - } - .remove_kv() - .0, - ), - GoDown(_) => None, - } - } - - fn replace(&mut self, key: K) -> Option { +/// Internal functionality for `BTreeSet`. +impl BTreeMap { + pub(super) fn replace(&mut self, key: K) -> Option + where + K: Ord, + { let (map, dormant_map) = DormantMutRef::new(self); let root_node = map.root.get_or_insert_with(|| Root::new((*map.alloc).clone())).borrow_mut(); @@ -705,7 +677,11 @@ impl BTreeMap { } } - /// Returns the key-value pair corresponding to the supplied key. + /// Returns the key-value pair corresponding to the supplied key. This is + /// potentially useful: + /// - for key types where non-identical keys can be considered equal; + /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or + /// - for getting a reference to a key with the same lifetime as the collection. /// /// The supplied key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. @@ -713,12 +689,46 @@ impl BTreeMap { /// # Examples /// /// ``` + /// use std::cmp::Ordering; /// use std::collections::BTreeMap; /// + /// #[derive(Clone, Copy, Debug)] + /// struct S { + /// id: u32, + /// # #[allow(unused)] // prevents a "field `name` is never read" error + /// name: &'static str, // ignored by equality and ordering operations + /// } + /// + /// impl PartialEq for S { + /// fn eq(&self, other: &S) -> bool { + /// self.id == other.id + /// } + /// } + /// + /// impl Eq for S {} + /// + /// impl PartialOrd for S { + /// fn partial_cmp(&self, other: &S) -> Option { + /// self.id.partial_cmp(&other.id) + /// } + /// } + /// + /// impl Ord for S { + /// fn cmp(&self, other: &S) -> Ordering { + /// self.id.cmp(&other.id) + /// } + /// } + /// + /// let j_a = S { id: 1, name: "Jessica" }; + /// let j_b = S { id: 1, name: "Jess" }; + /// let p = S { id: 2, name: "Paul" }; + /// assert_eq!(j_a, j_b); + /// /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); - /// assert_eq!(map.get_key_value(&2), None); + /// map.insert(j_a, "Paris"); + /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris"))); + /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case + /// assert_eq!(map.get_key_value(&p), None); /// ``` #[stable(feature = "map_get_key_value", since = "1.40.0")] pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> diff --git a/alloc/src/collections/btree/map/tests.rs b/alloc/src/collections/btree/map/tests.rs index db16d82be7dcc..5975134382e7d 100644 --- a/alloc/src/collections/btree/map/tests.rs +++ b/alloc/src/collections/btree/map/tests.rs @@ -2270,6 +2270,54 @@ fn test_into_iter_drop_leak_height_0() { assert_eq!(e.dropped(), 1); } +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_into_iter_drop_leak_kv_panic_in_key() { + let a_k = CrashTestDummy::new(0); + let a_v = CrashTestDummy::new(1); + let b_k = CrashTestDummy::new(2); + let b_v = CrashTestDummy::new(3); + let c_k = CrashTestDummy::new(4); + let c_v = CrashTestDummy::new(5); + let mut map = BTreeMap::new(); + map.insert(a_k.spawn(Panic::Never), a_v.spawn(Panic::Never)); + map.insert(b_k.spawn(Panic::InDrop), b_v.spawn(Panic::Never)); + map.insert(c_k.spawn(Panic::Never), c_v.spawn(Panic::Never)); + + catch_unwind(move || drop(map.into_iter())).unwrap_err(); + + assert_eq!(a_k.dropped(), 1); + assert_eq!(a_v.dropped(), 1); + assert_eq!(b_k.dropped(), 1); + assert_eq!(b_v.dropped(), 1); + assert_eq!(c_k.dropped(), 1); + assert_eq!(c_v.dropped(), 1); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_into_iter_drop_leak_kv_panic_in_val() { + let a_k = CrashTestDummy::new(0); + let a_v = CrashTestDummy::new(1); + let b_k = CrashTestDummy::new(2); + let b_v = CrashTestDummy::new(3); + let c_k = CrashTestDummy::new(4); + let c_v = CrashTestDummy::new(5); + let mut map = BTreeMap::new(); + map.insert(a_k.spawn(Panic::Never), a_v.spawn(Panic::Never)); + map.insert(b_k.spawn(Panic::Never), b_v.spawn(Panic::InDrop)); + map.insert(c_k.spawn(Panic::Never), c_v.spawn(Panic::Never)); + + catch_unwind(move || drop(map.into_iter())).unwrap_err(); + + assert_eq!(a_k.dropped(), 1); + assert_eq!(a_v.dropped(), 1); + assert_eq!(b_k.dropped(), 1); + assert_eq!(b_v.dropped(), 1); + assert_eq!(c_k.dropped(), 1); + assert_eq!(c_v.dropped(), 1); +} + #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_into_iter_drop_leak_height_1() { diff --git a/alloc/src/collections/btree/mod.rs b/alloc/src/collections/btree/mod.rs index c7d0144de30cb..b8667d09c33b3 100644 --- a/alloc/src/collections/btree/mod.rs +++ b/alloc/src/collections/btree/mod.rs @@ -12,11 +12,3 @@ mod search; pub mod set; mod set_val; mod split; - -trait Recover { - type Key; - - fn get(&self, key: &Q) -> Option<&Self::Key>; - fn take(&mut self, key: &Q) -> Option; - fn replace(&mut self, key: Self::Key) -> Option; -} diff --git a/alloc/src/collections/btree/node.rs b/alloc/src/collections/btree/node.rs index 2a853ef421629..64a13bb6a0b3a 100644 --- a/alloc/src/collections/btree/node.rs +++ b/alloc/src/collections/btree/node.rs @@ -1173,11 +1173,25 @@ impl Handle, marker::KV> /// The node that the handle refers to must not yet have been deallocated. #[inline] pub unsafe fn drop_key_val(mut self) { + // Run the destructor of the value even if the destructor of the key panics. + struct Dropper<'a, T>(&'a mut MaybeUninit); + impl Drop for Dropper<'_, T> { + #[inline] + fn drop(&mut self) { + unsafe { + self.0.assume_init_drop(); + } + } + } + debug_assert!(self.idx < self.node.len()); let leaf = self.node.as_leaf_dying(); unsafe { - leaf.keys.get_unchecked_mut(self.idx).assume_init_drop(); - leaf.vals.get_unchecked_mut(self.idx).assume_init_drop(); + let key = leaf.keys.get_unchecked_mut(self.idx); + let val = leaf.vals.get_unchecked_mut(self.idx); + let _guard = Dropper(val); + key.assume_init_drop(); + // dropping the guard will drop the value } } } diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index a40209fa2e397..8daee6030c270 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -7,7 +7,6 @@ use core::iter::{FusedIterator, Peekable}; use core::mem::ManuallyDrop; use core::ops::{BitAnd, BitOr, BitXor, Bound, RangeBounds, Sub}; -use super::Recover; use super::map::{BTreeMap, Keys}; use super::merge_iter::MergeIterInner; use super::set_val::SetValZST; @@ -635,7 +634,7 @@ impl BTreeSet { T: Borrow + Ord, Q: Ord, { - Recover::get(&self.map, value) + self.map.get_key_value(value).map(|(k, _)| k) } /// Returns `true` if `self` has no elements in common with `other`. @@ -926,7 +925,7 @@ impl BTreeSet { where T: Ord, { - Recover::replace(&mut self.map, value) + self.map.replace(value) } /// If the set contains an element equal to the value, removes it from the @@ -978,7 +977,7 @@ impl BTreeSet { T: Borrow + Ord, Q: Ord, { - Recover::take(&mut self.map, value) + self.map.remove_entry(value).map(|(k, _)| k) } /// Retains only the elements specified by the predicate. diff --git a/alloc/src/collections/btree/set_val.rs b/alloc/src/collections/btree/set_val.rs index 80c459bcf81db..cf30160bfbbc2 100644 --- a/alloc/src/collections/btree/set_val.rs +++ b/alloc/src/collections/btree/set_val.rs @@ -3,14 +3,14 @@ /// * `BTreeMap` (possible user-defined map) /// * `BTreeMap` (internal set representation) #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Default)] -pub struct SetValZST; +pub(super) struct SetValZST; /// A trait to differentiate between `BTreeMap` and `BTreeSet` values. /// Returns `true` only for type `SetValZST`, `false` for all other types (blanket implementation). /// `TypeId` requires a `'static` lifetime, use of this trait avoids that restriction. /// /// [`TypeId`]: std::any::TypeId -pub trait IsSetVal { +pub(super) trait IsSetVal { fn is_set_val() -> bool; } diff --git a/alloc/src/collections/vec_deque/iter.rs b/alloc/src/collections/vec_deque/iter.rs index 6922ea9b79bfd..d3dbd10c863fb 100644 --- a/alloc/src/collections/vec_deque/iter.rs +++ b/alloc/src/collections/vec_deque/iter.rs @@ -19,6 +19,40 @@ impl<'a, T> Iter<'a, T> { pub(super) fn new(i1: slice::Iter<'a, T>, i2: slice::Iter<'a, T>) -> Self { Self { i1, i2 } } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// This has the same lifetime as the original `VecDeque`, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter(); + /// iter.next(); + /// iter.next_back(); + /// + /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_slices(&self) -> (&'a [T], &'a [T]) { + (self.i1.as_slice(), self.i2.as_slice()) + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/alloc/src/collections/vec_deque/iter_mut.rs b/alloc/src/collections/vec_deque/iter_mut.rs index 84b7410958013..0c5f06e752b7b 100644 --- a/alloc/src/collections/vec_deque/iter_mut.rs +++ b/alloc/src/collections/vec_deque/iter_mut.rs @@ -19,6 +19,113 @@ impl<'a, T> IterMut<'a, T> { pub(super) fn new(i1: slice::IterMut<'a, T>, i2: slice::IterMut<'a, T>) -> Self { Self { i1, i2 } } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut` references that alias, this is forced to + /// consume the iterator. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// let slices = iter.into_slices(); + /// slices.0[0] = 42; + /// slices.1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn into_slices(self) -> (&'a mut [T], &'a mut [T]) { + (self.i1.into_slice(), self.i2.into_slice()) + } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slices + /// borrow their lifetimes from the iterator the method is applied on. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_slices(&self) -> (&[T], &[T]) { + (self.i1.as_slice(), self.i2.as_slice()) + } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slices + /// borrow their lifetimes from the iterator the method is applied on. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// iter.as_mut_slices().0[0] = 42; + /// iter.as_mut_slices().1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { + (self.i1.as_mut_slice(), self.i2.as_mut_slice()) + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/alloc/src/ffi/c_str.rs b/alloc/src/ffi/c_str.rs index d7e99f4a1a638..d91682b796e4f 100644 --- a/alloc/src/ffi/c_str.rs +++ b/alloc/src/ffi/c_str.rs @@ -772,6 +772,16 @@ impl From<&CStr> for Box { } } +#[cfg(not(test))] +#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut CStr> for Box { + /// Converts a `&mut CStr` into a `Box`, + /// by copying the contents into a newly allocated [`Box`]. + fn from(s: &mut CStr) -> Box { + Self::from(&*s) + } +} + #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { /// Converts a `Cow<'a, CStr>` into a `Box`, @@ -910,6 +920,17 @@ impl From<&CStr> for Arc { } } +#[cfg(target_has_atomic = "ptr")] +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut CStr> for Arc { + /// Converts a `&mut CStr` into a `Arc`, + /// by copying the contents into a newly allocated [`Arc`]. + #[inline] + fn from(s: &mut CStr) -> Arc { + Arc::from(&*s) + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { /// Converts a [`CString`] into an [Rc]<[CStr]> by moving the [`CString`] @@ -932,6 +953,16 @@ impl From<&CStr> for Rc { } } +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut CStr> for Rc { + /// Converts a `&mut CStr` into a `Rc`, + /// by copying the contents into a newly allocated [`Rc`]. + #[inline] + fn from(s: &mut CStr) -> Rc { + Rc::from(&*s) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "more_rc_default_impls", since = "1.80.0")] impl Default for Rc { diff --git a/alloc/src/fmt.rs b/alloc/src/fmt.rs index 3da71038a5e76..695dddb25eeb4 100644 --- a/alloc/src/fmt.rs +++ b/alloc/src/fmt.rs @@ -109,6 +109,16 @@ //! parameters (corresponding to `format_spec` in [the syntax](#syntax)). These //! parameters affect the string representation of what's being formatted. //! +//! The colon `:` in format syntax divides indentifier of the input data and +//! the formatting options, the colon itself does not change anything, only +//! introduces the options. +//! +//! ``` +//! let a = 5; +//! let b = &a; +//! println!("{a:e} {b:p}"); // => 5e0 0x7ffe37b7273c +//! ``` +//! //! ## Width //! //! ``` diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index dd9dfa3f5e26d..041ff37897f05 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -136,6 +136,7 @@ #![feature(panic_internals)] #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] +#![feature(pointer_like_trait)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] @@ -143,6 +144,7 @@ #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] #![feature(slice_index_methods)] +#![feature(slice_iter_mut_as_mut_slice)] #![feature(slice_ptr_get)] #![feature(slice_range)] #![feature(std_internals)] diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index fc8646e96d948..3a9bd1b5bf119 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -307,6 +307,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { /// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`. /// /// [get_mut]: Rc::get_mut +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] @@ -1875,7 +1876,7 @@ impl Rc { // Initialize with clone of this. let initialized_clone = unsafe { // Clone. If the clone panics, `in_progress` will be dropped and clean up. - this_data_ref.clone_to_uninit(in_progress.data_ptr()); + this_data_ref.clone_to_uninit(in_progress.data_ptr().cast()); // Cast type of pointer, now that it is initialized. in_progress.into_rc() }; @@ -2657,6 +2658,26 @@ impl From<&[T]> for Rc<[T]> { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut [T]> for Rc<[T]> { + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let mut original = [1, 2, 3]; + /// let original: &mut [i32] = &mut original; + /// let shared: Rc<[i32]> = Rc::from(original); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: &mut [T]) -> Rc<[T]> { + Rc::from(&*v) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From<&str> for Rc { @@ -2676,6 +2697,26 @@ impl From<&str> for Rc { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut str> for Rc { + /// Allocates a reference-counted string slice and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let mut original = String::from("statue"); + /// let original: &mut str = &mut original; + /// let shared: Rc = Rc::from(original); + /// assert_eq!("statue", &shared[..]); + /// ``` + #[inline] + fn from(v: &mut str) -> Rc { + Rc::from(&*v) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From for Rc { @@ -2891,7 +2932,9 @@ impl> ToRcSlice for I { } /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the -/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` +/// managed allocation. +/// +/// The allocation is accessed by calling [`upgrade`] on the `Weak` /// pointer, which returns an [Option]<[Rc]\>. /// /// Since a `Weak` reference does not count towards ownership, it will not diff --git a/alloc/src/str.rs b/alloc/src/str.rs index 26c1ba2a5c485..6fee8d3fe3346 100644 --- a/alloc/src/str.rs +++ b/alloc/src/str.rs @@ -531,6 +531,7 @@ impl str { #[rustc_allow_incoherent_impl] #[must_use] #[stable(feature = "repeat_str", since = "1.16.0")] + #[inline] pub fn repeat(&self, n: usize) -> String { unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) } } diff --git a/alloc/src/string.rs b/alloc/src/string.rs index b042720933b6d..e0576c2551545 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -116,7 +116,7 @@ use crate::vec::Vec; /// `String`s are always valid UTF-8. If you need a non-UTF-8 string, consider /// [`OsString`]. It is similar, but without the UTF-8 constraint. Because UTF-8 /// is a variable width encoding, `String`s are typically smaller than an array of -/// the same `chars`: +/// the same `char`s: /// /// ``` /// use std::mem; diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 98a2fe242570f..da2d6bb3bce24 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -235,6 +235,7 @@ macro_rules! acquire { /// counting in general. /// /// [rc_examples]: crate::rc#examples +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] @@ -290,7 +291,9 @@ impl Arc { } /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the -/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` +/// managed allocation. +/// +/// The allocation is accessed by calling [`upgrade`] on the `Weak` /// pointer, which returns an [Option]<[Arc]\>. /// /// Since a `Weak` reference does not count towards ownership, it will not @@ -2269,7 +2272,7 @@ impl Arc { let initialized_clone = unsafe { // Clone. If the clone panics, `in_progress` will be dropped and clean up. - this_data_ref.clone_to_uninit(in_progress.data_ptr()); + this_data_ref.clone_to_uninit(in_progress.data_ptr().cast()); // Cast type of pointer, now that it is initialized. in_progress.into_arc() }; @@ -3614,6 +3617,26 @@ impl From<&[T]> for Arc<[T]> { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut [T]> for Arc<[T]> { + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. + /// + /// # Example + /// + /// ``` + /// # use std::sync::Arc; + /// let mut original = [1, 2, 3]; + /// let original: &mut [i32] = &mut original; + /// let shared: Arc<[i32]> = Arc::from(original); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: &mut [T]) -> Arc<[T]> { + Arc::from(&*v) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From<&str> for Arc { @@ -3633,6 +3656,26 @@ impl From<&str> for Arc { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut str> for Arc { + /// Allocates a reference-counted `str` and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// # use std::sync::Arc; + /// let mut original = String::from("eggplant"); + /// let original: &mut str = &mut original; + /// let shared: Arc = Arc::from(original); + /// assert_eq!("eggplant", &shared[..]); + /// ``` + #[inline] + fn from(v: &mut str) -> Arc { + Arc::from(&*v) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From for Arc { diff --git a/alloc/src/task.rs b/alloc/src/task.rs index 27589aed2f97c..0f8e74300a491 100644 --- a/alloc/src/task.rs +++ b/alloc/src/task.rs @@ -176,9 +176,11 @@ fn raw_waker(waker: Arc) -> RawWaker { ) } -/// An analogous trait to `Wake` but used to construct a `LocalWaker`. This API -/// works in exactly the same way as `Wake`, except that it uses an `Rc` instead -/// of an `Arc`, and the result is a `LocalWaker` instead of a `Waker`. +/// An analogous trait to `Wake` but used to construct a `LocalWaker`. +/// +/// This API works in exactly the same way as `Wake`, +/// except that it uses an `Rc` instead of an `Arc`, +/// and the result is a `LocalWaker` instead of a `Waker`. /// /// The benefits of using `LocalWaker` over `Waker` are that it allows the local waker /// to hold data that does not implement `Send` and `Sync`. Additionally, it saves calls diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 07a1bd4932138..990b7e8f76127 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -1662,6 +1662,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through @@ -1724,6 +1725,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through diff --git a/core/benches/fmt.rs b/core/benches/fmt.rs index 4baefd5578808..ed478b0f1e055 100644 --- a/core/benches/fmt.rs +++ b/core/benches/fmt.rs @@ -149,3 +149,17 @@ fn write_u64_min(bh: &mut Bencher) { test::black_box(format!("{}", 0u64)); }); } + +#[bench] +fn write_u8_max(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", u8::MAX)); + }); +} + +#[bench] +fn write_u8_min(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", 0u8)); + }); +} diff --git a/core/src/array/iter.rs b/core/src/array/iter.rs index 2d19e4876f680..9ce0eb61e0814 100644 --- a/core/src/array/iter.rs +++ b/core/src/array/iter.rs @@ -136,7 +136,6 @@ impl IntoIter { /// assert_eq!(r.collect::>(), vec![10, 11, 12, 13, 14, 15]); /// ``` #[unstable(feature = "array_into_iter_constructors", issue = "91583")] - #[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")] pub const unsafe fn new_unchecked( buffer: [MaybeUninit; N], initialized: Range, @@ -199,7 +198,6 @@ impl IntoIter { /// assert_eq!(get_bytes(false).collect::>(), vec![]); /// ``` #[unstable(feature = "array_into_iter_constructors", issue = "91583")] - #[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")] pub const fn empty() -> Self { let buffer = [const { MaybeUninit::uninit() }; N]; let initialized = 0..0; diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index 4764d7f0b0fe0..67fbda34bb935 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -10,11 +10,13 @@ use crate::convert::Infallible; use crate::error::Error; use crate::fmt; use crate::hash::{self, Hash}; +use crate::intrinsics::transmute_unchecked; use crate::iter::{UncheckedIterator, repeat_n}; use crate::mem::{self, MaybeUninit}; use crate::ops::{ ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try, }; +use crate::ptr::{null, null_mut}; use crate::slice::{Iter, IterMut}; mod ascii; @@ -577,7 +579,8 @@ impl [T; N] { /// Returns a mutable slice containing the entire array. Equivalent to /// `&mut s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] - pub fn as_mut_slice(&mut self) -> &mut [T] { + #[rustc_const_unstable(feature = "const_array_as_mut_slice", issue = "133333")] + pub const fn as_mut_slice(&mut self) -> &mut [T] { self } @@ -606,8 +609,20 @@ impl [T; N] { /// assert_eq!(strings.len(), 3); /// ``` #[stable(feature = "array_methods", since = "1.77.0")] - pub fn each_ref(&self) -> [&T; N] { - from_trusted_iterator(self.iter()) + #[rustc_const_unstable(feature = "const_array_each_ref", issue = "133289")] + pub const fn each_ref(&self) -> [&T; N] { + let mut buf = [null::(); N]; + + // FIXME(const-hack): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions. + let mut i = 0; + while i < N { + buf[i] = &raw const self[i]; + + i += 1; + } + + // SAFETY: `*const T` has the same layout as `&T`, and we've also initialised each pointer as a valid reference. + unsafe { transmute_unchecked(buf) } } /// Borrows each element mutably and returns an array of mutable references @@ -625,8 +640,20 @@ impl [T; N] { /// assert_eq!(floats, [0.0, 2.7, -1.0]); /// ``` #[stable(feature = "array_methods", since = "1.77.0")] - pub fn each_mut(&mut self) -> [&mut T; N] { - from_trusted_iterator(self.iter_mut()) + #[rustc_const_unstable(feature = "const_array_each_ref", issue = "133289")] + pub const fn each_mut(&mut self) -> [&mut T; N] { + let mut buf = [null_mut::(); N]; + + // FIXME(const-hack): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions. + let mut i = 0; + while i < N { + buf[i] = &raw mut self[i]; + + i += 1; + } + + // SAFETY: `*mut T` has the same layout as `&mut T`, and we've also initialised each pointer as a valid reference. + unsafe { transmute_unchecked(buf) } } /// Divides one array reference into two at an index. diff --git a/core/src/cell.rs b/core/src/cell.rs index 7e6c042274df6..bfd2a71f97b2c 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -3,8 +3,8 @@ //! Rust memory safety is based on this rule: Given an object `T`, it is only possible to //! have one of the following: //! -//! - Having several immutable references (`&T`) to the object (also known as **aliasing**). -//! - Having one mutable reference (`&mut T`) to the object (also known as **mutability**). +//! - Several immutable references (`&T`) to the object (also known as **aliasing**). +//! - One mutable reference (`&mut T`) to the object (also known as **mutability**). //! //! This is enforced by the Rust compiler. However, there are situations where this rule is not //! flexible enough. Sometimes it is required to have multiple references to an object and yet @@ -587,6 +587,7 @@ impl Cell { #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() @@ -1149,6 +1150,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub fn as_ptr(&self) -> *mut T { self.value.get() @@ -2122,7 +2124,6 @@ impl UnsafeCell { /// # Examples /// /// ``` - /// # #![feature(unsafe_cell_from_mut)] /// use std::cell::UnsafeCell; /// /// let mut val = 42; @@ -2132,7 +2133,9 @@ impl UnsafeCell { /// assert_eq!(*uc.get_mut(), 41); /// ``` #[inline(always)] - #[unstable(feature = "unsafe_cell_from_mut", issue = "111645")] + #[stable(feature = "unsafe_cell_from_mut", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unsafe_cell_from_mut", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn from_mut(value: &mut T) -> &mut UnsafeCell { // SAFETY: `UnsafeCell` has the same memory layout as `T` due to #[repr(transparent)]. unsafe { &mut *(value as *mut T as *mut UnsafeCell) } @@ -2157,6 +2160,7 @@ impl UnsafeCell { #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of @@ -2270,6 +2274,7 @@ impl, U> DispatchFromDyn> for UnsafeCell /// See [`UnsafeCell`] for details. #[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[repr(transparent)] +#[rustc_diagnostic_item = "SyncUnsafeCell"] #[rustc_pub_transparent] pub struct SyncUnsafeCell { value: UnsafeCell, @@ -2303,6 +2308,7 @@ impl SyncUnsafeCell { /// when casting to `&mut T`, and ensure that there are no mutations /// or mutable aliases going on when casting to `&T` #[inline] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { self.value.get() diff --git a/core/src/char/methods.rs b/core/src/char/methods.rs index 206bbf5690ef1..974e7baccf7bc 100644 --- a/core/src/char/methods.rs +++ b/core/src/char/methods.rs @@ -1,7 +1,7 @@ //! impl char {} use super::*; -use crate::intrinsics::const_eval_select; +use crate::panic::const_panic; use crate::slice; use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; @@ -301,7 +301,7 @@ impl char { /// /// # Panics /// - /// Panics if given a radix larger than 36. + /// Panics if given a radix smaller than 2 or larger than 36. /// /// # Examples /// @@ -319,8 +319,15 @@ impl char { /// // this panics /// '1'.is_digit(37); /// ``` + /// + /// Passing a small radix, causing a panic: + /// + /// ```should_panic + /// // this panics + /// '1'.is_digit(1); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_char_is_digit", issue = "132241")] + #[rustc_const_unstable(feature = "const_char_classify", issue = "132241")] #[inline] pub const fn is_digit(self, radix: u32) -> bool { self.to_digit(radix).is_some() @@ -345,7 +352,7 @@ impl char { /// /// # Panics /// - /// Panics if given a radix larger than 36. + /// Panics if given a radix smaller than 2 or larger than 36. /// /// # Examples /// @@ -369,24 +376,35 @@ impl char { /// // this panics /// let _ = '1'.to_digit(37); /// ``` + /// Passing a small radix, causing a panic: + /// + /// ```should_panic + /// // this panics + /// let _ = '1'.to_digit(1); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn to_digit(self, radix: u32) -> Option { - // If not a digit, a number greater than radix will be created. - let mut digit = (self as u32).wrapping_sub('0' as u32); - if radix > 10 { - assert!(radix <= 36, "to_digit: radix is too high (maximum 36)"); - if digit < 10 { - return Some(digit); - } - // Force the 6th bit to be set to ensure ascii is lower case. - digit = (self as u32 | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10); - } + assert!( + radix >= 2 && radix <= 36, + "to_digit: invalid radix -- radix must be in the range 2 to 36 inclusive" + ); + // check radix to remove letter handling code when radix is a known constant + let value = if self > '9' && radix > 10 { + // convert ASCII letters to lowercase + let lower = self as u32 | 0x20; + // convert an ASCII letter to the corresponding value, + // non-letters convert to values > 36 + lower.wrapping_sub('a' as u32) as u64 + 10 + } else { + // convert digit to value, non-digits wrap to values > 36 + (self as u32).wrapping_sub('0' as u32) as u64 + }; // FIXME(const-hack): once then_some is const fn, use it here - if digit < radix { Some(digit) } else { None } + if value < radix as u64 { Some(value as u32) } else { None } } /// Returns an iterator that yields the hexadecimal Unicode escape of a @@ -711,7 +729,7 @@ impl char { /// '𝕊'.encode_utf16(&mut b); /// ``` #[stable(feature = "unicode_encode_char", since = "1.15.0")] - #[rustc_const_unstable(feature = "const_char_encode_utf16", issue = "130660")] + #[rustc_const_stable(feature = "const_char_encode_utf16", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { encode_utf16_raw(self as u32, dst) @@ -775,13 +793,12 @@ impl char { /// In a const context: /// /// ``` - /// #![feature(const_unicode_case_lookup)] /// const CAPITAL_DELTA_IS_LOWERCASE: bool = 'Δ'.is_lowercase(); /// assert!(!CAPITAL_DELTA_IS_LOWERCASE); /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + #[rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0")] #[inline] pub const fn is_lowercase(self) -> bool { match self { @@ -817,13 +834,12 @@ impl char { /// In a const context: /// /// ``` - /// #![feature(const_unicode_case_lookup)] /// const CAPITAL_DELTA_IS_UPPERCASE: bool = 'Δ'.is_uppercase(); /// assert!(CAPITAL_DELTA_IS_UPPERCASE); /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + #[rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0")] #[inline] pub const fn is_uppercase(self) -> bool { match self { @@ -856,8 +872,9 @@ impl char { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_char_classify", issue = "132241")] #[inline] - pub fn is_whitespace(self) -> bool { + pub const fn is_whitespace(self) -> bool { match self { ' ' | '\x09'..='\x0d' => true, c => c > '\x7f' && unicode::White_Space(c), @@ -1515,7 +1532,6 @@ impl char { /// ``` #[must_use] #[unstable(feature = "is_ascii_octdigit", issue = "101288")] - #[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")] #[inline] pub const fn is_ascii_octdigit(&self) -> bool { matches!(*self, '0'..='7') @@ -1774,17 +1790,7 @@ const fn len_utf16(code: u32) -> usize { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0"))] #[doc(hidden)] #[inline] -#[rustc_allow_const_fn_unstable(const_eval_select)] pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { - const fn panic_at_const(_code: u32, _len: usize, _dst_len: usize) { - // Note that we cannot format in constant expressions. - panic!("encode_utf8: buffer does not have enough bytes to encode code point"); - } - fn panic_at_rt(code: u32, len: usize, dst_len: usize) { - panic!( - "encode_utf8: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}", - ); - } let len = len_utf8(code); match (len, &mut *dst) { (1, [a, ..]) => { @@ -1805,8 +1811,15 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { *c = (code >> 6 & 0x3F) as u8 | TAG_CONT; *d = (code & 0x3F) as u8 | TAG_CONT; } - // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. - _ => const_eval_select((code, len, dst.len()), panic_at_const, panic_at_rt), + _ => { + const_panic!( + "encode_utf8: buffer does not have enough bytes to encode code point", + "encode_utf8: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}", + code: u32 = code, + len: usize = len, + dst_len: usize = dst.len(), + ) + } }; // SAFETY: `<&mut [u8]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds. unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) } @@ -1823,19 +1836,13 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { /// Panics if the buffer is not large enough. /// A buffer of length 2 is large enough to encode any `char`. #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -#[rustc_const_unstable(feature = "const_char_encode_utf16", issue = "130660")] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_char_encode_utf16", since = "CURRENT_RUSTC_VERSION") +)] #[doc(hidden)] #[inline] pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] { - const fn panic_at_const(_code: u32, _len: usize, _dst_len: usize) { - // Note that we cannot format in constant expressions. - panic!("encode_utf16: buffer does not have enough bytes to encode code point"); - } - fn panic_at_rt(code: u32, len: usize, dst_len: usize) { - panic!( - "encode_utf16: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}", - ); - } let len = len_utf16(code); match (len, &mut *dst) { (1, [a, ..]) => { @@ -1846,8 +1853,15 @@ pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] { *a = (code >> 10) as u16 | 0xD800; *b = (code & 0x3FF) as u16 | 0xDC00; } - // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. - _ => const_eval_select((code, len, dst.len()), panic_at_const, panic_at_rt), + _ => { + const_panic!( + "encode_utf16: buffer does not have enough bytes to encode code point", + "encode_utf16: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}", + code: u32 = code, + len: usize = len, + dst_len: usize = dst.len(), + ) + } }; // SAFETY: `<&mut [u16]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds. unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) } diff --git a/core/src/clone.rs b/core/src/clone.rs index c5f8bd7401e5e..ec1aed53eaf72 100644 --- a/core/src/clone.rs +++ b/core/src/clone.rs @@ -232,20 +232,20 @@ pub struct AssertParamIsCopy { pub unsafe trait CloneToUninit { /// Performs copy-assignment from `self` to `dst`. /// - /// This is analogous to `std::ptr::write(dst, self.clone())`, + /// This is analogous to `std::ptr::write(dst.cast(), self.clone())`, /// except that `self` may be a dynamically-sized type ([`!Sized`](Sized)). /// /// Before this function is called, `dst` may point to uninitialized memory. /// After this function is called, `dst` will point to initialized memory; it will be - /// sound to create a `&Self` reference from the pointer. + /// sound to create a `&Self` reference from the pointer with the [pointer metadata] + /// from `self`. /// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// - /// * `dst` must be [valid] for writes. - /// * `dst` must be properly aligned. - /// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`. + /// * `dst` must be [valid] for writes for `std::mem::size_of_val(self)` bytes. + /// * `dst` must be properly aligned to `std::mem::align_of_val(self)`. /// /// [valid]: crate::ptr#safety /// [pointer metadata]: crate::ptr::metadata() @@ -266,15 +266,15 @@ pub unsafe trait CloneToUninit { /// that might have already been created. (For example, if a `[Foo]` of length 3 is being /// cloned, and the second of the three calls to `Foo::clone()` unwinds, then the first `Foo` /// cloned should be dropped.) - unsafe fn clone_to_uninit(&self, dst: *mut Self); + unsafe fn clone_to_uninit(&self, dst: *mut u8); } #[unstable(feature = "clone_to_uninit", issue = "126799")] unsafe impl CloneToUninit for T { #[inline] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { + unsafe fn clone_to_uninit(&self, dst: *mut u8) { // SAFETY: we're calling a specialization with the same contract - unsafe { ::clone_one(self, dst) } + unsafe { ::clone_one(self, dst.cast::()) } } } @@ -282,7 +282,8 @@ unsafe impl CloneToUninit for T { unsafe impl CloneToUninit for [T] { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + let dst: *mut [T] = dst.with_metadata_of(self); // SAFETY: we're calling a specialization with the same contract unsafe { ::clone_slice(self, dst) } } @@ -292,21 +293,21 @@ unsafe impl CloneToUninit for [T] { unsafe impl CloneToUninit for str { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { + unsafe fn clone_to_uninit(&self, dst: *mut u8) { // SAFETY: str is just a [u8] with UTF-8 invariant - unsafe { self.as_bytes().clone_to_uninit(dst as *mut [u8]) } + unsafe { self.as_bytes().clone_to_uninit(dst) } } } #[unstable(feature = "clone_to_uninit", issue = "126799")] unsafe impl CloneToUninit for crate::ffi::CStr { #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { + unsafe fn clone_to_uninit(&self, dst: *mut u8) { // SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants. // And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul). - // The pointer metadata properly preserves the length (NUL included). + // The pointer metadata properly preserves the length (so NUL is also copied). // See: `cstr_metadata_is_length_with_nul` in tests. - unsafe { self.to_bytes_with_nul().clone_to_uninit(dst as *mut [u8]) } + unsafe { self.to_bytes_with_nul().clone_to_uninit(dst) } } } diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index 93dd351b02958..9e32f74227cf9 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -3,11 +3,12 @@ use crate::cmp::Ordering; use crate::error::Error; use crate::ffi::c_char; +use crate::intrinsics::const_eval_select; use crate::iter::FusedIterator; use crate::marker::PhantomData; use crate::ptr::NonNull; use crate::slice::memchr; -use crate::{fmt, intrinsics, ops, slice, str}; +use crate::{fmt, ops, slice, str}; // FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link // depends on where the item is being documented. however, since this is libcore, we can't @@ -411,37 +412,35 @@ impl CStr { #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")] #[rustc_allow_const_fn_unstable(const_eval_select)] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { - #[inline] - fn rt_impl(bytes: &[u8]) -> &CStr { - // Chance at catching some UB at runtime with debug builds. - debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); - - // SAFETY: Casting to CStr is safe because its internal representation - // is a [u8] too (safe only inside std). - // Dereferencing the obtained pointer is safe because it comes from a - // reference. Making a reference is then safe because its lifetime - // is bound by the lifetime of the given `bytes`. - unsafe { &*(bytes as *const [u8] as *const CStr) } - } - - const fn const_impl(bytes: &[u8]) -> &CStr { - // Saturating so that an empty slice panics in the assert with a good - // message, not here due to underflow. - let mut i = bytes.len().saturating_sub(1); - assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated"); - - // Ending nul byte exists, skip to the rest. - while i != 0 { - i -= 1; - let byte = bytes[i]; - assert!(byte != 0, "input contained interior nul"); + const_eval_select!( + @capture { bytes: &[u8] } -> &CStr: + if const { + // Saturating so that an empty slice panics in the assert with a good + // message, not here due to underflow. + let mut i = bytes.len().saturating_sub(1); + assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated"); + + // Ending nul byte exists, skip to the rest. + while i != 0 { + i -= 1; + let byte = bytes[i]; + assert!(byte != 0, "input contained interior nul"); + } + + // SAFETY: See runtime cast comment below. + unsafe { &*(bytes as *const [u8] as *const CStr) } + } else { + // Chance at catching some UB at runtime with debug builds. + debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); + + // SAFETY: Casting to CStr is safe because its internal representation + // is a [u8] too (safe only inside std). + // Dereferencing the obtained pointer is safe because it comes from a + // reference. Making a reference is then safe because its lifetime + // is bound by the lifetime of the given `bytes`. + unsafe { &*(bytes as *const [u8] as *const CStr) } } - - // SAFETY: See `rt_impl` cast. - unsafe { &*(bytes as *const [u8] as *const CStr) } - } - - intrinsics::const_eval_select((bytes,), const_impl, rt_impl) + ) } /// Returns the inner pointer to this C string. @@ -501,6 +500,7 @@ impl CStr { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() @@ -510,7 +510,7 @@ impl CStr { #[inline] #[must_use] const fn as_non_null_ptr(&self) -> NonNull { - // FIXME(effects) replace with `NonNull::from` + // FIXME(const_trait_impl) replace with `NonNull::from` // SAFETY: a reference is never null unsafe { NonNull::new_unchecked(&self.inner as *const [c_char] as *mut [c_char]) } .as_non_null_ptr() @@ -735,29 +735,27 @@ impl AsRef for CStr { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))] #[rustc_allow_const_fn_unstable(const_eval_select)] const unsafe fn strlen(ptr: *const c_char) -> usize { - const fn strlen_ct(s: *const c_char) -> usize { - let mut len = 0; - - // SAFETY: Outer caller has provided a pointer to a valid C string. - while unsafe { *s.add(len) } != 0 { - len += 1; - } + const_eval_select!( + @capture { s: *const c_char = ptr } -> usize: + if const { + let mut len = 0; + + // SAFETY: Outer caller has provided a pointer to a valid C string. + while unsafe { *s.add(len) } != 0 { + len += 1; + } - len - } + len + } else { + extern "C" { + /// Provided by libc or compiler_builtins. + fn strlen(s: *const c_char) -> usize; + } - #[inline] - fn strlen_rt(s: *const c_char) -> usize { - extern "C" { - /// Provided by libc or compiler_builtins. - fn strlen(s: *const c_char) -> usize; + // SAFETY: Outer caller has provided a pointer to a valid C string. + unsafe { strlen(s) } } - - // SAFETY: Outer caller has provided a pointer to a valid C string. - unsafe { strlen(s) } - } - - intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) + ) } /// An iterator over the bytes of a [`CStr`], without the nul terminator. diff --git a/core/src/fmt/float.rs b/core/src/fmt/float.rs index c70dbf54304de..04230b1610aae 100644 --- a/core/src/fmt/float.rs +++ b/core/src/fmt/float.rs @@ -13,7 +13,7 @@ macro_rules! impl_general_format { ($($t:ident)*) => { $(impl GeneralFormat for $t { fn already_rounded_value_should_use_exponential(&self) -> bool { - let abs = $t::abs_private(*self); + let abs = $t::abs(*self); (abs != 0.0 && abs < 1e-4) || abs >= 1e+16 } })* diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index f3b54230bc1a5..2b1692a195e50 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -438,10 +438,9 @@ impl<'a> Arguments<'a> { /// assert_eq!(format_args!("{:?}", std::env::current_dir()).as_str(), None); /// ``` #[stable(feature = "fmt_as_str", since = "1.52.0")] - #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] + #[rustc_const_stable(feature = "const_arguments_as_str", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { ([], []) => Some(""), diff --git a/core/src/fmt/num.rs b/core/src/fmt/num.rs index f1540803f978d..683e45b35f70a 100644 --- a/core/src/fmt/num.rs +++ b/core/src/fmt/num.rs @@ -65,11 +65,11 @@ unsafe trait GenericRadix: Sized { if is_nonnegative { // Accumulate each digit of the number from the least significant // to the most significant figure. - for byte in buf.iter_mut().rev() { + loop { let n = x % base; // Get the current place value. x = x / base; // Deaccumulate the number. - byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; + buf[curr].write(Self::digit(n.to_u8())); // Store the digit in the buffer. if x == zero { // No more digits left to accumulate. break; @@ -77,18 +77,21 @@ unsafe trait GenericRadix: Sized { } } else { // Do the same as above, but accounting for two's complement. - for byte in buf.iter_mut().rev() { + loop { let n = zero - (x % base); // Get the current place value. x = x / base; // Deaccumulate the number. - byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; + buf[curr].write(Self::digit(n.to_u8())); // Store the digit in the buffer. if x == zero { // No more digits left to accumulate. break; }; } } - let buf = &buf[curr..]; + // SAFETY: `curr` is initialized to `buf.len()` and is only decremented, so it can't overflow. It is + // decremented exactly once for each digit. Since u128 is the widest fixed width integer format supported, + // the maximum number of digits (bits) is 128 for base-2, so `curr` won't underflow as well. + let buf = unsafe { buf.get_unchecked(curr..) }; // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be // valid UTF-8 let buf = unsafe { @@ -196,32 +199,12 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ 8081828384858687888990919293949596979899"; macro_rules! impl_Display { - ($($t:ident $(as $positive:ident)? named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { + ($($signed:ident, $unsigned:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { $( #[stable(feature = "rust1", since = "1.0.0")] - impl fmt::Display for $t { + impl fmt::Display for $unsigned { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // If it's a signed integer. - $( - let is_nonnegative = *self >= 0; - - #[cfg(not(feature = "optimize_for_size"))] - { - if !is_nonnegative { - // convert the negative num to positive by summing 1 to its 2s complement - return (!self as $positive).wrapping_add(1)._fmt(false, f); - } - } - #[cfg(feature = "optimize_for_size")] - { - if !is_nonnegative { - // convert the negative num to positive by summing 1 to its 2s complement - return $gen_name((!self.$conv_fn()).wrapping_add(1), false, f); - } - } - )? - // If it's a positive integer. #[cfg(not(feature = "optimize_for_size"))] { self._fmt(true, f) @@ -233,10 +216,24 @@ macro_rules! impl_Display { } } + #[stable(feature = "rust1", since = "1.0.0")] + impl fmt::Display for $signed { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + #[cfg(not(feature = "optimize_for_size"))] + { + return self.unsigned_abs()._fmt(*self >= 0, f); + } + #[cfg(feature = "optimize_for_size")] + { + return $gen_name(self.unsigned_abs().$conv_fn(), *self >= 0, f); + } + } + } + #[cfg(not(feature = "optimize_for_size"))] - impl $t { - fn _fmt(mut self: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const SIZE: usize = $t::MAX.ilog(10) as usize + 1; + impl $unsigned { + fn _fmt(mut self, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1; let mut buf = [MaybeUninit::::uninit(); SIZE]; let mut curr = SIZE; let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); @@ -255,7 +252,7 @@ macro_rules! impl_Display { #[allow(unused_comparisons)] // This block will be removed for smaller types at compile time and in the worst // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`. - if core::mem::size_of::<$t>() >= 2 { + if core::mem::size_of::<$unsigned>() >= 2 { // eagerly decode 4 characters at a time while self >= 10000 { let rem = (self % 10000) as usize; @@ -309,8 +306,8 @@ macro_rules! impl_Display { #[cfg(feature = "optimize_for_size")] fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // 2^128 is about 3*10^38, so 39 gives an extra byte of space - let mut buf = [MaybeUninit::::uninit(); 39]; + const SIZE: usize = $u::MAX.ilog(10) as usize + 1; + let mut buf = [MaybeUninit::::uninit(); SIZE]; let mut curr = buf.len(); let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); @@ -520,16 +517,11 @@ impl_Debug! { mod imp { use super::*; impl_Display!( - i8 as u8 named fmt_i8, - u8 named fmt_u8, - i16 as u16 named fmt_i16, - u16 named fmt_u16, - i32 as u32 named fmt_i32, - u32 named fmt_u32, - i64 as u64 named fmt_i64, - u64 named fmt_u64, - isize as usize named fmt_isize, - usize named fmt_usize, + i8, u8, + i16, u16, + i32, u32, + i64, u64, + isize, usize, ; as u64 via to_u64 named fmt_u64 ); impl_Exp!( @@ -542,18 +534,13 @@ mod imp { mod imp { use super::*; impl_Display!( - i8 as u8 named fmt_i8, - u8 named fmt_u8, - i16 as u16 named fmt_i16, - u16 named fmt_u16, - i32 as u32 named fmt_i32, - u32 named fmt_u32, - isize as usize named fmt_isize, - usize named fmt_usize, + i8, u8, + i16, u16, + i32, u32, + isize, usize, ; as u32 via to_u32 named fmt_u32); impl_Display!( - i64 as u64 named fmt_i64, - u64 named fmt_u64, + i64, u64, ; as u64 via to_u64 named fmt_u64); impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32); diff --git a/core/src/future/future.rs b/core/src/future/future.rs index ca1c2d1ca1f2e..234914c20fc31 100644 --- a/core/src/future/future.rs +++ b/core/src/future/future.rs @@ -25,6 +25,7 @@ use crate::task::{Context, Poll}; /// [`async`]: ../../std/keyword.async.html /// [`Waker`]: crate::task::Waker #[doc(notable_trait)] +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"] diff --git a/core/src/hash/sip.rs b/core/src/hash/sip.rs index 17f2caaa0c083..6ea3241c59354 100644 --- a/core/src/hash/sip.rs +++ b/core/src/hash/sip.rs @@ -147,9 +147,8 @@ impl SipHasher { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] - #[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[must_use] - pub const fn new() -> SipHasher { + pub fn new() -> SipHasher { SipHasher::new_with_keys(0, 0) } @@ -157,9 +156,8 @@ impl SipHasher { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] - #[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[must_use] - pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher { + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { SipHasher(SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) }) } } @@ -169,8 +167,7 @@ impl SipHasher13 { #[inline] #[unstable(feature = "hashmap_internals", issue = "none")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] - #[rustc_const_unstable(feature = "const_hash", issue = "104061")] - pub const fn new() -> SipHasher13 { + pub fn new() -> SipHasher13 { SipHasher13::new_with_keys(0, 0) } @@ -178,8 +175,7 @@ impl SipHasher13 { #[inline] #[unstable(feature = "hashmap_internals", issue = "none")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] - #[rustc_const_unstable(feature = "const_hash", issue = "104061")] - pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) } } } diff --git a/core/src/intrinsics.rs b/core/src/intrinsics.rs deleted file mode 100644 index fc09da7bcbc65..0000000000000 --- a/core/src/intrinsics.rs +++ /dev/null @@ -1,3747 +0,0 @@ -//! Compiler intrinsics. -//! -//! The corresponding definitions are in . -//! The corresponding const implementations are in . -//! -//! # Const intrinsics -//! -//! Note: any changes to the constness of intrinsics should be discussed with the language team. -//! This includes changes in the stability of the constness. -//! -//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation -//! from to -//! and add a -//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration. -//! -//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, -//! `#[rustc_const_stable_indirect]` needs to be added to the intrinsic (`#[rustc_const_unstable]` -//! can be removed then). Such a change should not be done without T-lang consultation, because it -//! may bake a feature into the language that cannot be replicated in user code without compiler -//! support. -//! -//! # Volatiles -//! -//! 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 -//! -//! # 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`. -//! -//! # Unwinding -//! -//! Rust intrinsics may, in general, unwind. If an intrinsic can never unwind, add the -//! `#[rustc_nounwind]` attribute so that the compiler can make use of this fact. -//! -//! However, even for intrinsics that may unwind, rustc assumes that a Rust intrinsics will never -//! initiate a foreign (non-Rust) unwind, and thus for panic=abort we can always assume that these -//! intrinsics cannot unwind. - -#![unstable( - feature = "core_intrinsics", - reason = "intrinsics are unlikely to ever be stabilized, instead \ - they should be used through stabilized interfaces \ - in the rest of the standard library", - issue = "none" -)] -#![allow(missing_docs)] - -use crate::marker::{DiscriminantKind, Tuple}; -use crate::mem::SizedTypeProperties; -use crate::{ptr, ub_checks}; - -pub mod mir; -pub mod simd; - -// These imports are used for simplifying intra-doc links -#[allow(unused_imports)] -#[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))] -use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; - -#[stable(feature = "drop_in_place", since = "1.8.0")] -#[rustc_allowed_through_unstable_modules] -#[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] -#[inline] -pub unsafe fn drop_in_place(to_drop: *mut T) { - // SAFETY: see `ptr::drop_in_place` - unsafe { crate::ptr::drop_in_place(to_drop) } -} - -extern "rust-intrinsic" { - // N.B., these intrinsics take raw pointers because they mutate aliased - // memory, which is not valid for either `&` or `&mut`. - - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Relaxed`] as both the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_relaxed_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_relaxed_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_relaxed_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_acquire_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Acquire`] as both the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_acquire_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_release_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_acqrel_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_acqrel_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_acqrel_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_seqcst_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_seqcst_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`] as both the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange`]. - #[rustc_nounwind] - pub fn atomic_cxchg_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Relaxed`] as both the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_relaxed_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_relaxed_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_relaxed_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_acquire_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Acquire`] as both the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_acquire_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_release_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_acqrel_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_acqrel_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_acqrel_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_seqcst_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_seqcst_acquire(dst: *mut T, old: T, src: T) -> (T, bool); - /// Stores a value if the current value is the same as the `old` value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`] as both the success and failure parameters. - /// For example, [`AtomicBool::compare_exchange_weak`]. - #[rustc_nounwind] - pub fn atomic_cxchgweak_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); - - /// Loads the current value of the pointer. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `load` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::load`]. - #[rustc_nounwind] - pub fn atomic_load_seqcst(src: *const T) -> T; - /// Loads the current value of the pointer. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `load` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::load`]. - #[rustc_nounwind] - pub fn atomic_load_acquire(src: *const T) -> T; - /// Loads the current value of the pointer. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `load` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::load`]. - #[rustc_nounwind] - pub fn atomic_load_relaxed(src: *const T) -> T; - /// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model! - /// In terms of the Rust Abstract Machine, this operation is equivalent to `src.read()`, - /// i.e., it performs a non-atomic read. - #[rustc_nounwind] - pub fn atomic_load_unordered(src: *const T) -> T; - - /// Stores the value at the specified memory location. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `store` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::store`]. - #[rustc_nounwind] - pub fn atomic_store_seqcst(dst: *mut T, val: T); - /// Stores the value at the specified memory location. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `store` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::store`]. - #[rustc_nounwind] - pub fn atomic_store_release(dst: *mut T, val: T); - /// Stores the value at the specified memory location. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `store` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::store`]. - #[rustc_nounwind] - pub fn atomic_store_relaxed(dst: *mut T, val: T); - /// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model! - /// In terms of the Rust Abstract Machine, this operation is equivalent to `dst.write(val)`, - /// i.e., it performs a non-atomic write. - #[rustc_nounwind] - pub fn atomic_store_unordered(dst: *mut T, val: T); - - /// Stores the value at the specified memory location, returning the old value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `swap` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::swap`]. - #[rustc_nounwind] - pub fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; - /// Stores the value at the specified memory location, returning the old value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `swap` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::swap`]. - #[rustc_nounwind] - pub fn atomic_xchg_acquire(dst: *mut T, src: T) -> T; - /// Stores the value at the specified memory location, returning the old value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `swap` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::swap`]. - #[rustc_nounwind] - pub fn atomic_xchg_release(dst: *mut T, src: T) -> T; - /// Stores the value at the specified memory location, returning the old value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `swap` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::swap`]. - #[rustc_nounwind] - pub fn atomic_xchg_acqrel(dst: *mut T, src: T) -> T; - /// Stores the value at the specified memory location, returning the old value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `swap` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::swap`]. - #[rustc_nounwind] - pub fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; - - /// Adds to the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_add` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_add`]. - #[rustc_nounwind] - pub fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; - /// Adds to the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_add` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_add`]. - #[rustc_nounwind] - pub fn atomic_xadd_acquire(dst: *mut T, src: T) -> T; - /// Adds to the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_add` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_add`]. - #[rustc_nounwind] - pub fn atomic_xadd_release(dst: *mut T, src: T) -> T; - /// Adds to the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_add` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_add`]. - #[rustc_nounwind] - pub fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; - /// Adds to the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_add` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_add`]. - #[rustc_nounwind] - pub fn atomic_xadd_relaxed(dst: *mut T, src: T) -> T; - - /// Subtract from the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_sub` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. - #[rustc_nounwind] - pub fn atomic_xsub_seqcst(dst: *mut T, src: T) -> T; - /// Subtract from the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_sub` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. - #[rustc_nounwind] - pub fn atomic_xsub_acquire(dst: *mut T, src: T) -> T; - /// Subtract from the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_sub` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. - #[rustc_nounwind] - pub fn atomic_xsub_release(dst: *mut T, src: T) -> T; - /// Subtract from the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_sub` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. - #[rustc_nounwind] - pub fn atomic_xsub_acqrel(dst: *mut T, src: T) -> T; - /// Subtract from the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_sub` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. - #[rustc_nounwind] - pub fn atomic_xsub_relaxed(dst: *mut T, src: T) -> T; - - /// Bitwise and with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_and` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_and`]. - #[rustc_nounwind] - pub fn atomic_and_seqcst(dst: *mut T, src: T) -> T; - /// Bitwise and with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_and` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_and`]. - #[rustc_nounwind] - pub fn atomic_and_acquire(dst: *mut T, src: T) -> T; - /// Bitwise and with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_and` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_and`]. - #[rustc_nounwind] - pub fn atomic_and_release(dst: *mut T, src: T) -> T; - /// Bitwise and with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_and` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_and`]. - #[rustc_nounwind] - pub fn atomic_and_acqrel(dst: *mut T, src: T) -> T; - /// Bitwise and with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_and` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_and`]. - #[rustc_nounwind] - pub fn atomic_and_relaxed(dst: *mut T, src: T) -> T; - - /// Bitwise nand with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`AtomicBool`] type via the `fetch_nand` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_nand`]. - #[rustc_nounwind] - pub fn atomic_nand_seqcst(dst: *mut T, src: T) -> T; - /// Bitwise nand with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`AtomicBool`] type via the `fetch_nand` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_nand`]. - #[rustc_nounwind] - pub fn atomic_nand_acquire(dst: *mut T, src: T) -> T; - /// Bitwise nand with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`AtomicBool`] type via the `fetch_nand` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_nand`]. - #[rustc_nounwind] - pub fn atomic_nand_release(dst: *mut T, src: T) -> T; - /// Bitwise nand with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`AtomicBool`] type via the `fetch_nand` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_nand`]. - #[rustc_nounwind] - pub fn atomic_nand_acqrel(dst: *mut T, src: T) -> T; - /// Bitwise nand with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`AtomicBool`] type via the `fetch_nand` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_nand`]. - #[rustc_nounwind] - pub fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; - - /// Bitwise or with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_or` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_or`]. - #[rustc_nounwind] - pub fn atomic_or_seqcst(dst: *mut T, src: T) -> T; - /// Bitwise or with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_or` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_or`]. - #[rustc_nounwind] - pub fn atomic_or_acquire(dst: *mut T, src: T) -> T; - /// Bitwise or with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_or` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_or`]. - #[rustc_nounwind] - pub fn atomic_or_release(dst: *mut T, src: T) -> T; - /// Bitwise or with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_or` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_or`]. - #[rustc_nounwind] - pub fn atomic_or_acqrel(dst: *mut T, src: T) -> T; - /// Bitwise or with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_or` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_or`]. - #[rustc_nounwind] - pub fn atomic_or_relaxed(dst: *mut T, src: T) -> T; - - /// Bitwise xor with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_xor` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_xor`]. - #[rustc_nounwind] - pub fn atomic_xor_seqcst(dst: *mut T, src: T) -> T; - /// Bitwise xor with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_xor` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_xor`]. - #[rustc_nounwind] - pub fn atomic_xor_acquire(dst: *mut T, src: T) -> T; - /// Bitwise xor with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_xor` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_xor`]. - #[rustc_nounwind] - pub fn atomic_xor_release(dst: *mut T, src: T) -> T; - /// Bitwise xor with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_xor` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_xor`]. - #[rustc_nounwind] - pub fn atomic_xor_acqrel(dst: *mut T, src: T) -> T; - /// Bitwise xor with the current value, returning the previous value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] types via the `fetch_xor` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_xor`]. - #[rustc_nounwind] - pub fn atomic_xor_relaxed(dst: *mut T, src: T) -> T; - - /// Maximum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_max` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_max_seqcst(dst: *mut T, src: T) -> T; - /// Maximum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_max` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_max_acquire(dst: *mut T, src: T) -> T; - /// Maximum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_max` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_max_release(dst: *mut T, src: T) -> T; - /// Maximum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_max` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_max_acqrel(dst: *mut T, src: T) -> T; - /// Maximum with the current value. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_max` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_max_relaxed(dst: *mut T, src: T) -> T; - - /// Minimum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_min` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_min_seqcst(dst: *mut T, src: T) -> T; - /// Minimum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_min` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_min_acquire(dst: *mut T, src: T) -> T; - /// Minimum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_min` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_min_release(dst: *mut T, src: T) -> T; - /// Minimum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_min` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_min_acqrel(dst: *mut T, src: T) -> T; - /// Minimum with the current value using a signed comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] signed integer types via the `fetch_min` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_min_relaxed(dst: *mut T, src: T) -> T; - - /// Minimum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_umin_seqcst(dst: *mut T, src: T) -> T; - /// Minimum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_umin_acquire(dst: *mut T, src: T) -> T; - /// Minimum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_umin_release(dst: *mut T, src: T) -> T; - /// Minimum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_umin_acqrel(dst: *mut T, src: T) -> T; - /// Minimum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_min` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_min`]. - #[rustc_nounwind] - pub fn atomic_umin_relaxed(dst: *mut T, src: T) -> T; - - /// Maximum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_umax_seqcst(dst: *mut T, src: T) -> T; - /// Maximum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_umax_acquire(dst: *mut T, src: T) -> T; - /// Maximum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_umax_release(dst: *mut T, src: T) -> T; - /// Maximum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_umax_acqrel(dst: *mut T, src: T) -> T; - /// Maximum with the current value using an unsigned comparison. - /// - /// The stabilized version of this intrinsic is available on the - /// [`atomic`] unsigned integer types via the `fetch_max` method by passing - /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_max`]. - #[rustc_nounwind] - pub fn atomic_umax_relaxed(dst: *mut T, src: T) -> T; - - /// An atomic fence. - /// - /// The stabilized version of this intrinsic is available in - /// [`atomic::fence`] by passing [`Ordering::SeqCst`] - /// as the `order`. - #[rustc_nounwind] - pub fn atomic_fence_seqcst(); - /// An atomic fence. - /// - /// The stabilized version of this intrinsic is available in - /// [`atomic::fence`] by passing [`Ordering::Acquire`] - /// as the `order`. - #[rustc_nounwind] - pub fn atomic_fence_acquire(); - /// An atomic fence. - /// - /// The stabilized version of this intrinsic is available in - /// [`atomic::fence`] by passing [`Ordering::Release`] - /// as the `order`. - #[rustc_nounwind] - pub fn atomic_fence_release(); - /// An atomic fence. - /// - /// The stabilized version of this intrinsic is available in - /// [`atomic::fence`] by passing [`Ordering::AcqRel`] - /// as the `order`. - #[rustc_nounwind] - pub fn atomic_fence_acqrel(); - - /// A compiler-only memory barrier. - /// - /// Memory accesses will never be reordered across this barrier by the - /// compiler, but no instructions will be emitted for it. This is - /// appropriate for operations on the same thread that may be preempted, - /// such as when interacting with signal handlers. - /// - /// The stabilized version of this intrinsic is available in - /// [`atomic::compiler_fence`] by passing [`Ordering::SeqCst`] - /// as the `order`. - #[rustc_nounwind] - pub fn atomic_singlethreadfence_seqcst(); - /// A compiler-only memory barrier. - /// - /// Memory accesses will never be reordered across this barrier by the - /// compiler, but no instructions will be emitted for it. This is - /// appropriate for operations on the same thread that may be preempted, - /// such as when interacting with signal handlers. - /// - /// The stabilized version of this intrinsic is available in - /// [`atomic::compiler_fence`] by passing [`Ordering::Acquire`] - /// as the `order`. - #[rustc_nounwind] - pub fn atomic_singlethreadfence_acquire(); - /// A compiler-only memory barrier. - /// - /// Memory accesses will never be reordered across this barrier by the - /// compiler, but no instructions will be emitted for it. This is - /// appropriate for operations on the same thread that may be preempted, - /// such as when interacting with signal handlers. - /// - /// The stabilized version of this intrinsic is available in - /// [`atomic::compiler_fence`] by passing [`Ordering::Release`] - /// as the `order`. - #[rustc_nounwind] - pub fn atomic_singlethreadfence_release(); - /// A compiler-only memory barrier. - /// - /// Memory accesses will never be reordered across this barrier by the - /// compiler, but no instructions will be emitted for it. This is - /// appropriate for operations on the same thread that may be preempted, - /// such as when interacting with signal handlers. - /// - /// The stabilized version of this intrinsic is available in - /// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] - /// as the `order`. - #[rustc_nounwind] - pub fn atomic_singlethreadfence_acqrel(); - - /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a no-op. - /// Prefetches have no effect on the behavior of the program but can change its performance - /// characteristics. - /// - /// The `locality` argument must be a constant integer and is a temporal locality specifier - /// ranging from (0) - no locality, to (3) - extremely local keep in cache. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn prefetch_read_data(data: *const T, locality: i32); - /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a no-op. - /// Prefetches have no effect on the behavior of the program but can change its performance - /// characteristics. - /// - /// The `locality` argument must be a constant integer and is a temporal locality specifier - /// ranging from (0) - no locality, to (3) - extremely local keep in cache. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn prefetch_write_data(data: *const T, locality: i32); - /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a no-op. - /// Prefetches have no effect on the behavior of the program but can change its performance - /// characteristics. - /// - /// The `locality` argument must be a constant integer and is a temporal locality specifier - /// ranging from (0) - no locality, to (3) - extremely local keep in cache. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn prefetch_read_instruction(data: *const T, locality: i32); - /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a no-op. - /// Prefetches have no effect on the behavior of the program but can change its performance - /// characteristics. - /// - /// The `locality` argument must be a constant integer and is a temporal locality specifier - /// ranging from (0) - no locality, to (3) - extremely local keep in cache. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn prefetch_write_instruction(data: *const T, locality: i32); - - /// Magic intrinsic that derives its meaning from attributes - /// attached to the function. - /// - /// For example, dataflow uses this to inject static assertions so - /// that `rustc_peek(potentially_uninitialized)` would actually - /// double-check that dataflow did indeed compute that it is - /// uninitialized at that point in the control flow. - /// - /// This intrinsic should not be used outside of the compiler. - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn rustc_peek(_: T) -> T; - - /// Aborts the execution of the process. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// [`std::process::abort`](../../std/process/fn.abort.html) is to be preferred if possible, - /// as its behavior is more user-friendly and more stable. - /// - /// The current implementation of `intrinsics::abort` is to invoke an invalid instruction, - /// on most platforms. - /// On Unix, the - /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or - /// `SIGBUS`. The precise behavior is not guaranteed and not stable. - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn abort() -> !; - - /// Informs the optimizer that this point in the code is not reachable, - /// enabling further optimizations. - /// - /// N.B., this is very different from the `unreachable!()` macro: Unlike the - /// macro, which panics when it is executed, it is *undefined behavior* to - /// reach code marked with this function. - /// - /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unreachable() -> !; -} - -/// Informs the optimizer that a condition is always true. -/// If the condition is false, the behavior is undefined. -/// -/// No code is generated for this intrinsic, but the optimizer will try -/// to preserve it (and its condition) between passes, which may interfere -/// with optimization of surrounding code and reduce performance. It should -/// not be used if the invariant can be discovered by the optimizer on its -/// own, or if it does not enable any significant optimizations. -/// -/// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -pub const unsafe fn assume(b: bool) { - if !b { - // SAFETY: the caller must guarantee the argument is never `false` - unsafe { unreachable() } - } -} - -/// Hints to the compiler that branch condition is likely to be true. -/// Returns the value passed to it. -/// -/// Any use other than with `if` statements will probably not have an effect. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// This intrinsic does not have a stable counterpart. -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -#[rustc_nounwind] -#[miri::intrinsic_fallback_is_spec] -pub const fn likely(b: bool) -> bool { - b -} - -/// Hints to the compiler that branch condition is likely to be false. -/// Returns the value passed to it. -/// -/// Any use other than with `if` statements will probably not have an effect. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// This intrinsic does not have a stable counterpart. -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -#[rustc_nounwind] -#[miri::intrinsic_fallback_is_spec] -pub const fn unlikely(b: bool) -> bool { - b -} - -/// Returns either `true_val` or `false_val` depending on condition `b` with a -/// hint to the compiler that this condition is unlikely to be correctly -/// predicted by a CPU's branch predictor (e.g. a binary search). -/// -/// This is otherwise functionally equivalent to `if b { true_val } else { false_val }`. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// This intrinsic does not have a stable counterpart. -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -#[rustc_nounwind] -#[miri::intrinsic_fallback_is_spec] -#[inline] -pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { - if b { true_val } else { false_val } -} - -extern "rust-intrinsic" { - /// Executes a breakpoint trap, for inspection by a debugger. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn breakpoint(); - - /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: - /// This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_inhabited(); - - /// A guard for unsafe functions that cannot ever be executed if `T` does not permit - /// zero-initialization: This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_zero_valid(); - - /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_mem_uninitialized_valid(); - - /// Gets a reference to a static `Location` indicating where it was called. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// Consider using [`core::panic::Location::caller`] instead. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn caller_location() -> &'static crate::panic::Location<'static>; - - /// Moves a value out of scope without running drop glue. - /// - /// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses - /// `ManuallyDrop` instead. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn forget(_: T); - - /// Reinterprets the bits of a value of one type as another type. - /// - /// Both types must have the same size. Compilation will fail if this is not guaranteed. - /// - /// `transmute` is semantically equivalent to a bitwise move of one type - /// into another. It copies the bits from the source value into the - /// destination value, then forgets the original. Note that source and destination - /// are passed by-value, which means if `Src` or `Dst` contain padding, that padding - /// is *not* guaranteed to be preserved by `transmute`. - /// - /// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at - /// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler - /// will generate code *assuming that you, the programmer, ensure that there will never be - /// undefined behavior*. It is therefore your responsibility to guarantee that every value - /// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition - /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly - /// unsafe**. `transmute` should be the absolute last resort. - /// - /// Because `transmute` is a by-value operation, alignment of the *transmuted values - /// themselves* is not a concern. As with any other function, the compiler already ensures - /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point - /// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper - /// alignment of the pointed-to values. - /// - /// The [nomicon](../../nomicon/transmutes.html) has additional documentation. - /// - /// [ub]: ../../reference/behavior-considered-undefined.html - /// - /// # Transmutation between pointers and integers - /// - /// Special care has to be taken when transmuting between pointers and integers, e.g. - /// transmuting between `*const ()` and `usize`. - /// - /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless - /// the pointer was originally created *from* an integer. (That includes this function - /// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling], - /// but also semantically-equivalent conversions such as punning through `repr(C)` union - /// fields.) Any attempt to use the resulting value for integer operations will abort - /// const-evaluation. (And even outside `const`, such transmutation is touching on many - /// unspecified aspects of the Rust memory model and should be avoided. See below for - /// alternatives.) - /// - /// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not* - /// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed - /// this way is currently considered undefined behavior. - /// - /// All this also applies when the integer is nested inside an array, tuple, struct, or enum. - /// However, `MaybeUninit` is not considered an integer type for the purpose of this - /// section. Transmuting `*const ()` to `MaybeUninit` is fine---but then calling - /// `assume_init()` on that result is considered as completing the pointer-to-integer transmute - /// and thus runs into the issues discussed above. - /// - /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a - /// lossless process. If you want to round-trip a pointer through an integer in a way that you - /// can get back the original pointer, you need to use `as` casts, or replace the integer type - /// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to - /// store data of arbitrary type, also use `MaybeUninit` (that will also handle uninitialized - /// memory due to padding). If you specifically need to store something that is "either an - /// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without - /// any loss (via `as` casts or via `transmute`). - /// - /// # Examples - /// - /// There are a few things that `transmute` is really useful for. - /// - /// Turning a pointer into a function pointer. This is *not* portable to - /// machines where function pointers and data pointers have different sizes. - /// - /// ``` - /// fn foo() -> i32 { - /// 0 - /// } - /// // Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer. - /// // This avoids an integer-to-pointer `transmute`, which can be problematic. - /// // Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine. - /// let pointer = foo as *const (); - /// let function = unsafe { - /// std::mem::transmute::<*const (), fn() -> i32>(pointer) - /// }; - /// assert_eq!(function(), 0); - /// ``` - /// - /// Extending a lifetime, or shortening an invariant lifetime. This is - /// advanced, very unsafe Rust! - /// - /// ``` - /// struct R<'a>(&'a i32); - /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// std::mem::transmute::, R<'static>>(r) - /// } - /// - /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b mut R<'c> { - /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) - /// } - /// ``` - /// - /// # Alternatives - /// - /// Don't despair: many uses of `transmute` can be achieved through other means. - /// Below are common applications of `transmute` which can be replaced with safer - /// constructs. - /// - /// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.: - /// - /// ``` - /// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; - /// - /// let num = unsafe { - /// std::mem::transmute::<[u8; 4], u32>(raw_bytes) - /// }; - /// - /// // use `u32::from_ne_bytes` instead - /// let num = u32::from_ne_bytes(raw_bytes); - /// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness - /// let num = u32::from_le_bytes(raw_bytes); - /// assert_eq!(num, 0x12345678); - /// let num = u32::from_be_bytes(raw_bytes); - /// assert_eq!(num, 0x78563412); - /// ``` - /// - /// Turning a pointer into a `usize`: - /// - /// ```no_run - /// let ptr = &0; - /// let ptr_num_transmute = unsafe { - /// std::mem::transmute::<&i32, usize>(ptr) - /// }; - /// - /// // Use an `as` cast instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// ``` - /// - /// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined - /// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave - /// as expected -- this is touching on many unspecified aspects of the Rust memory model. - /// Depending on what the code is doing, the following alternatives are preferable to - /// pointer-to-integer transmutation: - /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a - /// type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit]. - /// - If the code actually wants to work on the address the pointer points to, it can use `as` - /// casts or [`ptr.addr()`][pointer::addr]. - /// - /// Turning a `*mut T` into a `&mut T`: - /// - /// ``` - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = unsafe { - /// std::mem::transmute::<*mut i32, &mut i32>(ptr) - /// }; - /// - /// // Use a reborrow instead - /// let ref_casted = unsafe { &mut *ptr }; - /// ``` - /// - /// Turning a `&mut T` into a `&mut U`: - /// - /// ``` - /// let ptr = &mut 0; - /// let val_transmuted = unsafe { - /// std::mem::transmute::<&mut i32, &mut u32>(ptr) - /// }; - /// - /// // Now, put together `as` and reborrowing - note the chaining of `as` - /// // `as` is not transitive - /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; - /// ``` - /// - /// Turning a `&str` into a `&[u8]`: - /// - /// ``` - /// // this is not a good way to do this. - /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, &[82, 117, 115, 116]); - /// - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, &[82, 117, 115, 116]); - /// - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", &[82, 117, 115, 116]); - /// ``` - /// - /// Turning a `Vec<&T>` into a `Vec>`. - /// - /// To transmute the inner type of the contents of a container, you must make sure to not - /// violate any of the container's invariants. For `Vec`, this means that both the size - /// *and alignment* of the inner types have to match. Other containers might rely on the - /// size of the type, alignment, or even the `TypeId`, in which case transmuting wouldn't - /// be possible at all without violating the container invariants. - /// - /// ``` - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// - /// // clone the vector as we will reuse them later - /// let v_clone = v_orig.clone(); - /// - /// // Using transmute: this relies on the unspecified data layout of `Vec`, which is a - /// // bad idea and could cause Undefined Behavior. - /// // However, it is no-copy. - /// let v_transmuted = unsafe { - /// std::mem::transmute::, Vec>>(v_clone) - /// }; - /// - /// let v_clone = v_orig.clone(); - /// - /// // This is the suggested, safe way. - /// // It may copy the entire vector into a new one though, but also may not. - /// let v_collected = v_clone.into_iter() - /// .map(Some) - /// .collect::>>(); - /// - /// let v_clone = v_orig.clone(); - /// - /// // This is the proper no-copy, unsafe way of "transmuting" a `Vec`, without relying on the - /// // data layout. Instead of literally calling `transmute`, we perform a pointer cast, but - /// // in terms of converting the original inner type (`&i32`) to the new one (`Option<&i32>`), - /// // this has all the same caveats. Besides the information provided above, also consult the - /// // [`from_raw_parts`] documentation. - /// let v_from_raw = unsafe { - // FIXME Update this when vec_into_raw_parts is stabilized - /// // Ensure the original vector is not dropped. - /// let mut v_clone = std::mem::ManuallyDrop::new(v_clone); - /// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>, - /// v_clone.len(), - /// v_clone.capacity()) - /// }; - /// ``` - /// - /// [`from_raw_parts`]: ../../std/vec/struct.Vec.html#method.from_raw_parts - /// - /// Implementing `split_at_mut`: - /// - /// ``` - /// use std::{slice, mem}; - /// - /// // There are multiple ways to do this, and there are multiple problems - /// // with the following (transmute) way. - /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); - /// // first: transmute is not type safe; all it checks is that T and - /// // U are of the same size. Second, right here, you have two - /// // mutable references pointing to the same memory. - /// (&mut slice[0..mid], &mut slice2[mid..len]) - /// } - /// } - /// - /// // This gets rid of the type safety problems; `&mut *` will *only* give - /// // you a `&mut T` from a `&mut T` or `*mut T`. - /// fn split_at_mut_casts(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let slice2 = &mut *(slice as *mut [T]); - /// // however, you still have two mutable references pointing to - /// // the same memory. - /// (&mut slice[0..mid], &mut slice2[mid..len]) - /// } - /// } - /// - /// // This is how the standard library does it. This is the best method, if - /// // you need to do something like this - /// fn split_at_stdlib(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let ptr = slice.as_mut_ptr(); - /// // This now has three mutable references pointing at the same - /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. - /// // `slice` is never used after `let ptr = ...`, and so one can - /// // treat it as "dead", and therefore, you only have two real - /// // mutable slices. - /// (slice::from_raw_parts_mut(ptr, mid), - /// slice::from_raw_parts_mut(ptr.add(mid), len - mid)) - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_allowed_through_unstable_modules] - #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] - #[rustc_diagnostic_item = "transmute"] - #[rustc_nounwind] - pub fn transmute(src: Src) -> Dst; - - /// Like [`transmute`], but even less checked at compile-time: rather than - /// giving an error for `size_of::() != size_of::()`, it's - /// **Undefined Behavior** at runtime. - /// - /// Prefer normal `transmute` where possible, for the extra checking, since - /// both do exactly the same thing at runtime, if they both compile. - /// - /// This is not expected to ever be exposed directly to users, rather it - /// may eventually be exposed through some more-constrained API. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn transmute_unchecked(src: Src) -> Dst; - - /// Returns `true` if the actual type given as `T` requires drop - /// glue; returns `false` if the actual type provided for `T` - /// implements `Copy`. - /// - /// If the actual type neither requires drop glue nor implements - /// `Copy`, then the return value of this function is unspecified. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn needs_drop() -> bool; - - /// Calculates the offset from a pointer. - /// - /// This is implemented as an intrinsic to avoid converting to and from an - /// integer, since the conversion would throw away aliasing information. - /// - /// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`) - /// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other - /// instantiations may arbitrarily misbehave, and that's *not* a compiler bug. - /// - /// # Safety - /// - /// If the computed offset is non-zero, then both the starting and resulting pointer must be - /// either in bounds or at the end of an allocated object. If either pointer is out - /// of bounds or arithmetic overflow occurs then this operation is undefined behavior. - /// - /// The stabilized version of this intrinsic is [`pointer::offset`]. - #[must_use = "returns a new pointer rather than modifying its argument"] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn offset(dst: Ptr, offset: Delta) -> Ptr; - - /// Calculates the offset from a pointer, potentially wrapping. - /// - /// This is implemented as an intrinsic to avoid converting to and from an - /// integer, since the conversion inhibits certain optimizations. - /// - /// # Safety - /// - /// Unlike the `offset` intrinsic, this intrinsic does not restrict the - /// resulting pointer to point into or at the end of an allocated - /// object, and it wraps with two's complement arithmetic. The resulting - /// value is not necessarily valid to be used to actually access memory. - /// - /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. - #[must_use = "returns a new pointer rather than modifying its argument"] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn arith_offset(dst: *const T, offset: isize) -> *const T; - - /// Masks out bits of the pointer according to a mask. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// Consider using [`pointer::mask`] instead. - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn ptr_mask(ptr: *const T, mask: usize) -> *const T; - - /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with - /// a size of `count` * `size_of::()` and an alignment of - /// `min_align_of::()` - /// - /// The volatile parameter is set to `true`, so it will not be optimized out - /// unless size is equal to zero. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: usize); - /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with - /// a size of `count * size_of::()` and an alignment of - /// `min_align_of::()` - /// - /// The volatile parameter is set to `true`, so it will not be optimized out - /// unless size is equal to zero. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); - /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a - /// size of `count * size_of::()` and an alignment of - /// `min_align_of::()`. - /// - /// The volatile parameter is set to `true`, so it will not be optimized out - /// unless size is equal to zero. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); - - /// Performs a volatile load from the `src` pointer. - /// - /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`]. - #[rustc_nounwind] - pub fn volatile_load(src: *const T) -> T; - /// Performs a volatile store to the `dst` pointer. - /// - /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`]. - #[rustc_nounwind] - pub fn volatile_store(dst: *mut T, val: T); - - /// Performs a volatile load from the `src` pointer - /// The pointer is not required to be aligned. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_load"] - pub fn unaligned_volatile_load(src: *const T) -> T; - /// Performs a volatile store to the `dst` pointer. - /// The pointer is not required to be aligned. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"] - pub fn unaligned_volatile_store(dst: *mut T, val: T); - - /// Returns the square root of an `f16` - /// - /// The stabilized version of this intrinsic is - /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt) - #[rustc_nounwind] - pub fn sqrtf16(x: f16) -> f16; - /// Returns the square root of an `f32` - /// - /// The stabilized version of this intrinsic is - /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt) - #[rustc_nounwind] - pub fn sqrtf32(x: f32) -> f32; - /// Returns the square root of an `f64` - /// - /// The stabilized version of this intrinsic is - /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) - #[rustc_nounwind] - pub fn sqrtf64(x: f64) -> f64; - /// Returns the square root of an `f128` - /// - /// The stabilized version of this intrinsic is - /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt) - #[rustc_nounwind] - pub fn sqrtf128(x: f128) -> f128; - - /// Raises an `f16` to an integer power. - /// - /// The stabilized version of this intrinsic is - /// [`f16::powi`](../../std/primitive.f16.html#method.powi) - #[rustc_nounwind] - pub fn powif16(a: f16, x: i32) -> f16; - /// Raises an `f32` to an integer power. - /// - /// The stabilized version of this intrinsic is - /// [`f32::powi`](../../std/primitive.f32.html#method.powi) - #[rustc_nounwind] - pub fn powif32(a: f32, x: i32) -> f32; - /// Raises an `f64` to an integer power. - /// - /// The stabilized version of this intrinsic is - /// [`f64::powi`](../../std/primitive.f64.html#method.powi) - #[rustc_nounwind] - pub fn powif64(a: f64, x: i32) -> f64; - /// Raises an `f128` to an integer power. - /// - /// The stabilized version of this intrinsic is - /// [`f128::powi`](../../std/primitive.f128.html#method.powi) - #[rustc_nounwind] - pub fn powif128(a: f128, x: i32) -> f128; - - /// Returns the sine of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::sin`](../../std/primitive.f16.html#method.sin) - #[rustc_nounwind] - pub fn sinf16(x: f16) -> f16; - /// Returns the sine of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::sin`](../../std/primitive.f32.html#method.sin) - #[rustc_nounwind] - pub fn sinf32(x: f32) -> f32; - /// Returns the sine of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::sin`](../../std/primitive.f64.html#method.sin) - #[rustc_nounwind] - pub fn sinf64(x: f64) -> f64; - /// Returns the sine of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::sin`](../../std/primitive.f128.html#method.sin) - #[rustc_nounwind] - pub fn sinf128(x: f128) -> f128; - - /// Returns the cosine of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::cos`](../../std/primitive.f16.html#method.cos) - #[rustc_nounwind] - pub fn cosf16(x: f16) -> f16; - /// Returns the cosine of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::cos`](../../std/primitive.f32.html#method.cos) - #[rustc_nounwind] - pub fn cosf32(x: f32) -> f32; - /// Returns the cosine of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::cos`](../../std/primitive.f64.html#method.cos) - #[rustc_nounwind] - pub fn cosf64(x: f64) -> f64; - /// Returns the cosine of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::cos`](../../std/primitive.f128.html#method.cos) - #[rustc_nounwind] - pub fn cosf128(x: f128) -> f128; - - /// Raises an `f16` to an `f16` power. - /// - /// The stabilized version of this intrinsic is - /// [`f16::powf`](../../std/primitive.f16.html#method.powf) - #[rustc_nounwind] - pub fn powf16(a: f16, x: f16) -> f16; - /// Raises an `f32` to an `f32` power. - /// - /// The stabilized version of this intrinsic is - /// [`f32::powf`](../../std/primitive.f32.html#method.powf) - #[rustc_nounwind] - pub fn powf32(a: f32, x: f32) -> f32; - /// Raises an `f64` to an `f64` power. - /// - /// The stabilized version of this intrinsic is - /// [`f64::powf`](../../std/primitive.f64.html#method.powf) - #[rustc_nounwind] - pub fn powf64(a: f64, x: f64) -> f64; - /// Raises an `f128` to an `f128` power. - /// - /// The stabilized version of this intrinsic is - /// [`f128::powf`](../../std/primitive.f128.html#method.powf) - #[rustc_nounwind] - pub fn powf128(a: f128, x: f128) -> f128; - - /// Returns the exponential of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::exp`](../../std/primitive.f16.html#method.exp) - #[rustc_nounwind] - pub fn expf16(x: f16) -> f16; - /// Returns the exponential of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::exp`](../../std/primitive.f32.html#method.exp) - #[rustc_nounwind] - pub fn expf32(x: f32) -> f32; - /// Returns the exponential of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::exp`](../../std/primitive.f64.html#method.exp) - #[rustc_nounwind] - pub fn expf64(x: f64) -> f64; - /// Returns the exponential of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::exp`](../../std/primitive.f128.html#method.exp) - #[rustc_nounwind] - pub fn expf128(x: f128) -> f128; - - /// Returns 2 raised to the power of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2) - #[rustc_nounwind] - pub fn exp2f16(x: f16) -> f16; - /// Returns 2 raised to the power of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) - #[rustc_nounwind] - pub fn exp2f32(x: f32) -> f32; - /// Returns 2 raised to the power of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) - #[rustc_nounwind] - pub fn exp2f64(x: f64) -> f64; - /// Returns 2 raised to the power of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2) - #[rustc_nounwind] - pub fn exp2f128(x: f128) -> f128; - - /// Returns the natural logarithm of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::ln`](../../std/primitive.f16.html#method.ln) - #[rustc_nounwind] - pub fn logf16(x: f16) -> f16; - /// Returns the natural logarithm of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::ln`](../../std/primitive.f32.html#method.ln) - #[rustc_nounwind] - pub fn logf32(x: f32) -> f32; - /// Returns the natural logarithm of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::ln`](../../std/primitive.f64.html#method.ln) - #[rustc_nounwind] - pub fn logf64(x: f64) -> f64; - /// Returns the natural logarithm of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::ln`](../../std/primitive.f128.html#method.ln) - #[rustc_nounwind] - pub fn logf128(x: f128) -> f128; - - /// Returns the base 10 logarithm of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::log10`](../../std/primitive.f16.html#method.log10) - #[rustc_nounwind] - pub fn log10f16(x: f16) -> f16; - /// Returns the base 10 logarithm of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::log10`](../../std/primitive.f32.html#method.log10) - #[rustc_nounwind] - pub fn log10f32(x: f32) -> f32; - /// Returns the base 10 logarithm of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::log10`](../../std/primitive.f64.html#method.log10) - #[rustc_nounwind] - pub fn log10f64(x: f64) -> f64; - /// Returns the base 10 logarithm of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::log10`](../../std/primitive.f128.html#method.log10) - #[rustc_nounwind] - pub fn log10f128(x: f128) -> f128; - - /// Returns the base 2 logarithm of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::log2`](../../std/primitive.f16.html#method.log2) - #[rustc_nounwind] - pub fn log2f16(x: f16) -> f16; - /// Returns the base 2 logarithm of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::log2`](../../std/primitive.f32.html#method.log2) - #[rustc_nounwind] - pub fn log2f32(x: f32) -> f32; - /// Returns the base 2 logarithm of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::log2`](../../std/primitive.f64.html#method.log2) - #[rustc_nounwind] - pub fn log2f64(x: f64) -> f64; - /// Returns the base 2 logarithm of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::log2`](../../std/primitive.f128.html#method.log2) - #[rustc_nounwind] - pub fn log2f128(x: f128) -> f128; - - /// Returns `a * b + c` for `f16` values. - /// - /// The stabilized version of this intrinsic is - /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) - #[rustc_nounwind] - pub fn fmaf16(a: f16, b: f16, c: f16) -> f16; - /// Returns `a * b + c` for `f32` values. - /// - /// The stabilized version of this intrinsic is - /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) - #[rustc_nounwind] - pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; - /// Returns `a * b + c` for `f64` values. - /// - /// The stabilized version of this intrinsic is - /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) - #[rustc_nounwind] - pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; - /// Returns `a * b + c` for `f128` values. - /// - /// The stabilized version of this intrinsic is - /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) - #[rustc_nounwind] - pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; - - /// Returns `a * b + c` for `f16` values, non-deterministically executing - /// either a fused multiply-add or two operations with rounding of the - /// intermediate result. - /// - /// The operation is fused if the code generator determines that target - /// instruction set has support for a fused operation, and that the fused - /// operation is more efficient than the equivalent, separate pair of mul - /// and add instructions. It is unspecified whether or not a fused operation - /// is selected, and that may depend on optimization level and context, for - /// example. - #[rustc_nounwind] - pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; - /// Returns `a * b + c` for `f32` values, non-deterministically executing - /// either a fused multiply-add or two operations with rounding of the - /// intermediate result. - /// - /// The operation is fused if the code generator determines that target - /// instruction set has support for a fused operation, and that the fused - /// operation is more efficient than the equivalent, separate pair of mul - /// and add instructions. It is unspecified whether or not a fused operation - /// is selected, and that may depend on optimization level and context, for - /// example. - #[rustc_nounwind] - pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; - /// Returns `a * b + c` for `f64` values, non-deterministically executing - /// either a fused multiply-add or two operations with rounding of the - /// intermediate result. - /// - /// The operation is fused if the code generator determines that target - /// instruction set has support for a fused operation, and that the fused - /// operation is more efficient than the equivalent, separate pair of mul - /// and add instructions. It is unspecified whether or not a fused operation - /// is selected, and that may depend on optimization level and context, for - /// example. - #[rustc_nounwind] - pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; - /// Returns `a * b + c` for `f128` values, non-deterministically executing - /// either a fused multiply-add or two operations with rounding of the - /// intermediate result. - /// - /// The operation is fused if the code generator determines that target - /// instruction set has support for a fused operation, and that the fused - /// operation is more efficient than the equivalent, separate pair of mul - /// and add instructions. It is unspecified whether or not a fused operation - /// is selected, and that may depend on optimization level and context, for - /// example. - #[rustc_nounwind] - pub fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; - - /// Returns the largest integer less than or equal to an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::floor`](../../std/primitive.f16.html#method.floor) - #[rustc_nounwind] - pub fn floorf16(x: f16) -> f16; - /// Returns the largest integer less than or equal to an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::floor`](../../std/primitive.f32.html#method.floor) - #[rustc_nounwind] - pub fn floorf32(x: f32) -> f32; - /// Returns the largest integer less than or equal to an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::floor`](../../std/primitive.f64.html#method.floor) - #[rustc_nounwind] - pub fn floorf64(x: f64) -> f64; - /// Returns the largest integer less than or equal to an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::floor`](../../std/primitive.f128.html#method.floor) - #[rustc_nounwind] - pub fn floorf128(x: f128) -> f128; - - /// Returns the smallest integer greater than or equal to an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) - #[rustc_nounwind] - pub fn ceilf16(x: f16) -> f16; - /// Returns the smallest integer greater than or equal to an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) - #[rustc_nounwind] - pub fn ceilf32(x: f32) -> f32; - /// Returns the smallest integer greater than or equal to an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) - #[rustc_nounwind] - pub fn ceilf64(x: f64) -> f64; - /// Returns the smallest integer greater than or equal to an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) - #[rustc_nounwind] - pub fn ceilf128(x: f128) -> f128; - - /// Returns the integer part of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) - #[rustc_nounwind] - pub fn truncf16(x: f16) -> f16; - /// Returns the integer part of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) - #[rustc_nounwind] - pub fn truncf32(x: f32) -> f32; - /// Returns the integer part of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) - #[rustc_nounwind] - pub fn truncf64(x: f64) -> f64; - /// Returns the integer part of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) - #[rustc_nounwind] - pub fn truncf128(x: f128) -> f128; - - /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// May raise an inexact floating-point exception if the argument is not an integer. - /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions - /// cannot actually be utilized from Rust code. - /// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) - #[rustc_nounwind] - pub fn rintf16(x: f16) -> f16; - /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// May raise an inexact floating-point exception if the argument is not an integer. - /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions - /// cannot actually be utilized from Rust code. - /// In other words, this intrinsic is equivalent in behavior to `nearbyintf32` and `roundevenf32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) - #[rustc_nounwind] - pub fn rintf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// May raise an inexact floating-point exception if the argument is not an integer. - /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions - /// cannot actually be utilized from Rust code. - /// In other words, this intrinsic is equivalent in behavior to `nearbyintf64` and `roundevenf64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) - #[rustc_nounwind] - pub fn rintf64(x: f64) -> f64; - /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// May raise an inexact floating-point exception if the argument is not an integer. - /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions - /// cannot actually be utilized from Rust code. - /// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) - #[rustc_nounwind] - pub fn rintf128(x: f128) -> f128; - - /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn nearbyintf16(x: f16) -> f16; - /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn nearbyintf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn nearbyintf64(x: f64) -> f64; - /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn nearbyintf128(x: f128) -> f128; - - /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. - /// - /// The stabilized version of this intrinsic is - /// [`f16::round`](../../std/primitive.f16.html#method.round) - #[rustc_nounwind] - pub fn roundf16(x: f16) -> f16; - /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. - /// - /// The stabilized version of this intrinsic is - /// [`f32::round`](../../std/primitive.f32.html#method.round) - #[rustc_nounwind] - pub fn roundf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. - /// - /// The stabilized version of this intrinsic is - /// [`f64::round`](../../std/primitive.f64.html#method.round) - #[rustc_nounwind] - pub fn roundf64(x: f64) -> f64; - /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero. - /// - /// The stabilized version of this intrinsic is - /// [`f128::round`](../../std/primitive.f128.html#method.round) - #[rustc_nounwind] - pub fn roundf128(x: f128) -> f128; - - /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn roundevenf16(x: f16) -> f16; - /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn roundevenf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn roundevenf64(x: f64) -> f64; - /// Returns the nearest integer to an `f128`. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn roundevenf128(x: f128) -> f128; - - /// Float addition that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn fadd_fast(a: T, b: T) -> T; - - /// Float subtraction that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn fsub_fast(a: T, b: T) -> T; - - /// Float multiplication that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn fmul_fast(a: T, b: T) -> T; - - /// Float division that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn fdiv_fast(a: T, b: T) -> T; - - /// Float remainder that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn frem_fast(a: T, b: T) -> T; - - /// Float addition that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn fadd_algebraic(a: T, b: T) -> T; - - /// Float subtraction that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn fsub_algebraic(a: T, b: T) -> T; - - /// Float multiplication that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn fmul_algebraic(a: T, b: T) -> T; - - /// Float division that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn fdiv_algebraic(a: T, b: T) -> T; - - /// Float remainder that allows optimizations based on algebraic rules. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_safe_intrinsic] - pub fn frem_algebraic(a: T, b: T) -> T; - - /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range - /// () - /// - /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. - #[rustc_nounwind] - pub fn float_to_int_unchecked(value: Float) -> Int; - - /// Returns the number of bits set in an integer type `T` - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `count_ones` method. For example, - /// [`u32::count_ones`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn ctpop(x: T) -> u32; - - /// Returns the number of leading unset bits (zeroes) in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `leading_zeros` method. For example, - /// [`u32::leading_zeros`] - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz; - /// - /// let x = 0b0001_1100_u8; - /// let num_leading = ctlz(x); - /// assert_eq!(num_leading, 3); - /// ``` - /// - /// An `x` with value `0` will return the bit width of `T`. - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz; - /// - /// let x = 0u16; - /// let num_leading = ctlz(x); - /// assert_eq!(num_leading, 16); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn ctlz(x: T) -> u32; - - /// Like `ctlz`, but extra-unsafe as it returns `undef` when - /// given an `x` with value `0`. - /// - /// This intrinsic does not have a stable counterpart. - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz_nonzero; - /// - /// let x = 0b0001_1100_u8; - /// let num_leading = unsafe { ctlz_nonzero(x) }; - /// assert_eq!(num_leading, 3); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn ctlz_nonzero(x: T) -> u32; - - /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `trailing_zeros` method. For example, - /// [`u32::trailing_zeros`] - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz; - /// - /// let x = 0b0011_1000_u8; - /// let num_trailing = cttz(x); - /// assert_eq!(num_trailing, 3); - /// ``` - /// - /// An `x` with value `0` will return the bit width of `T`: - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz; - /// - /// let x = 0u16; - /// let num_trailing = cttz(x); - /// assert_eq!(num_trailing, 16); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn cttz(x: T) -> u32; - - /// Like `cttz`, but extra-unsafe as it returns `undef` when - /// given an `x` with value `0`. - /// - /// This intrinsic does not have a stable counterpart. - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz_nonzero; - /// - /// let x = 0b0011_1000_u8; - /// let num_trailing = unsafe { cttz_nonzero(x) }; - /// assert_eq!(num_trailing, 3); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn cttz_nonzero(x: T) -> u32; - - /// Reverses the bytes in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `swap_bytes` method. For example, - /// [`u32::swap_bytes`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn bswap(x: T) -> T; - - /// Reverses the bits in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `reverse_bits` method. For example, - /// [`u32::reverse_bits`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn bitreverse(x: T) -> T; - - /// Does a three-way comparison between the two integer arguments. - /// - /// This is included as an intrinsic as it's useful to let it be one thing - /// in MIR, rather than the multiple checks and switches that make its IR - /// large and difficult to optimize. - /// - /// The stabilized version of this intrinsic is [`Ord::cmp`]. - #[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")] - #[rustc_safe_intrinsic] - pub fn three_way_compare(lhs: T, rhs: T) -> crate::cmp::Ordering; - - /// Performs checked integer addition. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_add` method. For example, - /// [`u32::overflowing_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn add_with_overflow(x: T, y: T) -> (T, bool); - - /// Performs checked integer subtraction - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_sub` method. For example, - /// [`u32::overflowing_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn sub_with_overflow(x: T, y: T) -> (T, bool); - - /// Performs checked integer multiplication - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_mul` method. For example, - /// [`u32::overflowing_mul`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn mul_with_overflow(x: T, y: T) -> (T, bool); - - /// Performs an exact division, resulting in undefined behavior where - /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_exact_div", issue = "none")] - #[rustc_nounwind] - pub fn exact_div(x: T, y: T) -> T; - - /// Performs an unchecked division, resulting in undefined behavior - /// where `y == 0` or `x == T::MIN && y == -1` - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_div` method. For example, - /// [`u32::checked_div`] - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_div(x: T, y: T) -> T; - /// Returns the remainder of an unchecked division, resulting in - /// undefined behavior when `y == 0` or `x == T::MIN && y == -1` - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_rem` method. For example, - /// [`u32::checked_rem`] - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_rem(x: T, y: T) -> T; - - /// Performs an unchecked left shift, resulting in undefined behavior when - /// `y < 0` or `y >= N`, where N is the width of T in bits. - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_shl` method. For example, - /// [`u32::checked_shl`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_shl(x: T, y: U) -> T; - /// Performs an unchecked right shift, resulting in undefined behavior when - /// `y < 0` or `y >= N`, where N is the width of T in bits. - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_shr` method. For example, - /// [`u32::checked_shr`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_shr(x: T, y: U) -> T; - - /// Returns the result of an unchecked addition, resulting in - /// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_add` on the various - /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_add(x: T, y: T) -> T; - - /// Returns the result of an unchecked subtraction, resulting in - /// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_sub` on the various - /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_sub(x: T, y: T) -> T; - - /// Returns the result of an unchecked multiplication, resulting in - /// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_mul` on the various - /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_mul(x: T, y: T) -> T; - - /// Performs rotate left. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `rotate_left` method. For example, - /// [`u32::rotate_left`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn rotate_left(x: T, shift: u32) -> T; - - /// Performs rotate right. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `rotate_right` method. For example, - /// [`u32::rotate_right`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn rotate_right(x: T, shift: u32) -> T; - - /// Returns (a + b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_add` method. For example, - /// [`u32::wrapping_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_add(a: T, b: T) -> T; - /// Returns (a - b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_sub` method. For example, - /// [`u32::wrapping_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_sub(a: T, b: T) -> T; - /// Returns (a * b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_mul` method. For example, - /// [`u32::wrapping_mul`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_mul(a: T, b: T) -> T; - - /// Computes `a + b`, saturating at numeric bounds. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `saturating_add` method. For example, - /// [`u32::saturating_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn saturating_add(a: T, b: T) -> T; - /// Computes `a - b`, saturating at numeric bounds. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `saturating_sub` method. For example, - /// [`u32::saturating_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn saturating_sub(a: T, b: T) -> T; - - /// This is an implementation detail of [`crate::ptr::read`] and should - /// not be used anywhere else. See its comments for why this exists. - /// - /// This intrinsic can *only* be called where the pointer is a local without - /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it - /// trivially obeys runtime-MIR rules about derefs in operands. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn read_via_copy(ptr: *const T) -> T; - - /// This is an implementation detail of [`crate::ptr::write`] and should - /// not be used anywhere else. See its comments for why this exists. - /// - /// This intrinsic can *only* be called where the pointer is a local without - /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so - /// that it trivially obeys runtime-MIR rules about derefs in operands. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn write_via_move(ptr: *mut T, value: T); - - /// Returns the value of the discriminant for the variant in 'v'; - /// if `T` has no discriminant, returns `0`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn discriminant_value(v: &T) -> ::Discriminant; - - /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the - /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. - /// - /// `catch_fn` must not unwind. - /// - /// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign - /// unwinds). This function takes the data pointer and a pointer to the target- and - /// runtime-specific exception object that was caught. - /// - /// Note that in the case of a foreign unwinding operation, the exception object data may not be - /// safely usable from Rust, and should not be directly exposed via the standard library. To - /// prevent unsafe access, the library implementation may either abort the process or present an - /// opaque error type to the user. - /// - /// For more information, see the compiler's source, as well as the documentation for the stable - /// version of this intrinsic, `std::panic::catch_unwind`. - #[rustc_nounwind] - pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; - - /// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held - /// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`. - /// - /// Not all architectures provide such an operation. For instance, x86 does not: while `MOVNT` - /// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered - /// in ways that are not allowed for regular writes). - #[rustc_nounwind] - pub fn nontemporal_store(ptr: *mut T, val: T); - - /// See documentation of `<*const T>::offset_from` for details. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; - - /// See documentation of `<*const T>::sub_ptr` for details. - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] - #[rustc_nounwind] - pub fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize; -} - -/// See documentation of `<*const T>::guaranteed_eq` for details. -/// Returns `2` if the result is unknown. -/// Returns `1` if the pointers are guaranteed equal -/// Returns `0` if the pointers are guaranteed inequal -#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -#[rustc_nounwind] -#[rustc_do_not_const_check] -#[inline] -#[miri::intrinsic_fallback_is_spec] -pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { - (ptr == other) as u8 -} - -extern "rust-intrinsic" { - /// Determines whether the raw bytes of the two values are equal. - /// - /// This is particularly handy for arrays, since it allows things like just - /// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`. - /// - /// Above some backend-decided threshold this will emit calls to `memcmp`, - /// like slice equality does, instead of causing massive code size. - /// - /// Since this works by comparing the underlying bytes, the actual `T` is - /// not particularly important. It will be used for its size and alignment, - /// but any validity restrictions will be ignored, not enforced. - /// - /// # Safety - /// - /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. - /// Note that this is a stricter criterion than just the *values* being - /// fully-initialized: if `T` has padding, it's UB to call this intrinsic. - /// - /// At compile-time, it is furthermore UB to call this if any of the bytes - /// in `*a` or `*b` have provenance. - /// - /// (The implementation is allowed to branch on the results of comparisons, - /// which is UB if any of their inputs are `undef`.) - #[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] - #[rustc_nounwind] - pub fn raw_eq(a: &T, b: &T) -> bool; - - /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` - /// as unsigned bytes, returning negative if `left` is less, zero if all the - /// bytes match, or positive if `left` is greater. - /// - /// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`. - /// - /// # Safety - /// - /// `left` and `right` must each be [valid] for reads of `bytes` bytes. - /// - /// Note that this applies to the whole range, not just until the first byte - /// that differs. That allows optimizations that can read in large chunks. - /// - /// [valid]: crate::ptr#safety - #[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] - #[rustc_nounwind] - pub fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; - - /// See documentation of [`std::hint::black_box`] for details. - /// - /// [`std::hint::black_box`]: crate::hint::black_box - #[rustc_const_unstable(feature = "const_black_box", issue = "none")] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn black_box(dummy: T) -> T; -} - -/// Selects which function to call depending on the context. -/// -/// If this function is evaluated at compile-time, then a call to this -/// intrinsic will be replaced with a call to `called_in_const`. It gets -/// replaced with a call to `called_at_rt` otherwise. -/// -/// This function is safe to call, but note the stability concerns below. -/// -/// # Type Requirements -/// -/// The two functions must be both function items. They cannot be function -/// pointers or closures. The first function must be a `const fn`. -/// -/// `arg` will be the tupled arguments that will be passed to either one of -/// the two functions, therefore, both functions must accept the same type of -/// arguments. Both functions must return RET. -/// -/// # Stability concerns -/// -/// Rust has not yet decided that `const fn` are allowed to tell whether -/// they run at compile-time or at runtime. Therefore, when using this -/// intrinsic anywhere that can be reached from stable, it is crucial that -/// the end-to-end behavior of the stable `const fn` is the same for both -/// modes of execution. (Here, Undefined Behavior is considered "the same" -/// as any other behavior, so if the function exhibits UB at runtime then -/// it may do whatever it wants at compile-time.) -/// -/// Here is an example of how this could cause a problem: -/// ```no_run -/// #![feature(const_eval_select)] -/// #![feature(core_intrinsics)] -/// # #![allow(internal_features)] -/// use std::intrinsics::const_eval_select; -/// -/// // Standard library -/// pub const fn inconsistent() -> i32 { -/// fn runtime() -> i32 { 1 } -/// const fn compiletime() -> i32 { 2 } -/// -/// // ⚠ This code violates the required equivalence of `compiletime` -/// // and `runtime`. -/// const_eval_select((), compiletime, runtime) -/// } -/// -/// // User Crate -/// const X: i32 = inconsistent(); -/// let x = inconsistent(); -/// assert_eq!(x, X); -/// ``` -/// -/// Currently such an assertion would always succeed; until Rust decides -/// otherwise, that principle should not be violated. -#[rustc_const_unstable(feature = "const_eval_select", issue = "124625")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn const_eval_select( - _arg: ARG, - _called_in_const: F, - _called_at_rt: G, -) -> RET -where - G: FnOnce, - F: FnOnce, -{ - unreachable!() -} - -/// Returns whether the argument's value is statically known at -/// compile-time. -/// -/// This is useful when there is a way of writing the code that will -/// be *faster* when some variables have known values, but *slower* -/// in the general case: an `if is_val_statically_known(var)` can be used -/// to select between these two variants. The `if` will be optimized away -/// and only the desired branch remains. -/// -/// Formally speaking, this function non-deterministically returns `true` -/// or `false`, and the caller has to ensure sound behavior for both cases. -/// In other words, the following code has *Undefined Behavior*: -/// -/// ```no_run -/// #![feature(is_val_statically_known)] -/// #![feature(core_intrinsics)] -/// # #![allow(internal_features)] -/// use std::hint::unreachable_unchecked; -/// use std::intrinsics::is_val_statically_known; -/// -/// if !is_val_statically_known(0) { unsafe { unreachable_unchecked(); } } -/// ``` -/// -/// This also means that the following code's behavior is unspecified; it -/// may panic, or it may not: -/// -/// ```no_run -/// #![feature(is_val_statically_known)] -/// #![feature(core_intrinsics)] -/// # #![allow(internal_features)] -/// use std::intrinsics::is_val_statically_known; -/// -/// assert_eq!(is_val_statically_known(0), is_val_statically_known(0)); -/// ``` -/// -/// Unsafe code may not rely on `is_val_statically_known` returning any -/// particular value, ever. However, the compiler will generally make it -/// return `true` only if the value of the argument is actually known. -/// -/// # Stability concerns -/// -/// While it is safe to call, this intrinsic may behave differently in -/// a `const` context than otherwise. See the [`const_eval_select`] -/// documentation for an explanation of the issues this can cause. Unlike -/// `const_eval_select`, this intrinsic isn't guaranteed to behave -/// deterministically even in a `const` context. -/// -/// # Type Requirements -/// -/// `T` must be either a `bool`, a `char`, a primitive numeric type (e.g. `f32`, -/// but not `NonZeroISize`), or any thin pointer (e.g. `*mut String`). -/// Any other argument types *may* cause a compiler error. -/// -/// ## Pointers -/// -/// When the input is a pointer, only the pointer itself is -/// ever considered. The pointee has no effect. Currently, these functions -/// behave identically: -/// -/// ``` -/// #![feature(is_val_statically_known)] -/// #![feature(core_intrinsics)] -/// # #![allow(internal_features)] -/// use std::intrinsics::is_val_statically_known; -/// -/// fn foo(x: &i32) -> bool { -/// is_val_statically_known(x) -/// } -/// -/// fn bar(x: &i32) -> bool { -/// is_val_statically_known( -/// (x as *const i32).addr() -/// ) -/// } -/// # _ = foo(&5_i32); -/// # _ = bar(&5_i32); -/// ``` -#[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")] -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -pub const fn is_val_statically_known(_arg: T) -> bool { - false -} - -/// Non-overlapping *typed* swap of a single value. -/// -/// The codegen backends will replace this with a better implementation when -/// `T` is a simple type that can be loaded and stored as an immediate. -/// -/// The stabilized form of this intrinsic is [`crate::mem::swap`]. -/// -/// # Safety -/// -/// `x` and `y` are readable and writable as `T`, and non-overlapping. -#[rustc_nounwind] -#[inline] -#[rustc_intrinsic] -// This has fallback `const fn` MIR, so shouldn't need stability, see #122652 -#[rustc_const_unstable(feature = "const_typed_swap", issue = "none")] -pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { - // SAFETY: The caller provided single non-overlapping items behind - // pointers, so swapping them with `count: 1` is fine. - unsafe { ptr::swap_nonoverlapping(x, y, 1) }; -} - -/// Returns whether we should perform some UB-checking at runtime. This eventually evaluates to -/// `cfg!(ub_checks)`, but behaves different from `cfg!` when mixing crates built with different -/// flags: if the crate has UB checks enabled or carries the `#[rustc_preserve_ub_checks]` -/// attribute, evaluation is delayed until monomorphization (or until the call gets inlined into -/// a crate that does not delay evaluation further); otherwise it can happen any time. -/// -/// The common case here is a user program built with ub_checks linked against the distributed -/// sysroot which is built without ub_checks but with `#[rustc_preserve_ub_checks]`. -/// For code that gets monomorphized in the user crate (i.e., generic functions and functions with -/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(ub_checks)` means that -/// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the -/// user has UB checks disabled, the checks will still get optimized out. This intrinsic is -/// primarily used by [`ub_checks::assert_unsafe_precondition`]. -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // just for UB checks -#[unstable(feature = "core_intrinsics", issue = "none")] -#[inline(always)] -#[rustc_intrinsic] -pub const fn ub_checks() -> bool { - cfg!(ub_checks) -} - -/// Allocates a block of memory at compile time. -/// At runtime, just returns a null pointer. -/// -/// # Safety -/// -/// - The `align` argument must be a power of two. -/// - At compile time, a compile error occurs if this constraint is violated. -/// - At runtime, it is not checked. -#[rustc_const_unstable(feature = "const_heap", issue = "79597")] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_nounwind] -#[rustc_intrinsic] -#[miri::intrinsic_fallback_is_spec] -pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 { - // const eval overrides this function, but runtime code for now just returns null pointers. - // See . - crate::ptr::null_mut() -} - -/// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time. -/// At runtime, does nothing. -/// -/// # Safety -/// -/// - The `align` argument must be a power of two. -/// - At compile time, a compile error occurs if this constraint is violated. -/// - At runtime, it is not checked. -/// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it. -/// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it. -#[rustc_const_unstable(feature = "const_heap", issue = "79597")] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_nounwind] -#[rustc_intrinsic] -#[miri::intrinsic_fallback_is_spec] -pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) { - // Runtime NOP -} - -/// The intrinsic will return the size stored in that vtable. -/// -/// # Safety -/// -/// `ptr` must point to a vtable. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub unsafe fn vtable_size(_ptr: *const ()) -> usize { - unreachable!() -} - -/// The intrinsic will return the alignment stored in that vtable. -/// -/// # Safety -/// -/// `ptr` must point to a vtable. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub unsafe fn vtable_align(_ptr: *const ()) -> usize { - unreachable!() -} - -/// The size of a type in bytes. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// More specifically, this is the offset in bytes between successive -/// items of the same type, including alignment padding. -/// -/// The stabilized version of this intrinsic is [`core::mem::size_of`]. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn size_of() -> usize { - unreachable!() -} - -/// The minimum alignment of a type. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`core::mem::align_of`]. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn min_align_of() -> usize { - unreachable!() -} - -/// The preferred alignment of a type. -/// -/// This intrinsic does not have a stable counterpart. -/// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_pref_align_of", issue = "91971")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn pref_align_of() -> usize { - unreachable!() -} - -/// Returns the number of variants of the type `T` cast to a `usize`; -/// if `T` has no variants, returns `0`. Uninhabited variants will be counted. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "variant_count", issue = "73662")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn variant_count() -> usize { - unreachable!() -} - -/// The size of the referenced value in bytes. -/// -/// The stabilized version of this intrinsic is [`crate::mem::size_of_val`]. -/// -/// # Safety -/// -/// See [`crate::mem::size_of_val_raw`] for safety conditions. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn size_of_val(_ptr: *const T) -> usize { - unreachable!() -} - -/// The required alignment of the referenced value. -/// -/// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. -/// -/// # Safety -/// -/// See [`crate::mem::align_of_val_raw`] for safety conditions. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { - unreachable!() -} - -/// Gets a static string slice containing the name of a type. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`core::any::type_name`]. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_type_name", issue = "63084")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn type_name() -> &'static str { - unreachable!() -} - -/// Gets an identifier which is globally unique to the specified type. This -/// function will return the same value for a type regardless of whichever -/// crate it is invoked in. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn type_id() -> u128 { - unreachable!() -} - -/// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. -/// -/// This is used to implement functions like `slice::from_raw_parts_mut` and -/// `ptr::from_raw_parts` in a way compatible with the compiler being able to -/// change the possible layouts of pointers. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { - // To implement a fallback we'd have to assume the layout of the pointer, - // but the whole point of this intrinsic is that we shouldn't do that. - unreachable!() -} - -#[unstable(feature = "core_intrinsics", issue = "none")] -pub trait AggregateRawPtr { - type Metadata: Copy; -} -impl AggregateRawPtr<*const T> for *const P { - type Metadata =

::Metadata; -} -impl AggregateRawPtr<*mut T> for *mut P { - type Metadata =

::Metadata; -} - -/// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`. -/// -/// This is used to implement functions like `ptr::metadata`. -#[rustc_nounwind] -#[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr( - bootstrap, - cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")) -)] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { - // To implement a fallback we'd have to assume the layout of the pointer, - // but the whole point of this intrinsic is that we shouldn't do that. - unreachable!() -} - -// Some functions are defined here because they accidentally got made -// available in this module on stable. See . -// (`transmute` also falls into this category, but it cannot be wrapped due to the -// check that `T` and `U` have the same size.) - -/// Copies `count * size_of::()` bytes from `src` to `dst`. The source -/// and destination must *not* overlap. -/// -/// For regions of memory which might overlap, use [`copy`] instead. -/// -/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but -/// with the argument order swapped. -/// -/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the -/// requirements of `T`. The initialization state is preserved exactly. -/// -/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads of `count * size_of::()` bytes. -/// -/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. -/// -/// * Both `src` and `dst` must be properly aligned. -/// -/// * The region of memory beginning at `src` with a size of `count * -/// size_of::()` bytes must *not* overlap with the region of memory -/// beginning at `dst` with the same size. -/// -/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values -/// in the region beginning at `*src` and the region beginning at `*dst` can -/// [violate memory safety][read-ownership]. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointers must be properly aligned. -/// -/// [`read`]: crate::ptr::read -/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value -/// [valid]: crate::ptr#safety -/// -/// # Examples -/// -/// Manually implement [`Vec::append`]: -/// -/// ``` -/// use std::ptr; -/// -/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. -/// fn append(dst: &mut Vec, src: &mut Vec) { -/// let src_len = src.len(); -/// let dst_len = dst.len(); -/// -/// // Ensure that `dst` has enough capacity to hold all of `src`. -/// dst.reserve(src_len); -/// -/// unsafe { -/// // The call to add is always safe because `Vec` will never -/// // allocate more than `isize::MAX` bytes. -/// let dst_ptr = dst.as_mut_ptr().add(dst_len); -/// let src_ptr = src.as_ptr(); -/// -/// // Truncate `src` without dropping its contents. We do this first, -/// // to avoid problems in case something further down panics. -/// src.set_len(0); -/// -/// // The two regions cannot overlap because mutable references do -/// // not alias, and two different vectors cannot own the same -/// // memory. -/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); -/// -/// // Notify `dst` that it now holds the contents of `src`. -/// dst.set_len(dst_len + src_len); -/// } -/// } -/// -/// let mut a = vec!['r']; -/// let mut b = vec!['u', 's', 't']; -/// -/// append(&mut a, &mut b); -/// -/// assert_eq!(a, &['r', 'u', 's', 't']); -/// assert!(b.is_empty()); -/// ``` -/// -/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append -#[doc(alias = "memcpy")] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] -#[inline(always)] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] -pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") - )] - #[cfg_attr( - not(bootstrap), - rustc_const_unstable(feature = "core_intrinsics", issue = "none") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - } - - ub_checks::assert_unsafe_precondition!( - check_language_ub, - "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \ - and the specified memory ranges do not overlap", - ( - src: *const () = src as *const (), - dst: *mut () = dst as *mut (), - size: usize = size_of::(), - align: usize = align_of::(), - count: usize = count, - ) => { - let zero_size = count == 0 || size == 0; - ub_checks::is_aligned_and_not_null(src, align, zero_size) - && ub_checks::is_aligned_and_not_null(dst, align, zero_size) - && ub_checks::is_nonoverlapping(src, dst, size, count) - } - ); - - // SAFETY: the safety contract for `copy_nonoverlapping` must be - // upheld by the caller. - unsafe { copy_nonoverlapping(src, dst, count) } -} - -/// Copies `count * size_of::()` bytes from `src` to `dst`. The source -/// and destination may overlap. -/// -/// If the source and destination will *never* overlap, -/// [`copy_nonoverlapping`] can be used instead. -/// -/// `copy` is semantically equivalent to C's [`memmove`], but with the argument -/// order swapped. Copying takes place as if the bytes were copied from `src` -/// to a temporary array and then copied from the array to `dst`. -/// -/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the -/// requirements of `T`. The initialization state is preserved exactly. -/// -/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads of `count * size_of::()` bytes, and must remain valid even -/// when `dst` is written for `count * size_of::()` bytes. (This means if the memory ranges -/// overlap, the two pointers must not be subject to aliasing restrictions relative to each -/// other.) -/// -/// * `dst` must be [valid] for writes of `count * size_of::()` bytes, and must remain valid even -/// when `src` is read for `count * size_of::()` bytes. -/// -/// * Both `src` and `dst` must be properly aligned. -/// -/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values -/// in the region beginning at `*src` and the region beginning at `*dst` can -/// [violate memory safety][read-ownership]. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointers must be properly aligned. -/// -/// [`read`]: crate::ptr::read -/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value -/// [valid]: crate::ptr#safety -/// -/// # Examples -/// -/// Efficiently create a Rust vector from an unsafe buffer: -/// -/// ``` -/// use std::ptr; -/// -/// /// # Safety -/// /// -/// /// * `ptr` must be correctly aligned for its type and non-zero. -/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. -/// /// * Those elements must not be used after calling this function unless `T: Copy`. -/// # #[allow(dead_code)] -/// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { -/// let mut dst = Vec::with_capacity(elts); -/// -/// // SAFETY: Our precondition ensures the source is aligned and valid, -/// // and `Vec::with_capacity` ensures that we have usable space to write them. -/// ptr::copy(ptr, dst.as_mut_ptr(), elts); -/// -/// // SAFETY: We created it with this much capacity earlier, -/// // and the previous `copy` has initialized these elements. -/// dst.set_len(elts); -/// dst -/// } -/// ``` -#[doc(alias = "memmove")] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] -#[inline(always)] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -#[rustc_diagnostic_item = "ptr_copy"] -pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") - )] - #[cfg_attr( - not(bootstrap), - rustc_const_unstable(feature = "core_intrinsics", issue = "none") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - fn copy(src: *const T, dst: *mut T, count: usize); - } - - // SAFETY: the safety contract for `copy` must be upheld by the caller. - unsafe { - ub_checks::assert_unsafe_precondition!( - check_language_ub, - "ptr::copy requires that both pointer arguments are aligned and non-null", - ( - src: *const () = src as *const (), - dst: *mut () = dst as *mut (), - align: usize = align_of::(), - zero_size: bool = T::IS_ZST || count == 0, - ) => - ub_checks::is_aligned_and_not_null(src, align, zero_size) - && ub_checks::is_aligned_and_not_null(dst, align, zero_size) - ); - copy(src, dst, count) - } -} - -/// Sets `count * size_of::()` bytes of memory starting at `dst` to -/// `val`. -/// -/// `write_bytes` is similar to C's [`memset`], but sets `count * -/// size_of::()` bytes to `val`. -/// -/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. -/// -/// * `dst` must be properly aligned. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointer must be properly aligned. -/// -/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB) -/// later if the written bytes are not a valid representation of some `T`. For instance, the -/// following is an **incorrect** use of this function: -/// -/// ```rust,no_run -/// unsafe { -/// let mut value: u8 = 0; -/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool; -/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`. -/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB... -/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️ -/// } -/// ``` -/// -/// [valid]: crate::ptr#safety -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::ptr; -/// -/// let mut vec = vec![0u32; 4]; -/// unsafe { -/// let vec_ptr = vec.as_mut_ptr(); -/// ptr::write_bytes(vec_ptr, 0xfe, 2); -/// } -/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); -/// ``` -#[doc(alias = "memset")] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules] -#[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 -#[rustc_diagnostic_item = "ptr_write_bytes"] -pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - fn write_bytes(dst: *mut T, val: u8, count: usize); - } - - // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. - unsafe { - ub_checks::assert_unsafe_precondition!( - check_language_ub, - "ptr::write_bytes requires that the destination pointer is aligned and non-null", - ( - addr: *const () = dst as *const (), - align: usize = align_of::(), - zero_size: bool = T::IS_ZST || count == 0, - ) => ub_checks::is_aligned_and_not_null(addr, align, zero_size) - ); - write_bytes(dst, val, count) - } -} - -/// Returns the minimum of two `f16` values. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is -/// [`f16::min`] -#[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn minnumf16(_x: f16, _y: f16) -> f16 { - unimplemented!(); -} - -/// Returns the minimum of two `f32` values. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is -/// [`f32::min`] -#[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn minnumf32(_x: f32, _y: f32) -> f32 { - unimplemented!(); -} - -/// Returns the minimum of two `f64` values. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is -/// [`f64::min`] -#[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn minnumf64(_x: f64, _y: f64) -> f64 { - unimplemented!(); -} - -/// Returns the minimum of two `f128` values. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is -/// [`f128::min`] -#[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn minnumf128(_x: f128, _y: f128) -> f128 { - unimplemented!(); -} - -/// Returns the maximum of two `f16` values. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is -/// [`f16::max`] -#[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { - unimplemented!(); -} - -/// Returns the maximum of two `f32` values. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is -/// [`f32::max`] -#[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { - unimplemented!(); -} - -/// Returns the maximum of two `f64` values. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is -/// [`f64::max`] -#[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { - unimplemented!(); -} - -/// Returns the maximum of two `f128` values. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is -/// [`f128::max`] -#[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { - unimplemented!(); -} - -/// Returns the absolute value of an `f16`. -/// -/// The stabilized version of this intrinsic is -/// [`f16::abs`](../../std/primitive.f16.html#method.abs) -#[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn fabsf16(_x: f16) -> f16 { - unimplemented!(); -} - -/// Returns the absolute value of an `f32`. -/// -/// The stabilized version of this intrinsic is -/// [`f32::abs`](../../std/primitive.f32.html#method.abs) -#[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn fabsf32(_x: f32) -> f32 { - unimplemented!(); -} - -/// Returns the absolute value of an `f64`. -/// -/// The stabilized version of this intrinsic is -/// [`f64::abs`](../../std/primitive.f64.html#method.abs) -#[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn fabsf64(_x: f64) -> f64 { - unimplemented!(); -} - -/// Returns the absolute value of an `f128`. -/// -/// The stabilized version of this intrinsic is -/// [`f128::abs`](../../std/primitive.f128.html#method.abs) -#[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn fabsf128(_x: f128) -> f128 { - unimplemented!(); -} - -/// Copies the sign from `y` to `x` for `f16` values. -/// -/// The stabilized version of this intrinsic is -/// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) -#[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { - unimplemented!(); -} - -/// Copies the sign from `y` to `x` for `f32` values. -/// -/// The stabilized version of this intrinsic is -/// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) -#[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { - unimplemented!(); -} -/// Copies the sign from `y` to `x` for `f64` values. -/// -/// The stabilized version of this intrinsic is -/// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) -#[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { - unimplemented!(); -} - -/// Copies the sign from `y` to `x` for `f128` values. -/// -/// The stabilized version of this intrinsic is -/// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) -#[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { - unimplemented!(); -} - -/// Inform Miri that a given pointer definitely has a certain alignment. -#[cfg(miri)] -#[rustc_allow_const_fn_unstable(const_eval_select)] -pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) { - extern "Rust" { - /// Miri-provided extern function to promise that a given pointer is properly aligned for - /// "symbolic" alignment checks. Will fail if the pointer is not actually aligned or `align` is - /// not a power of two. Has no effect when alignment checks are concrete (which is the default). - fn miri_promise_symbolic_alignment(ptr: *const (), align: usize); - } - - fn runtime(ptr: *const (), align: usize) { - // SAFETY: this call is always safe. - unsafe { - miri_promise_symbolic_alignment(ptr, align); - } - } - - const fn compiletime(_ptr: *const (), _align: usize) {} - - const_eval_select((ptr, align), compiletime, runtime); -} diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs new file mode 100644 index 0000000000000..2f75bfae988f2 --- /dev/null +++ b/core/src/intrinsics/mod.rs @@ -0,0 +1,4528 @@ +//! Compiler intrinsics. +//! +//! The corresponding definitions are in . +//! The corresponding const implementations are in . +//! +//! # Const intrinsics +//! +//! Note: any changes to the constness of intrinsics should be discussed with the language team. +//! This includes changes in the stability of the constness. +//! +//! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new" +//! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the +//! implementation from to +//! +//! and make the intrinsic declaration a `const fn`. +//! +//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, +//! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires +//! T-lang approval, because it may bake a feature into the language that cannot be replicated in +//! user code without compiler support. +//! +//! # Volatiles +//! +//! 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 +//! +//! # 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`. +//! +//! # Unwinding +//! +//! Rust intrinsics may, in general, unwind. If an intrinsic can never unwind, add the +//! `#[rustc_nounwind]` attribute so that the compiler can make use of this fact. +//! +//! However, even for intrinsics that may unwind, rustc assumes that a Rust intrinsics will never +//! initiate a foreign (non-Rust) unwind, and thus for panic=abort we can always assume that these +//! intrinsics cannot unwind. + +#![unstable( + feature = "core_intrinsics", + reason = "intrinsics are unlikely to ever be stabilized, instead \ + they should be used through stabilized interfaces \ + in the rest of the standard library", + issue = "none" +)] +#![allow(missing_docs)] + +use crate::marker::{DiscriminantKind, Tuple}; +use crate::mem::SizedTypeProperties; +use crate::{ptr, ub_checks}; + +pub mod mir; +pub mod simd; + +// These imports are used for simplifying intra-doc links +#[allow(unused_imports)] +#[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))] +use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; + +#[stable(feature = "drop_in_place", since = "1.8.0")] +#[rustc_allowed_through_unstable_modules] +#[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] +#[inline] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // SAFETY: see `ptr::drop_in_place` + unsafe { crate::ptr::drop_in_place(to_drop) } +} + +// N.B., these intrinsics take raw pointers because they mutate aliased +// memory, which is not valid for either `&` or `&mut`. + +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Relaxed`] as both the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_relaxed_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_relaxed_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_relaxed_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_acquire_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Acquire`] as both the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_acquire_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_acquire_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_release_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_release_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_release_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_acqrel_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_acqrel_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_acqrel_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_seqcst_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_seqcst_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange` method by passing +/// [`Ordering::SeqCst`] as both the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchg_seqcst_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} + +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Relaxed`] as both the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_relaxed_relaxed( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_relaxed_acquire( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_relaxed_seqcst( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_acquire_relaxed( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Acquire`] as both the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_acquire_acquire( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_acquire_seqcst( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_release_relaxed( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_release_acquire( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_release_seqcst( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_acqrel_relaxed( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_acqrel_acquire( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_acqrel_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_seqcst_relaxed( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_seqcst_acquire( + _dst: *mut T, + _old: T, + _src: T, +) -> (T, bool) { + unreachable!() +} +/// Stores a value if the current value is the same as the `old` value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `compare_exchange_weak` method by passing +/// [`Ordering::SeqCst`] as both the success and failure parameters. +/// For example, [`AtomicBool::compare_exchange_weak`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_cxchgweak_seqcst_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { + unreachable!() +} + +/// Loads the current value of the pointer. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `load` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::load`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_load_seqcst(_src: *const T) -> T { + unreachable!() +} +/// Loads the current value of the pointer. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `load` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::load`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_load_acquire(_src: *const T) -> T { + unreachable!() +} +/// Loads the current value of the pointer. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `load` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::load`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_load_relaxed(_src: *const T) -> T { + unreachable!() +} +/// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model! +/// In terms of the Rust Abstract Machine, this operation is equivalent to `src.read()`, +/// i.e., it performs a non-atomic read. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_load_unordered(_src: *const T) -> T { + unreachable!() +} + +/// Stores the value at the specified memory location. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `store` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::store`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_store_seqcst(_dst: *mut T, _val: T) { + unreachable!() +} +/// Stores the value at the specified memory location. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `store` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::store`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_store_release(_dst: *mut T, _val: T) { + unreachable!() +} +/// Stores the value at the specified memory location. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `store` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::store`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_store_relaxed(_dst: *mut T, _val: T) { + unreachable!() +} +/// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model! +/// In terms of the Rust Abstract Machine, this operation is equivalent to `dst.write(val)`, +/// i.e., it performs a non-atomic write. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_store_unordered(_dst: *mut T, _val: T) { + unreachable!() +} + +/// Stores the value at the specified memory location, returning the old value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `swap` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::swap`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xchg_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Stores the value at the specified memory location, returning the old value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `swap` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::swap`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xchg_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Stores the value at the specified memory location, returning the old value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `swap` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::swap`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xchg_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Stores the value at the specified memory location, returning the old value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `swap` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::swap`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xchg_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Stores the value at the specified memory location, returning the old value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `swap` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::swap`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xchg_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Adds to the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_add` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_add`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xadd_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Adds to the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_add` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_add`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xadd_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Adds to the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_add` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_add`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xadd_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Adds to the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_add` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_add`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xadd_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Adds to the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_add` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_add`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xadd_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Subtract from the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_sub` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xsub_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Subtract from the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_sub` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xsub_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Subtract from the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_sub` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xsub_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Subtract from the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_sub` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xsub_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Subtract from the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_sub` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xsub_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Bitwise and with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_and` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_and`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_and_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise and with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_and` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_and`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_and_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise and with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_and` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_and`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_and_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise and with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_and` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_and`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_and_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise and with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_and` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_and`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_and_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Bitwise nand with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`AtomicBool`] type via the `fetch_nand` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_nand`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_nand_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise nand with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`AtomicBool`] type via the `fetch_nand` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_nand`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_nand_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise nand with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`AtomicBool`] type via the `fetch_nand` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_nand`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_nand_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise nand with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`AtomicBool`] type via the `fetch_nand` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_nand`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_nand_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise nand with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`AtomicBool`] type via the `fetch_nand` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_nand`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_nand_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Bitwise or with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_or` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_or`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_or_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise or with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_or` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_or`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_or_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise or with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_or` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_or`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_or_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise or with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_or` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_or`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_or_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise or with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_or` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_or`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_or_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Bitwise xor with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_xor` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_xor`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xor_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise xor with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_xor` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_xor`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xor_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise xor with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_xor` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_xor`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xor_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise xor with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_xor` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_xor`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xor_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Bitwise xor with the current value, returning the previous value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] types via the `fetch_xor` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_xor`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_xor_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Maximum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_max` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_max_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Maximum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_max` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_max_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Maximum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_max` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_max_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Maximum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_max` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_max_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Maximum with the current value. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_max` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_max_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Minimum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_min` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_min_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Minimum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_min` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_min_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Minimum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_min` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_min_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Minimum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_min` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_min_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Minimum with the current value using a signed comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] signed integer types via the `fetch_min` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_min_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Minimum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_min` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umin_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Minimum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_min` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umin_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Minimum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_min` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umin_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Minimum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_min` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umin_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Minimum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_min` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_min`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umin_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// Maximum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_max` method by passing +/// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umax_seqcst(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Maximum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_max` method by passing +/// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umax_acquire(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Maximum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_max` method by passing +/// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umax_release(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Maximum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_max` method by passing +/// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umax_acqrel(_dst: *mut T, _src: T) -> T { + unreachable!() +} +/// Maximum with the current value using an unsigned comparison. +/// +/// The stabilized version of this intrinsic is available on the +/// [`atomic`] unsigned integer types via the `fetch_max` method by passing +/// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_max`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_umax_relaxed(_dst: *mut T, _src: T) -> T { + unreachable!() +} + +/// An atomic fence. +/// +/// The stabilized version of this intrinsic is available in +/// [`atomic::fence`] by passing [`Ordering::SeqCst`] +/// as the `order`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_fence_seqcst() { + unreachable!() +} +/// An atomic fence. +/// +/// The stabilized version of this intrinsic is available in +/// [`atomic::fence`] by passing [`Ordering::Acquire`] +/// as the `order`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_fence_acquire() { + unreachable!() +} +/// An atomic fence. +/// +/// The stabilized version of this intrinsic is available in +/// [`atomic::fence`] by passing [`Ordering::Release`] +/// as the `order`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_fence_release() { + unreachable!() +} +/// An atomic fence. +/// +/// The stabilized version of this intrinsic is available in +/// [`atomic::fence`] by passing [`Ordering::AcqRel`] +/// as the `order`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_fence_acqrel() { + unreachable!() +} + +/// A compiler-only memory barrier. +/// +/// Memory accesses will never be reordered across this barrier by the +/// compiler, but no instructions will be emitted for it. This is +/// appropriate for operations on the same thread that may be preempted, +/// such as when interacting with signal handlers. +/// +/// The stabilized version of this intrinsic is available in +/// [`atomic::compiler_fence`] by passing [`Ordering::SeqCst`] +/// as the `order`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_singlethreadfence_seqcst() { + unreachable!() +} +/// A compiler-only memory barrier. +/// +/// Memory accesses will never be reordered across this barrier by the +/// compiler, but no instructions will be emitted for it. This is +/// appropriate for operations on the same thread that may be preempted, +/// such as when interacting with signal handlers. +/// +/// The stabilized version of this intrinsic is available in +/// [`atomic::compiler_fence`] by passing [`Ordering::Acquire`] +/// as the `order`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_singlethreadfence_acquire() { + unreachable!() +} +/// A compiler-only memory barrier. +/// +/// Memory accesses will never be reordered across this barrier by the +/// compiler, but no instructions will be emitted for it. This is +/// appropriate for operations on the same thread that may be preempted, +/// such as when interacting with signal handlers. +/// +/// The stabilized version of this intrinsic is available in +/// [`atomic::compiler_fence`] by passing [`Ordering::Release`] +/// as the `order`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_singlethreadfence_release() { + unreachable!() +} +/// A compiler-only memory barrier. +/// +/// Memory accesses will never be reordered across this barrier by the +/// compiler, but no instructions will be emitted for it. This is +/// appropriate for operations on the same thread that may be preempted, +/// such as when interacting with signal handlers. +/// +/// The stabilized version of this intrinsic is available in +/// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] +/// as the `order`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn atomic_singlethreadfence_acqrel() { + unreachable!() +} + +/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction +/// if supported; otherwise, it is a no-op. +/// Prefetches have no effect on the behavior of the program but can change its performance +/// characteristics. +/// +/// The `locality` argument must be a constant integer and is a temporal locality specifier +/// ranging from (0) - no locality, to (3) - extremely local keep in cache. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn prefetch_read_data(_data: *const T, _locality: i32) { + unreachable!() +} +/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction +/// if supported; otherwise, it is a no-op. +/// Prefetches have no effect on the behavior of the program but can change its performance +/// characteristics. +/// +/// The `locality` argument must be a constant integer and is a temporal locality specifier +/// ranging from (0) - no locality, to (3) - extremely local keep in cache. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn prefetch_write_data(_data: *const T, _locality: i32) { + unreachable!() +} +/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction +/// if supported; otherwise, it is a no-op. +/// Prefetches have no effect on the behavior of the program but can change its performance +/// characteristics. +/// +/// The `locality` argument must be a constant integer and is a temporal locality specifier +/// ranging from (0) - no locality, to (3) - extremely local keep in cache. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn prefetch_read_instruction(_data: *const T, _locality: i32) { + unreachable!() +} +/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction +/// if supported; otherwise, it is a no-op. +/// Prefetches have no effect on the behavior of the program but can change its performance +/// characteristics. +/// +/// The `locality` argument must be a constant integer and is a temporal locality specifier +/// ranging from (0) - no locality, to (3) - extremely local keep in cache. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn prefetch_write_instruction(_data: *const T, _locality: i32) { + unreachable!() +} + +/// Executes a breakpoint trap, for inspection by a debugger. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn breakpoint() { + unreachable!() +} + +/// Magic intrinsic that derives its meaning from attributes +/// attached to the function. +/// +/// For example, dataflow uses this to inject static assertions so +/// that `rustc_peek(potentially_uninitialized)` would actually +/// double-check that dataflow did indeed compute that it is +/// uninitialized at that point in the control flow. +/// +/// This intrinsic should not be used outside of the compiler. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn rustc_peek(_: T) -> T { + unreachable!() +} + +/// Aborts the execution of the process. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// [`std::process::abort`](../../std/process/fn.abort.html) is to be preferred if possible, +/// as its behavior is more user-friendly and more stable. +/// +/// The current implementation of `intrinsics::abort` is to invoke an invalid instruction, +/// on most platforms. +/// On Unix, the +/// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or +/// `SIGBUS`. The precise behavior is not guaranteed and not stable. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn abort() -> ! { + unreachable!() +} + +/// Informs the optimizer that this point in the code is not reachable, +/// enabling further optimizations. +/// +/// N.B., this is very different from the `unreachable!()` macro: Unlike the +/// macro, which panics when it is executed, it is *undefined behavior* to +/// reach code marked with this function. +/// +/// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unreachable() -> ! { + unreachable!() +} + +/// Informs the optimizer that a condition is always true. +/// If the condition is false, the behavior is undefined. +/// +/// No code is generated for this intrinsic, but the optimizer will try +/// to preserve it (and its condition) between passes, which may interfere +/// with optimization of surrounding code and reduce performance. It should +/// not be used if the invariant can be discovered by the optimizer on its +/// own, or if it does not enable any significant optimizations. +/// +/// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +pub const unsafe fn assume(b: bool) { + if !b { + // SAFETY: the caller must guarantee the argument is never `false` + unsafe { unreachable() } + } +} + +/// Hints to the compiler that current code path is cold. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// This intrinsic does not have a stable counterpart. +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[cfg(not(bootstrap))] +#[rustc_nounwind] +#[miri::intrinsic_fallback_is_spec] +#[cold] +pub const fn cold_path() {} + +/// Hints to the compiler that branch condition is likely to be true. +/// Returns the value passed to it. +/// +/// Any use other than with `if` statements will probably not have an effect. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") +)] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_nounwind] +#[inline(always)] +pub const fn likely(b: bool) -> bool { + #[cfg(bootstrap)] + { + b + } + #[cfg(not(bootstrap))] + if b { + true + } else { + cold_path(); + false + } +} + +/// Hints to the compiler that branch condition is likely to be false. +/// Returns the value passed to it. +/// +/// Any use other than with `if` statements will probably not have an effect. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") +)] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_nounwind] +#[inline(always)] +pub const fn unlikely(b: bool) -> bool { + #[cfg(bootstrap)] + { + b + } + #[cfg(not(bootstrap))] + if b { + cold_path(); + true + } else { + false + } +} + +/// Returns either `true_val` or `false_val` depending on condition `b` with a +/// hint to the compiler that this condition is unlikely to be correctly +/// predicted by a CPU's branch predictor (e.g. a binary search). +/// +/// This is otherwise functionally equivalent to `if b { true_val } else { false_val }`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// This intrinsic does not have a stable counterpart. +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_nounwind] +#[miri::intrinsic_fallback_is_spec] +#[inline] +pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { + if b { true_val } else { false_val } +} + +/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: +/// This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_inhabited() { + unreachable!() +} + +/// A guard for unsafe functions that cannot ever be executed if `T` does not permit +/// zero-initialization: This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_zero_valid() { + unreachable!() +} + +/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_mem_uninitialized_valid() { + unreachable!() +} + +/// Gets a reference to a static `Location` indicating where it was called. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// Consider using [`core::panic::Location::caller`] instead. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn caller_location() -> &'static crate::panic::Location<'static> { + unreachable!() +} + +/// Moves a value out of scope without running drop glue. +/// +/// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses +/// `ManuallyDrop` instead. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn forget(_: T) { + unreachable!() +} + +/// Reinterprets the bits of a value of one type as another type. +/// +/// Both types must have the same size. Compilation will fail if this is not guaranteed. +/// +/// `transmute` is semantically equivalent to a bitwise move of one type +/// into another. It copies the bits from the source value into the +/// destination value, then forgets the original. Note that source and destination +/// are passed by-value, which means if `Src` or `Dst` contain padding, that padding +/// is *not* guaranteed to be preserved by `transmute`. +/// +/// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at +/// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler +/// will generate code *assuming that you, the programmer, ensure that there will never be +/// undefined behavior*. It is therefore your responsibility to guarantee that every value +/// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition +/// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly +/// unsafe**. `transmute` should be the absolute last resort. +/// +/// Because `transmute` is a by-value operation, alignment of the *transmuted values +/// themselves* is not a concern. As with any other function, the compiler already ensures +/// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point +/// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper +/// alignment of the pointed-to values. +/// +/// The [nomicon](../../nomicon/transmutes.html) has additional documentation. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// +/// # Transmutation between pointers and integers +/// +/// Special care has to be taken when transmuting between pointers and integers, e.g. +/// transmuting between `*const ()` and `usize`. +/// +/// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless +/// the pointer was originally created *from* an integer. (That includes this function +/// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling], +/// but also semantically-equivalent conversions such as punning through `repr(C)` union +/// fields.) Any attempt to use the resulting value for integer operations will abort +/// const-evaluation. (And even outside `const`, such transmutation is touching on many +/// unspecified aspects of the Rust memory model and should be avoided. See below for +/// alternatives.) +/// +/// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not* +/// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed +/// this way is currently considered undefined behavior. +/// +/// All this also applies when the integer is nested inside an array, tuple, struct, or enum. +/// However, `MaybeUninit` is not considered an integer type for the purpose of this +/// section. Transmuting `*const ()` to `MaybeUninit` is fine---but then calling +/// `assume_init()` on that result is considered as completing the pointer-to-integer transmute +/// and thus runs into the issues discussed above. +/// +/// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a +/// lossless process. If you want to round-trip a pointer through an integer in a way that you +/// can get back the original pointer, you need to use `as` casts, or replace the integer type +/// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to +/// store data of arbitrary type, also use `MaybeUninit` (that will also handle uninitialized +/// memory due to padding). If you specifically need to store something that is "either an +/// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without +/// any loss (via `as` casts or via `transmute`). +/// +/// # Examples +/// +/// There are a few things that `transmute` is really useful for. +/// +/// Turning a pointer into a function pointer. This is *not* portable to +/// machines where function pointers and data pointers have different sizes. +/// +/// ``` +/// fn foo() -> i32 { +/// 0 +/// } +/// // Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer. +/// // This avoids an integer-to-pointer `transmute`, which can be problematic. +/// // Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine. +/// let pointer = foo as *const (); +/// let function = unsafe { +/// std::mem::transmute::<*const (), fn() -> i32>(pointer) +/// }; +/// assert_eq!(function(), 0); +/// ``` +/// +/// Extending a lifetime, or shortening an invariant lifetime. This is +/// advanced, very unsafe Rust! +/// +/// ``` +/// struct R<'a>(&'a i32); +/// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { +/// std::mem::transmute::, R<'static>>(r) +/// } +/// +/// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) +/// -> &'b mut R<'c> { +/// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) +/// } +/// ``` +/// +/// # Alternatives +/// +/// Don't despair: many uses of `transmute` can be achieved through other means. +/// Below are common applications of `transmute` which can be replaced with safer +/// constructs. +/// +/// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.: +/// +/// ``` +/// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; +/// +/// let num = unsafe { +/// std::mem::transmute::<[u8; 4], u32>(raw_bytes) +/// }; +/// +/// // use `u32::from_ne_bytes` instead +/// let num = u32::from_ne_bytes(raw_bytes); +/// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness +/// let num = u32::from_le_bytes(raw_bytes); +/// assert_eq!(num, 0x12345678); +/// let num = u32::from_be_bytes(raw_bytes); +/// assert_eq!(num, 0x78563412); +/// ``` +/// +/// Turning a pointer into a `usize`: +/// +/// ```no_run +/// let ptr = &0; +/// let ptr_num_transmute = unsafe { +/// std::mem::transmute::<&i32, usize>(ptr) +/// }; +/// +/// // Use an `as` cast instead +/// let ptr_num_cast = ptr as *const i32 as usize; +/// ``` +/// +/// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined +/// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave +/// as expected -- this is touching on many unspecified aspects of the Rust memory model. +/// Depending on what the code is doing, the following alternatives are preferable to +/// pointer-to-integer transmutation: +/// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a +/// type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit]. +/// - If the code actually wants to work on the address the pointer points to, it can use `as` +/// casts or [`ptr.addr()`][pointer::addr]. +/// +/// Turning a `*mut T` into a `&mut T`: +/// +/// ``` +/// let ptr: *mut i32 = &mut 0; +/// let ref_transmuted = unsafe { +/// std::mem::transmute::<*mut i32, &mut i32>(ptr) +/// }; +/// +/// // Use a reborrow instead +/// let ref_casted = unsafe { &mut *ptr }; +/// ``` +/// +/// Turning a `&mut T` into a `&mut U`: +/// +/// ``` +/// let ptr = &mut 0; +/// let val_transmuted = unsafe { +/// std::mem::transmute::<&mut i32, &mut u32>(ptr) +/// }; +/// +/// // Now, put together `as` and reborrowing - note the chaining of `as` +/// // `as` is not transitive +/// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; +/// ``` +/// +/// Turning a `&str` into a `&[u8]`: +/// +/// ``` +/// // this is not a good way to do this. +/// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; +/// assert_eq!(slice, &[82, 117, 115, 116]); +/// +/// // You could use `str::as_bytes` +/// let slice = "Rust".as_bytes(); +/// assert_eq!(slice, &[82, 117, 115, 116]); +/// +/// // Or, just use a byte string, if you have control over the string +/// // literal +/// assert_eq!(b"Rust", &[82, 117, 115, 116]); +/// ``` +/// +/// Turning a `Vec<&T>` into a `Vec>`. +/// +/// To transmute the inner type of the contents of a container, you must make sure to not +/// violate any of the container's invariants. For `Vec`, this means that both the size +/// *and alignment* of the inner types have to match. Other containers might rely on the +/// size of the type, alignment, or even the `TypeId`, in which case transmuting wouldn't +/// be possible at all without violating the container invariants. +/// +/// ``` +/// let store = [0, 1, 2, 3]; +/// let v_orig = store.iter().collect::>(); +/// +/// // clone the vector as we will reuse them later +/// let v_clone = v_orig.clone(); +/// +/// // Using transmute: this relies on the unspecified data layout of `Vec`, which is a +/// // bad idea and could cause Undefined Behavior. +/// // However, it is no-copy. +/// let v_transmuted = unsafe { +/// std::mem::transmute::, Vec>>(v_clone) +/// }; +/// +/// let v_clone = v_orig.clone(); +/// +/// // This is the suggested, safe way. +/// // It may copy the entire vector into a new one though, but also may not. +/// let v_collected = v_clone.into_iter() +/// .map(Some) +/// .collect::>>(); +/// +/// let v_clone = v_orig.clone(); +/// +/// // This is the proper no-copy, unsafe way of "transmuting" a `Vec`, without relying on the +/// // data layout. Instead of literally calling `transmute`, we perform a pointer cast, but +/// // in terms of converting the original inner type (`&i32`) to the new one (`Option<&i32>`), +/// // this has all the same caveats. Besides the information provided above, also consult the +/// // [`from_raw_parts`] documentation. +/// let v_from_raw = unsafe { +// FIXME Update this when vec_into_raw_parts is stabilized +/// // Ensure the original vector is not dropped. +/// let mut v_clone = std::mem::ManuallyDrop::new(v_clone); +/// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>, +/// v_clone.len(), +/// v_clone.capacity()) +/// }; +/// ``` +/// +/// [`from_raw_parts`]: ../../std/vec/struct.Vec.html#method.from_raw_parts +/// +/// Implementing `split_at_mut`: +/// +/// ``` +/// use std::{slice, mem}; +/// +/// // There are multiple ways to do this, and there are multiple problems +/// // with the following (transmute) way. +/// fn split_at_mut_transmute(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); +/// // first: transmute is not type safe; all it checks is that T and +/// // U are of the same size. Second, right here, you have two +/// // mutable references pointing to the same memory. +/// (&mut slice[0..mid], &mut slice2[mid..len]) +/// } +/// } +/// +/// // This gets rid of the type safety problems; `&mut *` will *only* give +/// // you a `&mut T` from a `&mut T` or `*mut T`. +/// fn split_at_mut_casts(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let slice2 = &mut *(slice as *mut [T]); +/// // however, you still have two mutable references pointing to +/// // the same memory. +/// (&mut slice[0..mid], &mut slice2[mid..len]) +/// } +/// } +/// +/// // This is how the standard library does it. This is the best method, if +/// // you need to do something like this +/// fn split_at_stdlib(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let ptr = slice.as_mut_ptr(); +/// // This now has three mutable references pointing at the same +/// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. +/// // `slice` is never used after `let ptr = ...`, and so one can +/// // treat it as "dead", and therefore, you only have two real +/// // mutable slices. +/// (slice::from_raw_parts_mut(ptr, mid), +/// slice::from_raw_parts_mut(ptr.add(mid), len - mid)) +/// } +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allowed_through_unstable_modules] +#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] +#[rustc_diagnostic_item = "transmute"] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn transmute(_src: Src) -> Dst { + unreachable!() +} + +/// Like [`transmute`], but even less checked at compile-time: rather than +/// giving an error for `size_of::() != size_of::()`, it's +/// **Undefined Behavior** at runtime. +/// +/// Prefer normal `transmute` where possible, for the extra checking, since +/// both do exactly the same thing at runtime, if they both compile. +/// +/// This is not expected to ever be exposed directly to users, rather it +/// may eventually be exposed through some more-constrained API. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { + unreachable!() +} + +/// Returns `true` if the actual type given as `T` requires drop +/// glue; returns `false` if the actual type provided for `T` +/// implements `Copy`. +/// +/// If the actual type neither requires drop glue nor implements +/// `Copy`, then the return value of this function is unspecified. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn needs_drop() -> bool { + unreachable!() +} + +/// Calculates the offset from a pointer. +/// +/// This is implemented as an intrinsic to avoid converting to and from an +/// integer, since the conversion would throw away aliasing information. +/// +/// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`) +/// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other +/// instantiations may arbitrarily misbehave, and that's *not* a compiler bug. +/// +/// # Safety +/// +/// If the computed offset is non-zero, then both the starting and resulting pointer must be +/// either in bounds or at the end of an allocated object. If either pointer is out +/// of bounds or arithmetic overflow occurs then this operation is undefined behavior. +/// +/// The stabilized version of this intrinsic is [`pointer::offset`]. +#[must_use = "returns a new pointer rather than modifying its argument"] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { + unreachable!() +} + +/// Calculates the offset from a pointer, potentially wrapping. +/// +/// This is implemented as an intrinsic to avoid converting to and from an +/// integer, since the conversion inhibits certain optimizations. +/// +/// # Safety +/// +/// Unlike the `offset` intrinsic, this intrinsic does not restrict the +/// resulting pointer to point into or at the end of an allocated +/// object, and it wraps with two's complement arithmetic. The resulting +/// value is not necessarily valid to be used to actually access memory. +/// +/// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. +#[must_use = "returns a new pointer rather than modifying its argument"] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn arith_offset(_dst: *const T, _offset: isize) -> *const T { + unreachable!() +} + +/// Masks out bits of the pointer according to a mask. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// Consider using [`pointer::mask`] instead. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn ptr_mask(_ptr: *const T, _mask: usize) -> *const T { + unreachable!() +} + +extern "rust-intrinsic" { + /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with + /// a size of `count` * `size_of::()` and an alignment of + /// `min_align_of::()` + /// + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: usize); + /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with + /// a size of `count * size_of::()` and an alignment of + /// `min_align_of::()` + /// + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); + /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a + /// size of `count * size_of::()` and an alignment of + /// `min_align_of::()`. + /// + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); + + /// Performs a volatile load from the `src` pointer. + /// + /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`]. + #[rustc_nounwind] + pub fn volatile_load(src: *const T) -> T; + /// Performs a volatile store to the `dst` pointer. + /// + /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`]. + #[rustc_nounwind] + pub fn volatile_store(dst: *mut T, val: T); + + /// Performs a volatile load from the `src` pointer + /// The pointer is not required to be aligned. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_load"] + pub fn unaligned_volatile_load(src: *const T) -> T; + /// Performs a volatile store to the `dst` pointer. + /// The pointer is not required to be aligned. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"] + pub fn unaligned_volatile_store(dst: *mut T, val: T); + + /// Returns the square root of an `f16` + /// + /// The stabilized version of this intrinsic is + /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt) + #[rustc_nounwind] + pub fn sqrtf16(x: f16) -> f16; + /// Returns the square root of an `f32` + /// + /// The stabilized version of this intrinsic is + /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt) + #[rustc_nounwind] + pub fn sqrtf32(x: f32) -> f32; + /// Returns the square root of an `f64` + /// + /// The stabilized version of this intrinsic is + /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) + #[rustc_nounwind] + pub fn sqrtf64(x: f64) -> f64; + /// Returns the square root of an `f128` + /// + /// The stabilized version of this intrinsic is + /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt) + #[rustc_nounwind] + pub fn sqrtf128(x: f128) -> f128; + + /// Raises an `f16` to an integer power. + /// + /// The stabilized version of this intrinsic is + /// [`f16::powi`](../../std/primitive.f16.html#method.powi) + #[rustc_nounwind] + pub fn powif16(a: f16, x: i32) -> f16; + /// Raises an `f32` to an integer power. + /// + /// The stabilized version of this intrinsic is + /// [`f32::powi`](../../std/primitive.f32.html#method.powi) + #[rustc_nounwind] + pub fn powif32(a: f32, x: i32) -> f32; + /// Raises an `f64` to an integer power. + /// + /// The stabilized version of this intrinsic is + /// [`f64::powi`](../../std/primitive.f64.html#method.powi) + #[rustc_nounwind] + pub fn powif64(a: f64, x: i32) -> f64; + /// Raises an `f128` to an integer power. + /// + /// The stabilized version of this intrinsic is + /// [`f128::powi`](../../std/primitive.f128.html#method.powi) + #[rustc_nounwind] + pub fn powif128(a: f128, x: i32) -> f128; + + /// Returns the sine of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::sin`](../../std/primitive.f16.html#method.sin) + #[rustc_nounwind] + pub fn sinf16(x: f16) -> f16; + /// Returns the sine of an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::sin`](../../std/primitive.f32.html#method.sin) + #[rustc_nounwind] + pub fn sinf32(x: f32) -> f32; + /// Returns the sine of an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::sin`](../../std/primitive.f64.html#method.sin) + #[rustc_nounwind] + pub fn sinf64(x: f64) -> f64; + /// Returns the sine of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::sin`](../../std/primitive.f128.html#method.sin) + #[rustc_nounwind] + pub fn sinf128(x: f128) -> f128; + + /// Returns the cosine of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::cos`](../../std/primitive.f16.html#method.cos) + #[rustc_nounwind] + pub fn cosf16(x: f16) -> f16; + /// Returns the cosine of an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::cos`](../../std/primitive.f32.html#method.cos) + #[rustc_nounwind] + pub fn cosf32(x: f32) -> f32; + /// Returns the cosine of an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::cos`](../../std/primitive.f64.html#method.cos) + #[rustc_nounwind] + pub fn cosf64(x: f64) -> f64; + /// Returns the cosine of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::cos`](../../std/primitive.f128.html#method.cos) + #[rustc_nounwind] + pub fn cosf128(x: f128) -> f128; + + /// Raises an `f16` to an `f16` power. + /// + /// The stabilized version of this intrinsic is + /// [`f16::powf`](../../std/primitive.f16.html#method.powf) + #[rustc_nounwind] + pub fn powf16(a: f16, x: f16) -> f16; + /// Raises an `f32` to an `f32` power. + /// + /// The stabilized version of this intrinsic is + /// [`f32::powf`](../../std/primitive.f32.html#method.powf) + #[rustc_nounwind] + pub fn powf32(a: f32, x: f32) -> f32; + /// Raises an `f64` to an `f64` power. + /// + /// The stabilized version of this intrinsic is + /// [`f64::powf`](../../std/primitive.f64.html#method.powf) + #[rustc_nounwind] + pub fn powf64(a: f64, x: f64) -> f64; + /// Raises an `f128` to an `f128` power. + /// + /// The stabilized version of this intrinsic is + /// [`f128::powf`](../../std/primitive.f128.html#method.powf) + #[rustc_nounwind] + pub fn powf128(a: f128, x: f128) -> f128; + + /// Returns the exponential of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::exp`](../../std/primitive.f16.html#method.exp) + #[rustc_nounwind] + pub fn expf16(x: f16) -> f16; + /// Returns the exponential of an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::exp`](../../std/primitive.f32.html#method.exp) + #[rustc_nounwind] + pub fn expf32(x: f32) -> f32; + /// Returns the exponential of an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::exp`](../../std/primitive.f64.html#method.exp) + #[rustc_nounwind] + pub fn expf64(x: f64) -> f64; + /// Returns the exponential of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::exp`](../../std/primitive.f128.html#method.exp) + #[rustc_nounwind] + pub fn expf128(x: f128) -> f128; + + /// Returns 2 raised to the power of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2) + #[rustc_nounwind] + pub fn exp2f16(x: f16) -> f16; + /// Returns 2 raised to the power of an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) + #[rustc_nounwind] + pub fn exp2f32(x: f32) -> f32; + /// Returns 2 raised to the power of an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) + #[rustc_nounwind] + pub fn exp2f64(x: f64) -> f64; + /// Returns 2 raised to the power of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2) + #[rustc_nounwind] + pub fn exp2f128(x: f128) -> f128; + + /// Returns the natural logarithm of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::ln`](../../std/primitive.f16.html#method.ln) + #[rustc_nounwind] + pub fn logf16(x: f16) -> f16; + /// Returns the natural logarithm of an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::ln`](../../std/primitive.f32.html#method.ln) + #[rustc_nounwind] + pub fn logf32(x: f32) -> f32; + /// Returns the natural logarithm of an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::ln`](../../std/primitive.f64.html#method.ln) + #[rustc_nounwind] + pub fn logf64(x: f64) -> f64; + /// Returns the natural logarithm of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::ln`](../../std/primitive.f128.html#method.ln) + #[rustc_nounwind] + pub fn logf128(x: f128) -> f128; + + /// Returns the base 10 logarithm of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::log10`](../../std/primitive.f16.html#method.log10) + #[rustc_nounwind] + pub fn log10f16(x: f16) -> f16; + /// Returns the base 10 logarithm of an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::log10`](../../std/primitive.f32.html#method.log10) + #[rustc_nounwind] + pub fn log10f32(x: f32) -> f32; + /// Returns the base 10 logarithm of an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::log10`](../../std/primitive.f64.html#method.log10) + #[rustc_nounwind] + pub fn log10f64(x: f64) -> f64; + /// Returns the base 10 logarithm of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::log10`](../../std/primitive.f128.html#method.log10) + #[rustc_nounwind] + pub fn log10f128(x: f128) -> f128; + + /// Returns the base 2 logarithm of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::log2`](../../std/primitive.f16.html#method.log2) + #[rustc_nounwind] + pub fn log2f16(x: f16) -> f16; + /// Returns the base 2 logarithm of an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::log2`](../../std/primitive.f32.html#method.log2) + #[rustc_nounwind] + pub fn log2f32(x: f32) -> f32; + /// Returns the base 2 logarithm of an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::log2`](../../std/primitive.f64.html#method.log2) + #[rustc_nounwind] + pub fn log2f64(x: f64) -> f64; + /// Returns the base 2 logarithm of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::log2`](../../std/primitive.f128.html#method.log2) + #[rustc_nounwind] + pub fn log2f128(x: f128) -> f128; + + /// Returns `a * b + c` for `f16` values. + /// + /// The stabilized version of this intrinsic is + /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) + #[rustc_nounwind] + pub fn fmaf16(a: f16, b: f16, c: f16) -> f16; + /// Returns `a * b + c` for `f32` values. + /// + /// The stabilized version of this intrinsic is + /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) + #[rustc_nounwind] + pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; + /// Returns `a * b + c` for `f64` values. + /// + /// The stabilized version of this intrinsic is + /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) + #[rustc_nounwind] + pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; + /// Returns `a * b + c` for `f128` values. + /// + /// The stabilized version of this intrinsic is + /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) + #[rustc_nounwind] + pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; + + /// Returns `a * b + c` for `f16` values, non-deterministically executing + /// either a fused multiply-add or two operations with rounding of the + /// intermediate result. + /// + /// The operation is fused if the code generator determines that target + /// instruction set has support for a fused operation, and that the fused + /// operation is more efficient than the equivalent, separate pair of mul + /// and add instructions. It is unspecified whether or not a fused operation + /// is selected, and that may depend on optimization level and context, for + /// example. + #[rustc_nounwind] + pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; + /// Returns `a * b + c` for `f32` values, non-deterministically executing + /// either a fused multiply-add or two operations with rounding of the + /// intermediate result. + /// + /// The operation is fused if the code generator determines that target + /// instruction set has support for a fused operation, and that the fused + /// operation is more efficient than the equivalent, separate pair of mul + /// and add instructions. It is unspecified whether or not a fused operation + /// is selected, and that may depend on optimization level and context, for + /// example. + #[rustc_nounwind] + pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; + /// Returns `a * b + c` for `f64` values, non-deterministically executing + /// either a fused multiply-add or two operations with rounding of the + /// intermediate result. + /// + /// The operation is fused if the code generator determines that target + /// instruction set has support for a fused operation, and that the fused + /// operation is more efficient than the equivalent, separate pair of mul + /// and add instructions. It is unspecified whether or not a fused operation + /// is selected, and that may depend on optimization level and context, for + /// example. + #[rustc_nounwind] + pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; + /// Returns `a * b + c` for `f128` values, non-deterministically executing + /// either a fused multiply-add or two operations with rounding of the + /// intermediate result. + /// + /// The operation is fused if the code generator determines that target + /// instruction set has support for a fused operation, and that the fused + /// operation is more efficient than the equivalent, separate pair of mul + /// and add instructions. It is unspecified whether or not a fused operation + /// is selected, and that may depend on optimization level and context, for + /// example. + #[rustc_nounwind] + pub fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; + + /// Returns the largest integer less than or equal to an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::floor`](../../std/primitive.f16.html#method.floor) + #[rustc_nounwind] + pub fn floorf16(x: f16) -> f16; + /// Returns the largest integer less than or equal to an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::floor`](../../std/primitive.f32.html#method.floor) + #[rustc_nounwind] + pub fn floorf32(x: f32) -> f32; + /// Returns the largest integer less than or equal to an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::floor`](../../std/primitive.f64.html#method.floor) + #[rustc_nounwind] + pub fn floorf64(x: f64) -> f64; + /// Returns the largest integer less than or equal to an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::floor`](../../std/primitive.f128.html#method.floor) + #[rustc_nounwind] + pub fn floorf128(x: f128) -> f128; + + /// Returns the smallest integer greater than or equal to an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) + #[rustc_nounwind] + pub fn ceilf16(x: f16) -> f16; + /// Returns the smallest integer greater than or equal to an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) + #[rustc_nounwind] + pub fn ceilf32(x: f32) -> f32; + /// Returns the smallest integer greater than or equal to an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) + #[rustc_nounwind] + pub fn ceilf64(x: f64) -> f64; + /// Returns the smallest integer greater than or equal to an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) + #[rustc_nounwind] + pub fn ceilf128(x: f128) -> f128; + + /// Returns the integer part of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) + #[rustc_nounwind] + pub fn truncf16(x: f16) -> f16; + /// Returns the integer part of an `f32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) + #[rustc_nounwind] + pub fn truncf32(x: f32) -> f32; + /// Returns the integer part of an `f64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) + #[rustc_nounwind] + pub fn truncf64(x: f64) -> f64; + /// Returns the integer part of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) + #[rustc_nounwind] + pub fn truncf128(x: f128) -> f128; + + /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions + /// cannot actually be utilized from Rust code. + /// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) + #[rustc_nounwind] + pub fn rintf16(x: f16) -> f16; + /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions + /// cannot actually be utilized from Rust code. + /// In other words, this intrinsic is equivalent in behavior to `nearbyintf32` and `roundevenf32`. + /// + /// The stabilized version of this intrinsic is + /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) + #[rustc_nounwind] + pub fn rintf32(x: f32) -> f32; + /// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions + /// cannot actually be utilized from Rust code. + /// In other words, this intrinsic is equivalent in behavior to `nearbyintf64` and `roundevenf64`. + /// + /// The stabilized version of this intrinsic is + /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) + #[rustc_nounwind] + pub fn rintf64(x: f64) -> f64; + /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions + /// cannot actually be utilized from Rust code. + /// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) + #[rustc_nounwind] + pub fn rintf128(x: f128) -> f128; + + /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn nearbyintf16(x: f16) -> f16; + /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn nearbyintf32(x: f32) -> f32; + /// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn nearbyintf64(x: f64) -> f64; + /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn nearbyintf128(x: f128) -> f128; + + /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. + /// + /// The stabilized version of this intrinsic is + /// [`f16::round`](../../std/primitive.f16.html#method.round) + #[rustc_nounwind] + pub fn roundf16(x: f16) -> f16; + /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. + /// + /// The stabilized version of this intrinsic is + /// [`f32::round`](../../std/primitive.f32.html#method.round) + #[rustc_nounwind] + pub fn roundf32(x: f32) -> f32; + /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. + /// + /// The stabilized version of this intrinsic is + /// [`f64::round`](../../std/primitive.f64.html#method.round) + #[rustc_nounwind] + pub fn roundf64(x: f64) -> f64; + /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero. + /// + /// The stabilized version of this intrinsic is + /// [`f128::round`](../../std/primitive.f128.html#method.round) + #[rustc_nounwind] + pub fn roundf128(x: f128) -> f128; + + /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn roundevenf16(x: f16) -> f16; + /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn roundevenf32(x: f32) -> f32; + /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn roundevenf64(x: f64) -> f64; + /// Returns the nearest integer to an `f128`. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn roundevenf128(x: f128) -> f128; + + /// Float addition that allows optimizations based on algebraic rules. + /// May assume inputs are finite. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn fadd_fast(a: T, b: T) -> T; + + /// Float subtraction that allows optimizations based on algebraic rules. + /// May assume inputs are finite. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn fsub_fast(a: T, b: T) -> T; + + /// Float multiplication that allows optimizations based on algebraic rules. + /// May assume inputs are finite. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn fmul_fast(a: T, b: T) -> T; + + /// Float division that allows optimizations based on algebraic rules. + /// May assume inputs are finite. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn fdiv_fast(a: T, b: T) -> T; + + /// Float remainder that allows optimizations based on algebraic rules. + /// May assume inputs are finite. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn frem_fast(a: T, b: T) -> T; + + /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range + /// () + /// + /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. + #[rustc_nounwind] + pub fn float_to_int_unchecked(value: Float) -> Int; +} + +/// Float addition that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn fadd_algebraic(_a: T, _b: T) -> T { + unimplemented!() +} + +/// Float subtraction that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn fsub_algebraic(_a: T, _b: T) -> T { + unimplemented!() +} + +/// Float multiplication that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn fmul_algebraic(_a: T, _b: T) -> T { + unimplemented!() +} + +/// Float division that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn fdiv_algebraic(_a: T, _b: T) -> T { + unimplemented!() +} + +/// Float remainder that allows optimizations based on algebraic rules. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn frem_algebraic(_a: T, _b: T) -> T { + unimplemented!() +} + +/// Returns the number of bits set in an integer type `T` +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `count_ones` method. For example, +/// [`u32::count_ones`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn ctpop(_x: T) -> u32 { + unimplemented!() +} + +/// Returns the number of leading unset bits (zeroes) in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `leading_zeros` method. For example, +/// [`u32::leading_zeros`] +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz; +/// +/// let x = 0b0001_1100_u8; +/// let num_leading = ctlz(x); +/// assert_eq!(num_leading, 3); +/// ``` +/// +/// An `x` with value `0` will return the bit width of `T`. +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz; +/// +/// let x = 0u16; +/// let num_leading = ctlz(x); +/// assert_eq!(num_leading, 16); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn ctlz(_x: T) -> u32 { + unimplemented!() +} + +/// Like `ctlz`, but extra-unsafe as it returns `undef` when +/// given an `x` with value `0`. +/// +/// This intrinsic does not have a stable counterpart. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz_nonzero; +/// +/// let x = 0b0001_1100_u8; +/// let num_leading = unsafe { ctlz_nonzero(x) }; +/// assert_eq!(num_leading, 3); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ctlz_nonzero(_x: T) -> u32 { + unimplemented!() +} + +/// Returns the number of trailing unset bits (zeroes) in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `trailing_zeros` method. For example, +/// [`u32::trailing_zeros`] +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz; +/// +/// let x = 0b0011_1000_u8; +/// let num_trailing = cttz(x); +/// assert_eq!(num_trailing, 3); +/// ``` +/// +/// An `x` with value `0` will return the bit width of `T`: +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz; +/// +/// let x = 0u16; +/// let num_trailing = cttz(x); +/// assert_eq!(num_trailing, 16); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn cttz(_x: T) -> u32 { + unimplemented!() +} + +/// Like `cttz`, but extra-unsafe as it returns `undef` when +/// given an `x` with value `0`. +/// +/// This intrinsic does not have a stable counterpart. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz_nonzero; +/// +/// let x = 0b0011_1000_u8; +/// let num_trailing = unsafe { cttz_nonzero(x) }; +/// assert_eq!(num_trailing, 3); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn cttz_nonzero(_x: T) -> u32 { + unimplemented!() +} + +/// Reverses the bytes in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `swap_bytes` method. For example, +/// [`u32::swap_bytes`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn bswap(_x: T) -> T { + unimplemented!() +} + +/// Reverses the bits in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `reverse_bits` method. For example, +/// [`u32::reverse_bits`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn bitreverse(_x: T) -> T { + unimplemented!() +} + +/// Does a three-way comparison between the two integer arguments. +/// +/// This is included as an intrinsic as it's useful to let it be one thing +/// in MIR, rather than the multiple checks and switches that make its IR +/// large and difficult to optimize. +/// +/// The stabilized version of this intrinsic is [`Ord::cmp`]. +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_three_way_compare", issue = "none"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Ordering { + unimplemented!() +} + +/// Performs checked integer addition. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_add` method. For example, +/// [`u32::overflowing_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} + +/// Performs checked integer subtraction +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_sub` method. For example, +/// [`u32::overflowing_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} + +/// Performs checked integer multiplication +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_mul` method. For example, +/// [`u32::overflowing_mul`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} + +/// Performs an exact division, resulting in undefined behavior where +/// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_exact_div", issue = "none"))] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn exact_div(_x: T, _y: T) -> T { + unimplemented!() +} + +/// Performs an unchecked division, resulting in undefined behavior +/// where `y == 0` or `x == T::MIN && y == -1` +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_div` method. For example, +/// [`u32::checked_div`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { + unimplemented!() +} +/// Returns the remainder of an unchecked division, resulting in +/// undefined behavior when `y == 0` or `x == T::MIN && y == -1` +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_rem` method. For example, +/// [`u32::checked_rem`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { + unimplemented!() +} + +/// Performs an unchecked left shift, resulting in undefined behavior when +/// `y < 0` or `y >= N`, where N is the width of T in bits. +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_shl` method. For example, +/// [`u32::checked_shl`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { + unimplemented!() +} +/// Performs an unchecked right shift, resulting in undefined behavior when +/// `y < 0` or `y >= N`, where N is the width of T in bits. +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_shr` method. For example, +/// [`u32::checked_shr`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { + unimplemented!() +} + +/// Returns the result of an unchecked addition, resulting in +/// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_add` on the various +/// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { + unimplemented!() +} + +/// Returns the result of an unchecked subtraction, resulting in +/// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_sub` on the various +/// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { + unimplemented!() +} + +/// Returns the result of an unchecked multiplication, resulting in +/// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_mul` on the various +/// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { + unimplemented!() +} + +/// Performs rotate left. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `rotate_left` method. For example, +/// [`u32::rotate_left`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn rotate_left(_x: T, _shift: u32) -> T { + unimplemented!() +} + +/// Performs rotate right. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `rotate_right` method. For example, +/// [`u32::rotate_right`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn rotate_right(_x: T, _shift: u32) -> T { + unimplemented!() +} + +/// Returns (a + b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_add` method. For example, +/// [`u32::wrapping_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_add(_a: T, _b: T) -> T { + unimplemented!() +} +/// Returns (a - b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_sub` method. For example, +/// [`u32::wrapping_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_sub(_a: T, _b: T) -> T { + unimplemented!() +} +/// Returns (a * b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_mul` method. For example, +/// [`u32::wrapping_mul`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_mul(_a: T, _b: T) -> T { + unimplemented!() +} + +/// Computes `a + b`, saturating at numeric bounds. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `saturating_add` method. For example, +/// [`u32::saturating_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn saturating_add(_a: T, _b: T) -> T { + unimplemented!() +} +/// Computes `a - b`, saturating at numeric bounds. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `saturating_sub` method. For example, +/// [`u32::saturating_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn saturating_sub(_a: T, _b: T) -> T { + unimplemented!() +} + +/// This is an implementation detail of [`crate::ptr::read`] and should +/// not be used anywhere else. See its comments for why this exists. +/// +/// This intrinsic can *only* be called where the pointer is a local without +/// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it +/// trivially obeys runtime-MIR rules about derefs in operands. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn read_via_copy(_ptr: *const T) -> T { + unimplemented!() +} + +/// This is an implementation detail of [`crate::ptr::write`] and should +/// not be used anywhere else. See its comments for why this exists. +/// +/// This intrinsic can *only* be called where the pointer is a local without +/// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so +/// that it trivially obeys runtime-MIR rules about derefs in operands. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { + unimplemented!() +} + +/// Returns the value of the discriminant for the variant in 'v'; +/// if `T` has no discriminant, returns `0`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::mem::discriminant`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn discriminant_value(_v: &T) -> ::Discriminant { + unimplemented!() +} + +extern "rust-intrinsic" { + /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the + /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. + /// + /// `catch_fn` must not unwind. + /// + /// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign + /// unwinds). This function takes the data pointer and a pointer to the target- and + /// runtime-specific exception object that was caught. + /// + /// Note that in the case of a foreign unwinding operation, the exception object data may not be + /// safely usable from Rust, and should not be directly exposed via the standard library. To + /// prevent unsafe access, the library implementation may either abort the process or present an + /// opaque error type to the user. + /// + /// For more information, see the compiler's source, as well as the documentation for the stable + /// version of this intrinsic, `std::panic::catch_unwind`. + #[rustc_nounwind] + pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; + + /// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held + /// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`. + /// + /// Not all architectures provide such an operation. For instance, x86 does not: while `MOVNT` + /// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered + /// in ways that are not allowed for regular writes). + #[rustc_nounwind] + pub fn nontemporal_store(ptr: *mut T, val: T); +} + +/// See documentation of `<*const T>::offset_from` for details. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ptr_offset_from(_ptr: *const T, _base: *const T) -> isize { + unimplemented!() +} + +/// See documentation of `<*const T>::sub_ptr` for details. +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892"))] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ptr_offset_from_unsigned(_ptr: *const T, _base: *const T) -> usize { + unimplemented!() +} + +/// See documentation of `<*const T>::guaranteed_eq` for details. +/// Returns `2` if the result is unknown. +/// Returns `1` if the pointers are guaranteed equal. +/// Returns `0` if the pointers are guaranteed inequal. +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))] +#[rustc_intrinsic] +#[rustc_nounwind] +#[rustc_do_not_const_check] +#[inline] +#[miri::intrinsic_fallback_is_spec] +pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { + (ptr == other) as u8 +} + +/// Determines whether the raw bytes of the two values are equal. +/// +/// This is particularly handy for arrays, since it allows things like just +/// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`. +/// +/// Above some backend-decided threshold this will emit calls to `memcmp`, +/// like slice equality does, instead of causing massive code size. +/// +/// Since this works by comparing the underlying bytes, the actual `T` is +/// not particularly important. It will be used for its size and alignment, +/// but any validity restrictions will be ignored, not enforced. +/// +/// # Safety +/// +/// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. +/// Note that this is a stricter criterion than just the *values* being +/// fully-initialized: if `T` has padding, it's UB to call this intrinsic. +/// +/// At compile-time, it is furthermore UB to call this if any of the bytes +/// in `*a` or `*b` have provenance. +/// +/// (The implementation is allowed to branch on the results of comparisons, +/// which is UB if any of their inputs are `undef`.) +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none"))] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn raw_eq(_a: &T, _b: &T) -> bool { + unimplemented!() +} + +/// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` +/// as unsigned bytes, returning negative if `left` is less, zero if all the +/// bytes match, or positive if `left` is greater. +/// +/// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`. +/// +/// # Safety +/// +/// `left` and `right` must each be [valid] for reads of `bytes` bytes. +/// +/// Note that this applies to the whole range, not just until the first byte +/// that differs. That allows optimizations that can read in large chunks. +/// +/// [valid]: crate::ptr#safety +#[cfg_attr( + bootstrap, + rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none") +)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: usize) -> i32 { + unimplemented!() +} + +/// See documentation of [`std::hint::black_box`] for details. +/// +/// [`std::hint::black_box`]: crate::hint::black_box +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_black_box", issue = "none"))] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn black_box(_dummy: T) -> T { + unimplemented!() +} + +/// Selects which function to call depending on the context. +/// +/// If this function is evaluated at compile-time, then a call to this +/// intrinsic will be replaced with a call to `called_in_const`. It gets +/// replaced with a call to `called_at_rt` otherwise. +/// +/// This function is safe to call, but note the stability concerns below. +/// +/// # Type Requirements +/// +/// The two functions must be both function items. They cannot be function +/// pointers or closures. The first function must be a `const fn`. +/// +/// `arg` will be the tupled arguments that will be passed to either one of +/// the two functions, therefore, both functions must accept the same type of +/// arguments. Both functions must return RET. +/// +/// # Stability concerns +/// +/// Rust has not yet decided that `const fn` are allowed to tell whether +/// they run at compile-time or at runtime. Therefore, when using this +/// intrinsic anywhere that can be reached from stable, it is crucial that +/// the end-to-end behavior of the stable `const fn` is the same for both +/// modes of execution. (Here, Undefined Behavior is considered "the same" +/// as any other behavior, so if the function exhibits UB at runtime then +/// it may do whatever it wants at compile-time.) +/// +/// Here is an example of how this could cause a problem: +/// ```no_run +/// #![feature(const_eval_select)] +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// use std::intrinsics::const_eval_select; +/// +/// // Standard library +/// pub const fn inconsistent() -> i32 { +/// fn runtime() -> i32 { 1 } +/// const fn compiletime() -> i32 { 2 } +/// +/// // ⚠ This code violates the required equivalence of `compiletime` +/// // and `runtime`. +/// const_eval_select((), compiletime, runtime) +/// } +/// +/// // User Crate +/// const X: i32 = inconsistent(); +/// let x = inconsistent(); +/// assert_eq!(x, X); +/// ``` +/// +/// Currently such an assertion would always succeed; until Rust decides +/// otherwise, that principle should not be violated. +#[rustc_const_unstable(feature = "const_eval_select", issue = "124625")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn const_eval_select( + _arg: ARG, + _called_in_const: F, + _called_at_rt: G, +) -> RET +where + G: FnOnce, + F: FnOnce, +{ + unreachable!() +} + +/// A macro to make it easier to invoke const_eval_select. Use as follows: +/// ```rust,ignore (just a macro example) +/// const_eval_select!( +/// @capture { arg1: i32 = some_expr, arg2: T = other_expr } -> U: +/// if const #[attributes_for_const_arm] { +/// // Compile-time code goes here. +/// } else #[attributes_for_runtime_arm] { +/// // Run-time code goes here. +/// } +/// ) +/// ``` +/// The `@capture` block declares which surrounding variables / expressions can be +/// used inside the `if const`. +/// Note that the two arms of this `if` really each become their own function, which is why the +/// macro supports setting attributes for those functions. The runtime function is always +/// markes as `#[inline]`. +/// +/// See [`const_eval_select()`] for the rules and requirements around that intrinsic. +pub(crate) macro const_eval_select { + ( + @capture { $($arg:ident : $ty:ty = $val:expr),* $(,)? } $( -> $ret:ty )? : + if const + $(#[$compiletime_attr:meta])* $compiletime:block + else + $(#[$runtime_attr:meta])* $runtime:block + ) => { + // Use the `noinline` arm, after adding explicit `inline` attributes + $crate::intrinsics::const_eval_select!( + @capture { $($arg : $ty = $val),* } $(-> $ret)? : + #[noinline] + if const + #[inline] // prevent codegen on this function + $(#[$compiletime_attr])* + $compiletime + else + #[inline] // avoid the overhead of an extra fn call + $(#[$runtime_attr])* + $runtime + ) + }, + // With a leading #[noinline], we don't add inline attributes + ( + @capture { $($arg:ident : $ty:ty = $val:expr),* $(,)? } $( -> $ret:ty )? : + #[noinline] + if const + $(#[$compiletime_attr:meta])* $compiletime:block + else + $(#[$runtime_attr:meta])* $runtime:block + ) => {{ + $(#[$runtime_attr])* + fn runtime($($arg: $ty),*) $( -> $ret )? { + $runtime + } + + $(#[$compiletime_attr])* + const fn compiletime($($arg: $ty),*) $( -> $ret )? { + // Don't warn if one of the arguments is unused. + $(let _ = $arg;)* + + $compiletime + } + + const_eval_select(($($val,)*), compiletime, runtime) + }}, + // We support leaving away the `val` expressions for *all* arguments + // (but not for *some* arguments, that's too tricky). + ( + @capture { $($arg:ident : $ty:ty),* $(,)? } $( -> $ret:ty )? : + if const + $(#[$compiletime_attr:meta])* $compiletime:block + else + $(#[$runtime_attr:meta])* $runtime:block + ) => { + $crate::intrinsics::const_eval_select!( + @capture { $($arg : $ty = $arg),* } $(-> $ret)? : + if const + $(#[$compiletime_attr])* $compiletime + else + $(#[$runtime_attr])* $runtime + ) + }, +} + +/// Returns whether the argument's value is statically known at +/// compile-time. +/// +/// This is useful when there is a way of writing the code that will +/// be *faster* when some variables have known values, but *slower* +/// in the general case: an `if is_val_statically_known(var)` can be used +/// to select between these two variants. The `if` will be optimized away +/// and only the desired branch remains. +/// +/// Formally speaking, this function non-deterministically returns `true` +/// or `false`, and the caller has to ensure sound behavior for both cases. +/// In other words, the following code has *Undefined Behavior*: +/// +/// ```no_run +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// use std::hint::unreachable_unchecked; +/// use std::intrinsics::is_val_statically_known; +/// +/// if !is_val_statically_known(0) { unsafe { unreachable_unchecked(); } } +/// ``` +/// +/// This also means that the following code's behavior is unspecified; it +/// may panic, or it may not: +/// +/// ```no_run +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// use std::intrinsics::is_val_statically_known; +/// +/// assert_eq!(is_val_statically_known(0), is_val_statically_known(0)); +/// ``` +/// +/// Unsafe code may not rely on `is_val_statically_known` returning any +/// particular value, ever. However, the compiler will generally make it +/// return `true` only if the value of the argument is actually known. +/// +/// # Stability concerns +/// +/// While it is safe to call, this intrinsic may behave differently in +/// a `const` context than otherwise. See the [`const_eval_select()`] +/// documentation for an explanation of the issues this can cause. Unlike +/// `const_eval_select`, this intrinsic isn't guaranteed to behave +/// deterministically even in a `const` context. +/// +/// # Type Requirements +/// +/// `T` must be either a `bool`, a `char`, a primitive numeric type (e.g. `f32`, +/// but not `NonZeroISize`), or any thin pointer (e.g. `*mut String`). +/// Any other argument types *may* cause a compiler error. +/// +/// ## Pointers +/// +/// When the input is a pointer, only the pointer itself is +/// ever considered. The pointee has no effect. Currently, these functions +/// behave identically: +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// use std::intrinsics::is_val_statically_known; +/// +/// fn foo(x: &i32) -> bool { +/// is_val_statically_known(x) +/// } +/// +/// fn bar(x: &i32) -> bool { +/// is_val_statically_known( +/// (x as *const i32).addr() +/// ) +/// } +/// # _ = foo(&5_i32); +/// # _ = bar(&5_i32); +/// ``` +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_is_val_statically_known", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +pub const fn is_val_statically_known(_arg: T) -> bool { + false +} + +/// Non-overlapping *typed* swap of a single value. +/// +/// The codegen backends will replace this with a better implementation when +/// `T` is a simple type that can be loaded and stored as an immediate. +/// +/// The stabilized form of this intrinsic is [`crate::mem::swap`]. +/// +/// # Safety +/// +/// `x` and `y` are readable and writable as `T`, and non-overlapping. +#[rustc_nounwind] +#[inline] +#[rustc_intrinsic] +// Const-unstable because `swap_nonoverlapping` is const-unstable. +#[rustc_const_unstable(feature = "const_typed_swap", issue = "none")] +pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { + // SAFETY: The caller provided single non-overlapping items behind + // pointers, so swapping them with `count: 1` is fine. + unsafe { ptr::swap_nonoverlapping(x, y, 1) }; +} + +/// Returns whether we should perform some UB-checking at runtime. This eventually evaluates to +/// `cfg!(ub_checks)`, but behaves different from `cfg!` when mixing crates built with different +/// flags: if the crate has UB checks enabled or carries the `#[rustc_preserve_ub_checks]` +/// attribute, evaluation is delayed until monomorphization (or until the call gets inlined into +/// a crate that does not delay evaluation further); otherwise it can happen any time. +/// +/// The common case here is a user program built with ub_checks linked against the distributed +/// sysroot which is built without ub_checks but with `#[rustc_preserve_ub_checks]`. +/// For code that gets monomorphized in the user crate (i.e., generic functions and functions with +/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(ub_checks)` means that +/// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the +/// user has UB checks disabled, the checks will still get optimized out. This intrinsic is +/// primarily used by [`ub_checks::assert_unsafe_precondition`]. +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] // just for UB checks +#[inline(always)] +#[rustc_intrinsic] +pub const fn ub_checks() -> bool { + cfg!(ub_checks) +} + +/// Allocates a block of memory at compile time. +/// At runtime, just returns a null pointer. +/// +/// # Safety +/// +/// - The `align` argument must be a power of two. +/// - At compile time, a compile error occurs if this constraint is violated. +/// - At runtime, it is not checked. +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[miri::intrinsic_fallback_is_spec] +pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 { + // const eval overrides this function, but runtime code for now just returns null pointers. + // See . + crate::ptr::null_mut() +} + +/// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time. +/// At runtime, does nothing. +/// +/// # Safety +/// +/// - The `align` argument must be a power of two. +/// - At compile time, a compile error occurs if this constraint is violated. +/// - At runtime, it is not checked. +/// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it. +/// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it. +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[miri::intrinsic_fallback_is_spec] +pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) { + // Runtime NOP +} + +/// The intrinsic will return the size stored in that vtable. +/// +/// # Safety +/// +/// `ptr` must point to a vtable. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub unsafe fn vtable_size(_ptr: *const ()) -> usize { + unreachable!() +} + +/// The intrinsic will return the alignment stored in that vtable. +/// +/// # Safety +/// +/// `ptr` must point to a vtable. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub unsafe fn vtable_align(_ptr: *const ()) -> usize { + unreachable!() +} + +/// The size of a type in bytes. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// More specifically, this is the offset in bytes between successive +/// items of the same type, including alignment padding. +/// +/// The stabilized version of this intrinsic is [`core::mem::size_of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn size_of() -> usize { + unreachable!() +} + +/// The minimum alignment of a type. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::mem::align_of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn min_align_of() -> usize { + unreachable!() +} + +/// The preferred alignment of a type. +/// +/// This intrinsic does not have a stable counterpart. +/// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_pref_align_of", issue = "91971"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn pref_align_of() -> usize { + unreachable!() +} + +/// Returns the number of variants of the type `T` cast to a `usize`; +/// if `T` has no variants, returns `0`. Uninhabited variants will be counted. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "variant_count", issue = "73662"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn variant_count() -> usize { + unreachable!() +} + +/// The size of the referenced value in bytes. +/// +/// The stabilized version of this intrinsic is [`crate::mem::size_of_val`]. +/// +/// # Safety +/// +/// See [`crate::mem::size_of_val_raw`] for safety conditions. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_size_of_val", issue = "46571"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn size_of_val(_ptr: *const T) -> usize { + unreachable!() +} + +/// The required alignment of the referenced value. +/// +/// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. +/// +/// # Safety +/// +/// See [`crate::mem::align_of_val_raw`] for safety conditions. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_align_of_val", issue = "46571"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { + unreachable!() +} + +/// Gets a static string slice containing the name of a type. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::any::type_name`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_name", issue = "63084"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn type_name() -> &'static str { + unreachable!() +} + +/// Gets an identifier which is globally unique to the specified type. This +/// function will return the same value for a type regardless of whichever +/// crate it is invoked in. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_id", issue = "77125"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn type_id() -> u128 { + unreachable!() +} + +/// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. +/// +/// This is used to implement functions like `slice::from_raw_parts_mut` and +/// `ptr::from_raw_parts` in a way compatible with the compiler being able to +/// change the possible layouts of pointers. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { + // To implement a fallback we'd have to assume the layout of the pointer, + // but the whole point of this intrinsic is that we shouldn't do that. + unreachable!() +} + +#[unstable(feature = "core_intrinsics", issue = "none")] +pub trait AggregateRawPtr { + type Metadata: Copy; +} +impl AggregateRawPtr<*const T> for *const P { + type Metadata =

::Metadata; +} +impl AggregateRawPtr<*mut T> for *mut P { + type Metadata =

::Metadata; +} + +/// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`. +/// +/// This is used to implement functions like `ptr::metadata`. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr( + bootstrap, + cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")) +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { + // To implement a fallback we'd have to assume the layout of the pointer, + // but the whole point of this intrinsic is that we shouldn't do that. + unreachable!() +} + +// Some functions are defined here because they accidentally got made +// available in this module on stable. See . +// (`transmute` also falls into this category, but it cannot be wrapped due to the +// check that `T` and `U` have the same size.) + +/// Copies `count * size_of::()` bytes from `src` to `dst`. The source +/// and destination must *not* overlap. +/// +/// For regions of memory which might overlap, use [`copy`] instead. +/// +/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but +/// with the argument order swapped. +/// +/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// +/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// * The region of memory beginning at `src` with a size of `count * +/// size_of::()` bytes must *not* overlap with the region of memory +/// beginning at `dst` with the same size. +/// +/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointers must be properly aligned. +/// +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Manually implement [`Vec::append`]: +/// +/// ``` +/// use std::ptr; +/// +/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. +/// fn append(dst: &mut Vec, src: &mut Vec) { +/// let src_len = src.len(); +/// let dst_len = dst.len(); +/// +/// // Ensure that `dst` has enough capacity to hold all of `src`. +/// dst.reserve(src_len); +/// +/// unsafe { +/// // The call to add is always safe because `Vec` will never +/// // allocate more than `isize::MAX` bytes. +/// let dst_ptr = dst.as_mut_ptr().add(dst_len); +/// let src_ptr = src.as_ptr(); +/// +/// // Truncate `src` without dropping its contents. We do this first, +/// // to avoid problems in case something further down panics. +/// src.set_len(0); +/// +/// // The two regions cannot overlap because mutable references do +/// // not alias, and two different vectors cannot own the same +/// // memory. +/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); +/// +/// // Notify `dst` that it now holds the contents of `src`. +/// dst.set_len(dst_len + src_len); +/// } +/// } +/// +/// let mut a = vec!['r']; +/// let mut b = vec!['u', 's', 't']; +/// +/// append(&mut a, &mut b); +/// +/// assert_eq!(a, &['r', 'u', 's', 't']); +/// assert!(b.is_empty()); +/// ``` +/// +/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append +#[doc(alias = "memcpy")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allowed_through_unstable_modules] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] +#[inline(always)] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] +pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn copy_nonoverlapping(_src: *const T, _dst: *mut T, _count: usize) { + unreachable!() + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \ + and the specified memory ranges do not overlap", + ( + src: *const () = src as *const (), + dst: *mut () = dst as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + count: usize = count, + ) => { + let zero_size = count == 0 || size == 0; + ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size) + && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size) + && ub_checks::maybe_is_nonoverlapping(src, dst, size, count) + } + ); + + // SAFETY: the safety contract for `copy_nonoverlapping` must be + // upheld by the caller. + unsafe { copy_nonoverlapping(src, dst, count) } +} + +/// Copies `count * size_of::()` bytes from `src` to `dst`. The source +/// and destination may overlap. +/// +/// If the source and destination will *never* overlap, +/// [`copy_nonoverlapping`] can be used instead. +/// +/// `copy` is semantically equivalent to C's [`memmove`], but with the argument +/// order swapped. Copying takes place as if the bytes were copied from `src` +/// to a temporary array and then copied from the array to `dst`. +/// +/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// +/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::()` bytes, and must remain valid even +/// when `dst` is written for `count * size_of::()` bytes. (This means if the memory ranges +/// overlap, the two pointers must not be subject to aliasing restrictions relative to each +/// other.) +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes, and must remain valid even +/// when `src` is read for `count * size_of::()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointers must be properly aligned. +/// +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Efficiently create a Rust vector from an unsafe buffer: +/// +/// ``` +/// use std::ptr; +/// +/// /// # Safety +/// /// +/// /// * `ptr` must be correctly aligned for its type and non-zero. +/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. +/// /// * Those elements must not be used after calling this function unless `T: Copy`. +/// # #[allow(dead_code)] +/// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { +/// let mut dst = Vec::with_capacity(elts); +/// +/// // SAFETY: Our precondition ensures the source is aligned and valid, +/// // and `Vec::with_capacity` ensures that we have usable space to write them. +/// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// +/// // SAFETY: We created it with this much capacity earlier, +/// // and the previous `copy` has initialized these elements. +/// dst.set_len(elts); +/// dst +/// } +/// ``` +#[doc(alias = "memmove")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allowed_through_unstable_modules] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] +#[inline(always)] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[rustc_diagnostic_item = "ptr_copy"] +pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize) { + unreachable!() + } + + // SAFETY: the safety contract for `copy` must be upheld by the caller. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::copy requires that both pointer arguments are aligned and non-null", + ( + src: *const () = src as *const (), + dst: *mut () = dst as *mut (), + align: usize = align_of::(), + zero_size: bool = T::IS_ZST || count == 0, + ) => + ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size) + && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size) + ); + copy(src, dst, count) + } +} + +/// Sets `count * size_of::()` bytes of memory starting at `dst` to +/// `val`. +/// +/// `write_bytes` is similar to C's [`memset`], but sets `count * +/// size_of::()` bytes to `val`. +/// +/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * `dst` must be properly aligned. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointer must be properly aligned. +/// +/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB) +/// later if the written bytes are not a valid representation of some `T`. For instance, the +/// following is an **incorrect** use of this function: +/// +/// ```rust,no_run +/// unsafe { +/// let mut value: u8 = 0; +/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool; +/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`. +/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB... +/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️ +/// } +/// ``` +/// +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::ptr; +/// +/// let mut vec = vec![0u32; 4]; +/// unsafe { +/// let vec_ptr = vec.as_mut_ptr(); +/// ptr::write_bytes(vec_ptr, 0xfe, 2); +/// } +/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); +/// ``` +#[doc(alias = "memset")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allowed_through_unstable_modules] +#[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 +#[rustc_diagnostic_item = "ptr_write_bytes"] +pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize) { + unreachable!() + } + + // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::write_bytes requires that the destination pointer is aligned and non-null", + ( + addr: *const () = dst as *const (), + align: usize = align_of::(), + zero_size: bool = T::IS_ZST || count == 0, + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size) + ); + write_bytes(dst, val, count) + } +} + +/// Returns the minimum of two `f16` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f16::min`] +#[rustc_nounwind] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn minnumf16(_x: f16, _y: f16) -> f16 { + unimplemented!(); +} + +/// Returns the minimum of two `f32` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f32::min`] +#[rustc_nounwind] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn minnumf32(_x: f32, _y: f32) -> f32 { + unimplemented!(); +} + +/// Returns the minimum of two `f64` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f64::min`] +#[rustc_nounwind] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn minnumf64(_x: f64, _y: f64) -> f64 { + unimplemented!(); +} + +/// Returns the minimum of two `f128` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f128::min`] +#[rustc_nounwind] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn minnumf128(_x: f128, _y: f128) -> f128 { + unimplemented!(); +} + +/// Returns the maximum of two `f16` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f16::max`] +#[rustc_nounwind] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { + unimplemented!(); +} + +/// Returns the maximum of two `f32` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f32::max`] +#[rustc_nounwind] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { + unimplemented!(); +} + +/// Returns the maximum of two `f64` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f64::max`] +#[rustc_nounwind] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { + unimplemented!(); +} + +/// Returns the maximum of two `f128` values. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is +/// [`f128::max`] +#[rustc_nounwind] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { + unimplemented!(); +} + +/// Returns the absolute value of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::abs`](../../std/primitive.f16.html#method.abs) +#[rustc_nounwind] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf16(_x: f16) -> f16 { + unimplemented!(); +} + +/// Returns the absolute value of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::abs`](../../std/primitive.f32.html#method.abs) +#[rustc_nounwind] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf32(_x: f32) -> f32 { + unimplemented!(); +} + +/// Returns the absolute value of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::abs`](../../std/primitive.f64.html#method.abs) +#[rustc_nounwind] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf64(_x: f64) -> f64 { + unimplemented!(); +} + +/// Returns the absolute value of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::abs`](../../std/primitive.f128.html#method.abs) +#[rustc_nounwind] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf128(_x: f128) -> f128 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f16` values. +/// +/// The stabilized version of this intrinsic is +/// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) +#[rustc_nounwind] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f32` values. +/// +/// The stabilized version of this intrinsic is +/// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) +#[rustc_nounwind] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { + unimplemented!(); +} +/// Copies the sign from `y` to `x` for `f64` values. +/// +/// The stabilized version of this intrinsic is +/// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) +#[rustc_nounwind] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f128` values. +/// +/// The stabilized version of this intrinsic is +/// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) +#[rustc_nounwind] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { + unimplemented!(); +} + +/// Inform Miri that a given pointer definitely has a certain alignment. +#[cfg(miri)] +#[rustc_allow_const_fn_unstable(const_eval_select)] +pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) { + extern "Rust" { + /// Miri-provided extern function to promise that a given pointer is properly aligned for + /// "symbolic" alignment checks. Will fail if the pointer is not actually aligned or `align` is + /// not a power of two. Has no effect when alignment checks are concrete (which is the default). + fn miri_promise_symbolic_alignment(ptr: *const (), align: usize); + } + + const_eval_select!( + @capture { ptr: *const (), align: usize}: + if const { + // Do nothing. + } else { + // SAFETY: this call is always safe. + unsafe { + miri_promise_symbolic_alignment(ptr, align); + } + } + ) +} diff --git a/core/src/io/borrowed_buf.rs b/core/src/io/borrowed_buf.rs index dbc60aa8154c6..4227e503ba7ba 100644 --- a/core/src/io/borrowed_buf.rs +++ b/core/src/io/borrowed_buf.rs @@ -108,6 +108,26 @@ impl<'data> BorrowedBuf<'data> { } } + /// Returns a shared reference to the filled portion of the buffer with its original lifetime. + #[inline] + pub fn into_filled(self) -> &'data [u8] { + // SAFETY: We only slice the filled part of the buffer, which is always valid + unsafe { + let buf = self.buf.get_unchecked(..self.filled); + MaybeUninit::slice_assume_init_ref(buf) + } + } + + /// Returns a mutable reference to the filled portion of the buffer with its original lifetime. + #[inline] + pub fn into_filled_mut(self) -> &'data mut [u8] { + // SAFETY: We only slice the filled part of the buffer, which is always valid + unsafe { + let buf = self.buf.get_unchecked_mut(..self.filled); + MaybeUninit::slice_assume_init_mut(buf) + } + } + /// Returns a cursor over the unfilled part of the buffer. #[inline] pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> { diff --git a/core/src/iter/range.rs b/core/src/iter/range.rs index da4f68a0de4fb..4fa719de5ebf0 100644 --- a/core/src/iter/range.rs +++ b/core/src/iter/range.rs @@ -22,23 +22,21 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6 /// The *predecessor* operation moves towards values that compare lesser. #[unstable(feature = "step_trait", issue = "42168")] pub trait Step: Clone + PartialOrd + Sized { - /// Returns the number of *successor* steps required to get from `start` to `end`. + /// Returns the bounds on the number of *successor* steps required to get from `start` to `end` + /// like [`Iterator::size_hint()`][Iterator::size_hint()]. /// - /// Returns `None` if the number of steps would overflow `usize` - /// (or is infinite, or if `end` would never be reached). + /// Returns `(usize::MAX, None)` if the number of steps would overflow `usize`, or is infinite. /// /// # Invariants /// /// For any `a`, `b`, and `n`: /// - /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::forward_checked(&a, n) == Some(b)` - /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::backward_checked(&b, n) == Some(a)` - /// * `steps_between(&a, &b) == Some(n)` only if `a <= b` - /// * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b` - /// * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`; - /// this is the case when it would require more than `usize::MAX` steps to get to `b` - /// * `steps_between(&a, &b) == None` if `a > b` - fn steps_between(start: &Self, end: &Self) -> Option; + /// * `steps_between(&a, &b) == (n, Some(n))` if and only if `Step::forward_checked(&a, n) == Some(b)` + /// * `steps_between(&a, &b) == (n, Some(n))` if and only if `Step::backward_checked(&b, n) == Some(a)` + /// * `steps_between(&a, &b) == (n, Some(n))` only if `a <= b` + /// * Corollary: `steps_between(&a, &b) == (0, Some(0))` if and only if `a == b` + /// * `steps_between(&a, &b) == (0, None)` if `a > b` + fn steps_between(start: &Self, end: &Self) -> (usize, Option); /// Returns the value that would be obtained by taking the *successor* /// of `self` `count` times. @@ -169,7 +167,7 @@ pub trait Step: Clone + PartialOrd + Sized { /// For any `a`: /// /// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)` - /// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`, + /// * if there exists `b`, `n` such that `steps_between(&b, &a) == (n, Some(n))`, /// it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`. /// * Corollary: `Step::backward_unchecked(a, 0)` is always safe. /// @@ -261,12 +259,13 @@ macro_rules! step_integer_impls { step_unsigned_methods!(); #[inline] - fn steps_between(start: &Self, end: &Self) -> Option { + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { if *start <= *end { // This relies on $u_narrower <= usize - Some((*end - *start) as usize) + let steps = (*end - *start) as usize; + (steps, Some(steps)) } else { - None + (0, None) } } @@ -294,16 +293,17 @@ macro_rules! step_integer_impls { step_signed_methods!($u_narrower); #[inline] - fn steps_between(start: &Self, end: &Self) -> Option { + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { if *start <= *end { // This relies on $i_narrower <= usize // // Casting to isize extends the width but preserves the sign. // Use wrapping_sub in isize space and cast to usize to compute // the difference that might not fit inside the range of isize. - Some((*end as isize).wrapping_sub(*start as isize) as usize) + let steps = (*end as isize).wrapping_sub(*start as isize) as usize; + (steps, Some(steps)) } else { - None + (0, None) } } @@ -359,11 +359,15 @@ macro_rules! step_integer_impls { step_unsigned_methods!(); #[inline] - fn steps_between(start: &Self, end: &Self) -> Option { + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { if *start <= *end { - usize::try_from(*end - *start).ok() + if let Ok(steps) = usize::try_from(*end - *start) { + (steps, Some(steps)) + } else { + (usize::MAX, None) + } } else { - None + (0, None) } } @@ -385,16 +389,22 @@ macro_rules! step_integer_impls { step_signed_methods!($u_wider); #[inline] - fn steps_between(start: &Self, end: &Self) -> Option { + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { if *start <= *end { match end.checked_sub(*start) { - Some(result) => usize::try_from(result).ok(), + Some(result) => { + if let Ok(steps) = usize::try_from(result) { + (steps, Some(steps)) + } else { + (usize::MAX, None) + } + } // If the difference is too big for e.g. i128, // it's also gonna be too big for usize with fewer bits. - None => None, + None => (usize::MAX, None), } } else { - None + (0, None) } } @@ -433,18 +443,26 @@ step_integer_impls! { #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] impl Step for char { #[inline] - fn steps_between(&start: &char, &end: &char) -> Option { + fn steps_between(&start: &char, &end: &char) -> (usize, Option) { let start = start as u32; let end = end as u32; if start <= end { let count = end - start; if start < 0xD800 && 0xE000 <= end { - usize::try_from(count - 0x800).ok() + if let Ok(steps) = usize::try_from(count - 0x800) { + (steps, Some(steps)) + } else { + (usize::MAX, None) + } } else { - usize::try_from(count).ok() + if let Ok(steps) = usize::try_from(count) { + (steps, Some(steps)) + } else { + (usize::MAX, None) + } } } else { - None + (0, None) } } @@ -512,7 +530,7 @@ impl Step for char { #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] impl Step for AsciiChar { #[inline] - fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> Option { + fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> (usize, Option) { Step::steps_between(&start.to_u8(), &end.to_u8()) } @@ -554,7 +572,7 @@ impl Step for AsciiChar { #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] impl Step for Ipv4Addr { #[inline] - fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> Option { + fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> (usize, Option) { u32::steps_between(&start.to_bits(), &end.to_bits()) } @@ -586,7 +604,7 @@ impl Step for Ipv4Addr { #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] impl Step for Ipv6Addr { #[inline] - fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> Option { + fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> (usize, Option) { u128::steps_between(&start.to_bits(), &end.to_bits()) } @@ -690,11 +708,8 @@ impl RangeIteratorImpl for ops::Range { #[inline] default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero> { - let available = if self.start <= self.end { - Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) - } else { - 0 - }; + let steps = Step::steps_between(&self.start, &self.end); + let available = steps.1.unwrap_or(steps.0); let taken = available.min(n); @@ -731,11 +746,8 @@ impl RangeIteratorImpl for ops::Range { #[inline] default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - let available = if self.start <= self.end { - Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) - } else { - 0 - }; + let steps = Step::steps_between(&self.start, &self.end); + let available = steps.1.unwrap_or(steps.0); let taken = available.min(n); @@ -775,11 +787,8 @@ impl RangeIteratorImpl for ops::Range { #[inline] fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero> { - let available = if self.start <= self.end { - Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) - } else { - 0 - }; + let steps = Step::steps_between(&self.start, &self.end); + let available = steps.1.unwrap_or(steps.0); let taken = available.min(n); @@ -819,11 +828,8 @@ impl RangeIteratorImpl for ops::Range { #[inline] fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - let available = if self.start <= self.end { - Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) - } else { - 0 - }; + let steps = Step::steps_between(&self.start, &self.end); + let available = steps.1.unwrap_or(steps.0); let taken = available.min(n); @@ -846,8 +852,7 @@ impl Iterator for ops::Range { #[inline] fn size_hint(&self) -> (usize, Option) { if self.start < self.end { - let hint = Step::steps_between(&self.start, &self.end); - (hint.unwrap_or(usize::MAX), hint) + Step::steps_between(&self.start, &self.end) } else { (0, Some(0)) } @@ -856,7 +861,7 @@ impl Iterator for ops::Range { #[inline] fn count(self) -> usize { if self.start < self.end { - Step::steps_between(&self.start, &self.end).expect("count overflowed usize") + Step::steps_between(&self.start, &self.end).1.expect("count overflowed usize") } else { 0 } @@ -980,11 +985,11 @@ impl DoubleEndedIterator for ops::Range { // Safety: // The following invariants for `Step::steps_between` exist: // -// > * `steps_between(&a, &b) == Some(n)` only if `a <= b` -// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`; +// > * `steps_between(&a, &b) == (n, Some(n))` only if `a <= b` +// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != (n, None)`; // > this is the case when it would require more than `usize::MAX` steps to // > get to `b` -// > * `steps_between(&a, &b) == None` if `a > b` +// > * `steps_between(&a, &b) == (0, None)` if `a > b` // // The first invariant is what is generally required for `TrustedLen` to be // sound. The note addendum satisfies an additional `TrustedLen` invariant. @@ -1253,10 +1258,8 @@ impl Iterator for ops::RangeInclusive { return (0, Some(0)); } - match Step::steps_between(&self.start, &self.end) { - Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), - None => (usize::MAX, None), - } + let hint = Step::steps_between(&self.start, &self.end); + (hint.0.saturating_add(1), hint.1.and_then(|steps| steps.checked_add(1))) } #[inline] @@ -1266,6 +1269,7 @@ impl Iterator for ops::RangeInclusive { } Step::steps_between(&self.start, &self.end) + .1 .and_then(|steps| steps.checked_add(1)) .expect("count overflowed usize") } diff --git a/core/src/lib.rs b/core/src/lib.rs index 115fdd7a14024..a178d10125477 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -107,49 +107,35 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_exact_div))] #![cfg_attr(bootstrap, feature(const_fmt_arguments_new))] +#![cfg_attr(bootstrap, feature(const_ub_checks))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] -#![feature(const_align_offset)] #![feature(const_alloc_layout)] -#![feature(const_arguments_as_str)] -#![feature(const_array_into_iter_constructors)] -#![feature(const_bigint_helper_methods)] #![feature(const_black_box)] -#![feature(const_char_encode_utf16)] +#![feature(const_eq_ignore_ascii_case)] #![feature(const_eval_select)] -#![feature(const_exact_div)] -#![feature(const_float_methods)] -#![feature(const_hash)] #![feature(const_heap)] #![feature(const_nonnull_new)] -#![feature(const_num_midpoint)] -#![feature(const_option_ext)] -#![feature(const_pin_2)] -#![feature(const_pointer_is_aligned)] -#![feature(const_ptr_is_null)] #![feature(const_ptr_sub_ptr)] #![feature(const_raw_ptr_comparison)] #![feature(const_size_of_val)] #![feature(const_size_of_val_raw)] #![feature(const_sockaddr_setters)] -#![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] #![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_typed_swap)] -#![feature(const_ub_checks)] -#![feature(const_unicode_case_lookup)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] -#![feature(is_val_statically_known)] #![feature(lazy_get)] #![feature(link_cfg)] #![feature(non_null_from_ref)] @@ -167,7 +153,6 @@ #![feature(unchecked_neg)] #![feature(unchecked_shifts)] #![feature(utf16_extra)] -#![feature(utf16_extra_const)] #![feature(variant_count)] // tidy-alphabetical-end // @@ -188,6 +173,7 @@ #![feature(const_is_char_boundary)] #![feature(const_precise_live_drops)] #![feature(const_str_split_at)] +#![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] diff --git a/core/src/marker.rs b/core/src/marker.rs index 1c5c58d64a2b2..acbad07746bb9 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -953,7 +953,7 @@ marker_impls! { /// /// This should be used for `~const` bounds, /// as non-const bounds will always hold for every type. -#[unstable(feature = "const_trait_impl", issue = "67792")] +#[unstable(feature = "const_destruct", issue = "133214")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[rustc_deny_explicit_impl(implement_via_object = false)] @@ -981,6 +981,18 @@ pub trait Tuple {} )] pub trait PointerLike {} +#[cfg(not(bootstrap))] +marker_impls! { + #[unstable(feature = "pointer_like_trait", issue = "none")] + PointerLike for + usize, + {T} &T, + {T} &mut T, + {T} *const T, + {T} *mut T, + {T: PointerLike} crate::pin::Pin, +} + /// A marker for types which can be used as types of `const` generic parameters. /// /// These types must have a proper equivalence relation (`Eq`) and it must be automatically diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index a57e265c7cc00..58315cb74f0a1 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -338,7 +338,6 @@ impl MaybeUninit { /// let data = read(&mut buf); /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "96097")] - #[rustc_const_unstable(feature = "const_maybe_uninit_uninit_array", issue = "96097")] #[must_use] #[inline(always)] pub const fn uninit_array() -> [Self; N] { @@ -526,6 +525,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] pub const fn as_ptr(&self) -> *const T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. @@ -567,6 +567,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_mut_ptr", since = "1.83.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. @@ -946,7 +947,6 @@ impl MaybeUninit { /// assert_eq!(array, [0, 1, 2]); /// ``` #[unstable(feature = "maybe_uninit_array_assume_init", issue = "96097")] - #[rustc_const_unstable(feature = "const_maybe_uninit_array_assume_init", issue = "96097")] #[inline(always)] #[track_caller] pub const unsafe fn array_assume_init(array: [Self; N]) -> [T; N] { @@ -973,7 +973,6 @@ impl MaybeUninit { /// /// [`assume_init_ref`]: MaybeUninit::assume_init_ref #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that @@ -995,7 +994,6 @@ impl MaybeUninit { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a @@ -1005,7 +1003,6 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T @@ -1013,7 +1010,6 @@ impl MaybeUninit { /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T diff --git a/core/src/net/ip_addr.rs b/core/src/net/ip_addr.rs index 0d1f4a9ea3eed..6746f0b2b316b 100644 --- a/core/src/net/ip_addr.rs +++ b/core/src/net/ip_addr.rs @@ -373,7 +373,6 @@ impl IpAddr { /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); /// ``` #[unstable(feature = "ip", issue = "27709")] - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[must_use] #[inline] pub const fn is_benchmarking(&self) -> bool { @@ -1595,16 +1594,15 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); /// ``` - #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] + #[stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")] pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } @@ -1666,8 +1664,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// // The loopback address (`::1`) does not actually have link-local scope. @@ -1681,9 +1677,10 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); /// ``` - #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] + #[stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")] pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } diff --git a/core/src/num/dec2flt/mod.rs b/core/src/num/dec2flt/mod.rs index 87bfd0d256634..6dca740684537 100644 --- a/core/src/num/dec2flt/mod.rs +++ b/core/src/num/dec2flt/mod.rs @@ -58,7 +58,7 @@ //! //! There are unit tests but they are woefully inadequate at ensuring correctness, they only cover //! a small percentage of possible errors. Far more extensive tests are located in the directory -//! `src/etc/test-float-parse` as a Python script. +//! `src/etc/test-float-parse` as a Rust program. //! //! A note on integer overflow: Many parts of this file perform arithmetic with the decimal //! exponent `e`. Primarily, we shift the decimal point around: Before the first decimal digit, diff --git a/core/src/num/f128.rs b/core/src/num/f128.rs index e8161cce2fe29..abeccb7eea248 100644 --- a/core/src/num/f128.rs +++ b/core/src/num/f128.rs @@ -16,6 +16,7 @@ use crate::convert::FloatToInt; use crate::intrinsics; use crate::mem; use crate::num::FpCategory; +use crate::panic::const_assert; /// Basic mathematical constants. #[unstable(feature = "f128", issue = "116909")] @@ -284,17 +285,6 @@ impl f128 { self != self } - // FIXME(#50145): `abs` is publicly unavailable in core due to - // concerns about portability, so this implementation is for - // private use internally. - #[inline] - pub(crate) const fn abs_private(self) -> f128 { - // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. - unsafe { - mem::transmute::(mem::transmute::(self) & !Self::SIGN_MASK) - } - } - /// Returns `true` if this value is positive infinity or negative infinity, and /// `false` otherwise. /// @@ -344,10 +334,11 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. - self.abs_private() < Self::INFINITY + self.abs() < Self::INFINITY } /// Returns `true` if the number is [subnormal]. @@ -621,7 +612,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn recip(self) -> Self { 1.0 / self @@ -642,7 +632,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_degrees(self) -> Self { // Use a literal for better precision. @@ -666,7 +655,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_radians(self) -> f128 { // Use a literal for better precision. @@ -695,7 +683,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn max(self, other: f128) -> f128 { intrinsics::maxnumf128(self, other) @@ -721,7 +709,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn min(self, other: f128) -> f128 { intrinsics::minnumf128(self, other) @@ -835,8 +823,8 @@ impl f128 { const HI: f128 = f128::MAX / 2.; let (a, b) = (self, other); - let abs_a = a.abs_private(); - let abs_b = b.abs_private(); + let abs_a = a.abs(); + let abs_b = b.abs(); if abs_a <= HI && abs_b <= HI { // Overflow is impossible @@ -1260,20 +1248,16 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn clamp(mut self, min: f128, max: f128) -> f128 { - #[inline] // inline to avoid LLVM crash - const fn assert_at_const(min: f128, max: f128) { - // Note that we cannot format in constant expressions. - assert!(min <= max, "min > max, or either was NaN"); - } - #[inline] // inline to avoid codegen regression - fn assert_at_rt(min: f128, max: f128) { - assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); - } - // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. - intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt); + const_assert!( + min <= max, + "min > max, or either was NaN", + "min > max, or either was NaN. min = {min:?}, max = {max:?}", + min: f128, + max: f128, + ); + if self < min { self = min; } @@ -1282,4 +1266,100 @@ impl f128 { } self } + + /// Computes the absolute value of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let x = 3.5_f128; + /// let y = -3.5_f128; + /// + /// assert_eq!(x.abs(), x); + /// assert_eq!(y.abs(), -y); + /// + /// assert!(f128::NAN.abs().is_nan()); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn abs(self) -> Self { + // FIXME(f16_f128): replace with `intrinsics::fabsf128` when available + // We don't do this now because LLVM has lowering bugs for f128 math. + Self::from_bits(self.to_bits() & !(1 << 127)) + } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - NaN if the number is NaN + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let f = 3.5_f128; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f128::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f128::NAN.signum().is_nan()); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn signum(self) -> f128 { + if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) } + } + + /// Returns a number composed of the magnitude of `self` and the sign of + /// `sign`. + /// + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. + /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is + /// returned. + /// + /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note + /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust + /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the + /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable + /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more + /// info. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let f = 3.5_f128; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f128); + /// assert_eq!(f.copysign(-0.42), -3.5_f128); + /// assert_eq!((-f).copysign(0.42), 3.5_f128); + /// assert_eq!((-f).copysign(-0.42), -3.5_f128); + /// + /// assert!(f128::NAN.copysign(1.0).is_nan()); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn copysign(self, sign: f128) -> f128 { + // SAFETY: this is actually a safe intrinsic + unsafe { intrinsics::copysignf128(self, sign) } + } } diff --git a/core/src/num/f16.rs b/core/src/num/f16.rs index 8b3f3b7d19bf7..0d3e92695707c 100644 --- a/core/src/num/f16.rs +++ b/core/src/num/f16.rs @@ -16,6 +16,7 @@ use crate::convert::FloatToInt; use crate::intrinsics; use crate::mem; use crate::num::FpCategory; +use crate::panic::const_assert; /// Basic mathematical constants. #[unstable(feature = "f16", issue = "116909")] @@ -278,15 +279,6 @@ impl f16 { self != self } - // FIXMxE(#50145): `abs` is publicly unavailable in core due to - // concerns about portability, so this implementation is for - // private use internally. - #[inline] - pub(crate) const fn abs_private(self) -> f16 { - // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. - unsafe { mem::transmute::(mem::transmute::(self) & !Self::SIGN_MASK) } - } - /// Returns `true` if this value is positive infinity or negative infinity, and /// `false` otherwise. /// @@ -334,10 +326,11 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. - self.abs_private() < Self::INFINITY + self.abs() < Self::INFINITY } /// Returns `true` if the number is [subnormal]. @@ -612,7 +605,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn recip(self) -> Self { 1.0 / self @@ -633,7 +625,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_degrees(self) -> Self { // Use a literal for better precision. @@ -657,7 +648,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_radians(self) -> f16 { // Use a literal for better precision. @@ -684,7 +674,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn max(self, other: f16) -> f16 { intrinsics::maxnumf16(self, other) @@ -709,7 +699,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn min(self, other: f16) -> f16 { intrinsics::minnumf16(self, other) @@ -820,8 +810,8 @@ impl f16 { const HI: f16 = f16::MAX / 2.; let (a, b) = (self, other); - let abs_a = a.abs_private(); - let abs_b = b.abs_private(); + let abs_a = a.abs(); + let abs_b = b.abs(); if abs_a <= HI && abs_b <= HI { // Overflow is impossible @@ -1235,20 +1225,16 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn clamp(mut self, min: f16, max: f16) -> f16 { - #[inline] // inline to avoid LLVM crash - const fn assert_at_const(min: f16, max: f16) { - // Note that we cannot format in constant expressions. - assert!(min <= max, "min > max, or either was NaN"); - } - #[inline] // inline to avoid codegen regression - fn assert_at_rt(min: f16, max: f16) { - assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); - } - // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. - intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt); + const_assert!( + min <= max, + "min > max, or either was NaN", + "min > max, or either was NaN. min = {min:?}, max = {max:?}", + min: f16, + max: f16, + ); + if self < min { self = min; } @@ -1257,4 +1243,99 @@ impl f16 { } self } + + /// Computes the absolute value of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let x = 3.5_f16; + /// let y = -3.5_f16; + /// + /// assert_eq!(x.abs(), x); + /// assert_eq!(y.abs(), -y); + /// + /// assert!(f16::NAN.abs().is_nan()); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn abs(self) -> Self { + // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available + Self::from_bits(self.to_bits() & !(1 << 15)) + } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - NaN if the number is NaN + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let f = 3.5_f16; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f16::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f16::NAN.signum().is_nan()); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn signum(self) -> f16 { + if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) } + } + + /// Returns a number composed of the magnitude of `self` and the sign of + /// `sign`. + /// + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. + /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is + /// returned. + /// + /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note + /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust + /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the + /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable + /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more + /// info. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let f = 3.5_f16; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f16); + /// assert_eq!(f.copysign(-0.42), -3.5_f16); + /// assert_eq!((-f).copysign(0.42), 3.5_f16); + /// assert_eq!((-f).copysign(-0.42), -3.5_f16); + /// + /// assert!(f16::NAN.copysign(1.0).is_nan()); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn copysign(self, sign: f16) -> f16 { + // SAFETY: this is actually a safe intrinsic + unsafe { intrinsics::copysignf16(self, sign) } + } } diff --git a/core/src/num/f32.rs b/core/src/num/f32.rs index a01761ee5d4a3..47dfce7530fb7 100644 --- a/core/src/num/f32.rs +++ b/core/src/num/f32.rs @@ -16,6 +16,7 @@ use crate::convert::FloatToInt; use crate::intrinsics; use crate::mem; use crate::num::FpCategory; +use crate::panic::const_assert; /// The radix or base of the internal representation of `f32`. /// Use [`f32::RADIX`] instead. @@ -524,15 +525,6 @@ impl f32 { self != self } - // FIXME(#50145): `abs` is publicly unavailable in core due to - // concerns about portability, so this implementation is for - // private use internally. - #[inline] - pub(crate) const fn abs_private(self) -> f32 { - // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. - unsafe { mem::transmute::(mem::transmute::(self) & !Self::SIGN_MASK) } - } - /// Returns `true` if this value is positive infinity or negative infinity, and /// `false` otherwise. /// @@ -580,7 +572,7 @@ impl f32 { pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. - self.abs_private() < Self::INFINITY + self.abs() < Self::INFINITY } /// Returns `true` if the number is [subnormal]. @@ -748,7 +740,6 @@ impl f32 { /// [`MAX`]: Self::MAX #[inline] #[unstable(feature = "float_next_up_down", issue = "91399")] - #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -797,7 +788,6 @@ impl f32 { /// [`MAX`]: Self::MAX #[inline] #[unstable(feature = "float_next_up_down", issue = "91399")] - #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -828,7 +818,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the operation, without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn recip(self) -> f32 { 1.0 / self @@ -846,7 +836,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_degrees(self) -> f32 { // Use a constant for better precision. @@ -866,7 +856,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_radians(self) -> f32 { const RADS_PER_DEG: f32 = consts::PI / 180.0; @@ -888,7 +878,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn max(self, other: f32) -> f32 { intrinsics::maxnumf32(self, other) @@ -909,7 +899,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn min(self, other: f32) -> f32 { intrinsics::minnumf32(self, other) @@ -1020,8 +1010,8 @@ impl f32 { const HI: f32 = f32::MAX / 2.; let (a, b) = (self, other); - let abs_a = a.abs_private(); - let abs_b = b.abs_private(); + let abs_a = a.abs(); + let abs_b = b.abs(); if abs_a <= HI && abs_b <= HI { // Overflow is impossible @@ -1406,19 +1396,17 @@ impl f32 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn clamp(mut self, min: f32, max: f32) -> f32 { - const fn assert_at_const(min: f32, max: f32) { - // Note that we cannot format in constant expressions. - assert!(min <= max, "min > max, or either was NaN"); - } - #[inline] // inline to avoid codegen regression - fn assert_at_rt(min: f32, max: f32) { - assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); - } - // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. - intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt); + const_assert!( + min <= max, + "min > max, or either was NaN", + "min > max, or either was NaN. min = {min:?}, max = {max:?}", + min: f32, + max: f32, + ); + if self < min { self = min; } @@ -1427,4 +1415,87 @@ impl f32 { } self } + + /// Computes the absolute value of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// let x = 3.5_f32; + /// let y = -3.5_f32; + /// + /// assert_eq!(x.abs(), x); + /// assert_eq!(y.abs(), -y); + /// + /// assert!(f32::NAN.abs().is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[inline] + pub const fn abs(self) -> f32 { + // SAFETY: this is actually a safe intrinsic + unsafe { intrinsics::fabsf32(self) } + } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - NaN if the number is NaN + /// + /// # Examples + /// + /// ``` + /// let f = 3.5_f32; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f32::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f32::NAN.signum().is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[inline] + pub const fn signum(self) -> f32 { + if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) } + } + + /// Returns a number composed of the magnitude of `self` and the sign of + /// `sign`. + /// + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. + /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is + /// returned. + /// + /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note + /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust + /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the + /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable + /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more + /// info. + /// + /// # Examples + /// + /// ``` + /// let f = 3.5_f32; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f32); + /// assert_eq!(f.copysign(-0.42), -3.5_f32); + /// assert_eq!((-f).copysign(0.42), 3.5_f32); + /// assert_eq!((-f).copysign(-0.42), -3.5_f32); + /// + /// assert!(f32::NAN.copysign(1.0).is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[inline] + #[stable(feature = "copysign", since = "1.35.0")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + pub const fn copysign(self, sign: f32) -> f32 { + // SAFETY: this is actually a safe intrinsic + unsafe { intrinsics::copysignf32(self, sign) } + } } diff --git a/core/src/num/f64.rs b/core/src/num/f64.rs index 2995e41cd6ea0..c89023c1ae490 100644 --- a/core/src/num/f64.rs +++ b/core/src/num/f64.rs @@ -16,6 +16,7 @@ use crate::convert::FloatToInt; use crate::intrinsics; use crate::mem; use crate::num::FpCategory; +use crate::panic::const_assert; /// The radix or base of the internal representation of `f64`. /// Use [`f64::RADIX`] instead. @@ -523,15 +524,6 @@ impl f64 { self != self } - // FIXME(#50145): `abs` is publicly unavailable in core due to - // concerns about portability, so this implementation is for - // private use internally. - #[inline] - pub(crate) const fn abs_private(self) -> f64 { - // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. - unsafe { mem::transmute::(mem::transmute::(self) & !Self::SIGN_MASK) } - } - /// Returns `true` if this value is positive infinity or negative infinity, and /// `false` otherwise. /// @@ -579,7 +571,7 @@ impl f64 { pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. - self.abs_private() < Self::INFINITY + self.abs() < Self::INFINITY } /// Returns `true` if the number is [subnormal]. @@ -765,7 +757,6 @@ impl f64 { /// [`MAX`]: Self::MAX #[inline] #[unstable(feature = "float_next_up_down", issue = "91399")] - #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -814,7 +805,6 @@ impl f64 { /// [`MAX`]: Self::MAX #[inline] #[unstable(feature = "float_next_up_down", issue = "91399")] - #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -845,7 +835,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the operation, without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn recip(self) -> f64 { 1.0 / self @@ -863,7 +853,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_degrees(self) -> f64 { // The division here is correctly rounded with respect to the true @@ -884,7 +874,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn to_radians(self) -> f64 { const RADS_PER_DEG: f64 = consts::PI / 180.0; @@ -906,7 +896,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn max(self, other: f64) -> f64 { intrinsics::maxnumf64(self, other) @@ -927,7 +917,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn min(self, other: f64) -> f64 { intrinsics::minnumf64(self, other) @@ -1023,8 +1013,8 @@ impl f64 { const HI: f64 = f64::MAX / 2.; let (a, b) = (self, other); - let abs_a = a.abs_private(); - let abs_b = b.abs_private(); + let abs_a = a.abs(); + let abs_b = b.abs(); if abs_a <= HI && abs_b <= HI { // Overflow is impossible @@ -1406,19 +1396,17 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn clamp(mut self, min: f64, max: f64) -> f64 { - const fn assert_at_const(min: f64, max: f64) { - // Note that we cannot format in constant expressions. - assert!(min <= max, "min > max, or either was NaN"); - } - #[inline] // inline to avoid codegen regression - fn assert_at_rt(min: f64, max: f64) { - assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); - } - // FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly. - intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt); + const_assert!( + min <= max, + "min > max, or either was NaN", + "min > max, or either was NaN. min = {min:?}, max = {max:?}", + min: f64, + max: f64, + ); + if self < min { self = min; } @@ -1427,4 +1415,87 @@ impl f64 { } self } + + /// Computes the absolute value of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// let x = 3.5_f64; + /// let y = -3.5_f64; + /// + /// assert_eq!(x.abs(), x); + /// assert_eq!(y.abs(), -y); + /// + /// assert!(f64::NAN.abs().is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[inline] + pub const fn abs(self) -> f64 { + // SAFETY: this is actually a safe intrinsic + unsafe { intrinsics::fabsf64(self) } + } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - NaN if the number is NaN + /// + /// # Examples + /// + /// ``` + /// let f = 3.5_f64; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f64::NAN.signum().is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[inline] + pub const fn signum(self) -> f64 { + if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) } + } + + /// Returns a number composed of the magnitude of `self` and the sign of + /// `sign`. + /// + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. + /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is + /// returned. + /// + /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note + /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust + /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the + /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable + /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more + /// info. + /// + /// # Examples + /// + /// ``` + /// let f = 3.5_f64; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f64); + /// assert_eq!(f.copysign(-0.42), -3.5_f64); + /// assert_eq!((-f).copysign(0.42), 3.5_f64); + /// assert_eq!((-f).copysign(-0.42), -3.5_f64); + /// + /// assert!(f64::NAN.copysign(1.0).is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "copysign", since = "1.35.0")] + #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[inline] + pub const fn copysign(self, sign: f64) -> f64 { + // SAFETY: this is actually a safe intrinsic + unsafe { intrinsics::copysignf64(self, sign) } + } } diff --git a/core/src/num/int_macros.rs b/core/src/num/int_macros.rs index 72adb1bf19019..64dcb4c91e628 100644 --- a/core/src/num/int_macros.rs +++ b/core/src/num/int_macros.rs @@ -477,7 +477,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -573,7 +572,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -629,7 +627,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -725,7 +722,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -781,7 +777,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -895,7 +890,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -969,7 +963,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1042,7 +1035,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1115,7 +1107,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1203,7 +1194,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] /// #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1266,7 +1256,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1311,7 +1300,7 @@ macro_rules! int_impl { } } - /// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs` + /// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs`. /// /// If `rhs` is larger or equal to the number of bits in `self`, /// the entire value is shifted out, and `0` is returned. @@ -1325,7 +1314,6 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` #[unstable(feature = "unbounded_shifts", issue = "129375")] - #[rustc_const_unstable(feature = "const_unbounded_shifts", issue = "129375")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1391,7 +1379,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1436,7 +1423,7 @@ macro_rules! int_impl { } } - /// Unbounded shift right. Computes `self >> rhs`, without bounding the value of `rhs` + /// Unbounded shift right. Computes `self >> rhs`, without bounding the value of `rhs`. /// /// If `rhs` is larger or equal to the number of bits in `self`, /// the entire value is shifted out, which yields `0` for a positive number, @@ -1452,7 +1439,6 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")] /// ``` #[unstable(feature = "unbounded_shifts", issue = "129375")] - #[rustc_const_unstable(feature = "const_unbounded_shifts", issue = "129375")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1519,7 +1505,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1594,7 +1579,6 @@ macro_rules! int_impl { #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2117,6 +2101,7 @@ macro_rules! int_impl { /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100);")] + #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").wrapping_neg(), 100);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), "::MIN);")] /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] @@ -2258,7 +2243,6 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn wrapping_pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; @@ -2368,7 +2352,6 @@ macro_rules! int_impl { /// assert_eq!((sum1, sum0), (6, 8)); /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2406,7 +2389,7 @@ macro_rules! int_impl { (res, overflowed ^ (rhs < 0)) } - /// Calculates `self` - `rhs` + /// Calculates `self` - `rhs`. /// /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow /// would occur. If an overflow would have occurred then the wrapped value is returned. @@ -2476,7 +2459,6 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((diff1, diff0), (10, ", stringify!($UnsignedT), "::MAX));")] /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2488,7 +2470,7 @@ macro_rules! int_impl { (c, b != d) } - /// Calculates `self` - `rhs` with an unsigned `rhs` + /// Calculates `self` - `rhs` with an unsigned `rhs`. /// /// Returns a tuple of the subtraction along with a boolean indicating /// whether an arithmetic overflow would occur. If an overflow would @@ -2826,7 +2808,6 @@ macro_rules! int_impl { without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 6a0b40ff51771..9d9897b9cf05e 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -2,6 +2,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::panic::const_panic; use crate::str::FromStr; use crate::ub_checks::assert_unsafe_precondition; use crate::{ascii, intrinsics, mem}; @@ -114,7 +115,6 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] /// ``` #[unstable(feature = "num_midpoint", issue = "110840")] - #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -142,7 +142,6 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` #[unstable(feature = "num_midpoint", issue = "110840")] - #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -170,7 +169,6 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] /// ``` #[unstable(feature = "num_midpoint", issue = "110840")] - #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -196,7 +194,6 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` #[unstable(feature = "num_midpoint", issue = "110840")] - #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -229,7 +226,6 @@ macro_rules! widening_impl { /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2)); /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -320,7 +316,6 @@ macro_rules! widening_impl { /// ); /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -533,7 +528,7 @@ impl isize { midpoint_impl! { isize, signed } } -/// If the 6th bit is set ascii is lower case. +/// If the bit selected by this mask is set, ascii is lower case. const ASCII_CASE_MASK: u8 = 0b0010_0000; impl u8 { @@ -915,7 +910,6 @@ impl u8 { /// ``` #[must_use] #[unstable(feature = "is_ascii_octdigit", issue = "101288")] - #[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")] #[inline] pub const fn is_ascii_octdigit(&self) -> bool { matches!(*self, b'0'..=b'7') @@ -1195,7 +1189,6 @@ impl u16 { /// ``` #[must_use] #[unstable(feature = "utf16_extra", issue = "94919")] - #[rustc_const_unstable(feature = "utf16_extra_const", issue = "94919")] #[inline] pub const fn is_utf16_surrogate(self) -> bool { matches!(self, 0xD800..=0xDFFF) @@ -1440,6 +1433,7 @@ macro_rules! from_str_radix_int_impl { #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for $t { type Err = ParseIntError; + #[inline] fn from_str(src: &str) -> Result { <$t>::from_str_radix(src, 10) } @@ -1460,24 +1454,16 @@ pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } -#[track_caller] -const fn from_str_radix_panic_ct(_radix: u32) -> ! { - panic!("from_str_radix_int: must lie in the range `[2, 36]`"); -} - -#[track_caller] -fn from_str_radix_panic_rt(radix: u32) -> ! { - panic!("from_str_radix_int: must lie in the range `[2, 36]` - found {}", radix); -} - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[cold] #[track_caller] -#[rustc_allow_const_fn_unstable(const_eval_select)] -const fn from_str_radix_panic(radix: u32) { - // The only difference between these two functions is their panic message. - intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt); +const fn from_str_radix_panic(radix: u32) -> ! { + const_panic!( + "from_str_radix_int: must lie in the range `[2, 36]`", + "from_str_radix_int: must lie in the range `[2, 36]` - found {radix}", + radix: u32 = radix, + ) } macro_rules! from_str_radix { @@ -1520,6 +1506,7 @@ macro_rules! from_str_radix { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] + #[inline] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> { use self::IntErrorKind::*; use self::ParseIntError as PIE; @@ -1664,6 +1651,7 @@ macro_rules! from_str_radix_size_impl { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] + #[inline] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> { match <$t>::from_str_radix(src, radix) { Ok(x) => Ok(x as $size), diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index f04c83693ef63..b883a0c2ec7f9 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -110,26 +110,40 @@ impl_zeroable_primitive!( pub struct NonZero(T::NonZeroInner); macro_rules! impl_nonzero_fmt { - ($Trait:ident) => { - #[stable(feature = "nonzero", since = "1.28.0")] - impl fmt::$Trait for NonZero - where - T: ZeroablePrimitive + fmt::$Trait, - { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.get().fmt(f) + ($(#[$Attribute:meta] $Trait:ident)*) => { + $( + #[$Attribute] + impl fmt::$Trait for NonZero + where + T: ZeroablePrimitive + fmt::$Trait, + { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } } - } + )* }; } -impl_nonzero_fmt!(Debug); -impl_nonzero_fmt!(Display); -impl_nonzero_fmt!(Binary); -impl_nonzero_fmt!(Octal); -impl_nonzero_fmt!(LowerHex); -impl_nonzero_fmt!(UpperHex); +impl_nonzero_fmt! { + #[stable(feature = "nonzero", since = "1.28.0")] + Debug + #[stable(feature = "nonzero", since = "1.28.0")] + Display + #[stable(feature = "nonzero", since = "1.28.0")] + Binary + #[stable(feature = "nonzero", since = "1.28.0")] + Octal + #[stable(feature = "nonzero", since = "1.28.0")] + LowerHex + #[stable(feature = "nonzero", since = "1.28.0")] + UpperHex + #[stable(feature = "nonzero_fmt_exp", since = "CURRENT_RUSTC_VERSION")] + LowerExp + #[stable(feature = "nonzero_fmt_exp", since = "CURRENT_RUSTC_VERSION")] + UpperExp +} macro_rules! impl_nonzero_auto_trait { (unsafe $Trait:ident) => { @@ -458,7 +472,15 @@ macro_rules! nonzero_integer { reversed = $reversed:literal, leading_zeros_test = $leading_zeros_test:expr, ) => { - /// An integer that is known not to equal zero. + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + concat!("An [`", stringify!($Int), "`] that is known not to equal zero.") + } + if unsigned { + concat!("A [`", stringify!($Int), "`] that is known not to equal zero.") + } + }] /// /// This enables some memory layout optimization. #[doc = concat!("For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:")] @@ -1192,6 +1214,35 @@ macro_rules! nonzero_integer_signedness_dependent_impls { *self = *self % other; } } + + impl NonZero<$Int> { + /// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity. + /// + /// The result is guaranteed to be non-zero. + /// + /// # Examples + /// + /// ``` + /// # #![feature(unsigned_nonzero_div_ceil)] + /// # use std::num::NonZero; + #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ").unwrap();")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX).unwrap();")] + /// assert_eq!(one.div_ceil(max), one); + /// + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ").unwrap();")] + #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ").unwrap();")] + /// assert_eq!(three.div_ceil(two), two); + /// ``` + #[unstable(feature = "unsigned_nonzero_div_ceil", issue = "132968")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn div_ceil(self, rhs: Self) -> Self { + let v = self.get().div_ceil(rhs.get()); + // SAFETY: ceiled division of two positive integers can never be zero. + unsafe { Self::new_unchecked(v) } + } + } }; // Impls for signed nonzero types only. (signed $Int:ty) => { @@ -1474,7 +1525,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # } /// ``` #[unstable(feature = "num_midpoint", issue = "110840")] - #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index ded8997c634ed..0383c13fa082d 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -524,7 +524,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -626,7 +625,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_signed(3);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -691,7 +689,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -766,6 +763,33 @@ macro_rules! uint_impl { } } + /// Checked subtraction with a signed integer. Computes `self - rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(mixed_integer_ops_unsigned_sub)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(2), None);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(-2), Some(3));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_sub_signed(-4), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub_signed(self, rhs: $SignedT) -> Option { + let (res, overflow) = self.overflowing_sub_signed(rhs); + + if !overflow { + Some(res) + } else { + None + } + } + #[doc = concat!( "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`", stringify!($SignedT), "`], returning `None` if overflow occurred." @@ -873,7 +897,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -975,7 +998,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1035,7 +1057,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1097,7 +1118,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1159,7 +1179,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1392,7 +1411,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] /// #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1455,7 +1473,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1500,7 +1517,7 @@ macro_rules! uint_impl { } } - /// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs` + /// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs`. /// /// If `rhs` is larger or equal to the number of bits in `self`, /// the entire value is shifted out, and `0` is returned. @@ -1514,7 +1531,6 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` #[unstable(feature = "unbounded_shifts", issue = "129375")] - #[rustc_const_unstable(feature = "const_unbounded_shifts", issue = "129375")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1580,7 +1596,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1625,7 +1640,7 @@ macro_rules! uint_impl { } } - /// Unbounded shift right. Computes `self >> rhs`, without bounding the value of `rhs` + /// Unbounded shift right. Computes `self >> rhs`, without bounding the value of `rhs`. /// /// If `rhs` is larger or equal to the number of bits in `self`, /// the entire value is shifted out, and `0` is returned. @@ -1639,7 +1654,6 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] /// ``` #[unstable(feature = "unbounded_shifts", issue = "129375")] - #[rustc_const_unstable(feature = "const_unbounded_shifts", issue = "129375")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1714,7 +1728,6 @@ macro_rules! uint_impl { #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] - #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1807,6 +1820,35 @@ macro_rules! uint_impl { intrinsics::saturating_sub(self, rhs) } + /// Saturating integer subtraction. Computes `self` - `rhs`, saturating at + /// the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(mixed_integer_ops_unsigned_sub)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(2), 0);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(-2), 3);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_sub_signed(-4), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_sub_signed(self, rhs: $SignedT) -> Self { + let (res, overflow) = self.overflowing_sub_signed(rhs); + + if !overflow { + res + } else if rhs < 0 { + Self::MAX + } else { + 0 + } + } + /// Saturating integer multiplication. Computes `self * rhs`, /// saturating at the numeric bounds instead of overflowing. /// @@ -1940,6 +1982,27 @@ macro_rules! uint_impl { intrinsics::wrapping_sub(self, rhs) } + /// Wrapping (modular) subtraction with a signed integer. Computes + /// `self - rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(mixed_integer_ops_unsigned_sub)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(2), ", stringify!($SelfT), "::MAX);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(-2), 3);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_sub_signed(-4), 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_sub_signed(self, rhs: $SignedT) -> Self { + self.wrapping_sub(rhs as Self) + } + /// Wrapping (modular) multiplication. Computes `self * /// rhs`, wrapping around at the boundary of the type. /// @@ -2188,7 +2251,6 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn wrapping_pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; @@ -2236,7 +2298,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")] @@ -2290,7 +2352,6 @@ macro_rules! uint_impl { /// assert_eq!((sum1, sum0), (9, 6)); /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2327,7 +2388,7 @@ macro_rules! uint_impl { (res, overflowed ^ (rhs < 0)) } - /// Calculates `self` - `rhs` + /// Calculates `self` - `rhs`. /// /// Returns a tuple of the subtraction along with a boolean indicating /// whether an arithmetic overflow would occur. If an overflow would @@ -2335,7 +2396,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")] @@ -2382,7 +2443,6 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!((diff1, diff0), (3, ", stringify!($SelfT), "::MAX));")] /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2394,6 +2454,32 @@ macro_rules! uint_impl { (c, b || d) } + /// Calculates `self` - `rhs` with a signed `rhs` + /// + /// Returns a tuple of the subtraction along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(mixed_integer_ops_unsigned_sub)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(2), (", stringify!($SelfT), "::MAX, true));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(-2), (3, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_sub_signed(-4), (1, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub_signed(self, rhs: $SignedT) -> (Self, bool) { + let (res, overflow) = self.overflowing_sub(rhs as Self); + + (res, overflow ^ (rhs < 0)) + } + /// Computes the absolute difference between `self` and `other`. /// /// # Examples @@ -2463,7 +2549,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")] @@ -2494,7 +2580,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")] @@ -2522,7 +2608,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")] @@ -2553,7 +2639,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")] @@ -2577,7 +2663,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));")] @@ -2602,7 +2688,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));")] @@ -2628,7 +2714,7 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));")] @@ -2704,7 +2790,6 @@ macro_rules! uint_impl { without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; diff --git a/core/src/ops/arith.rs b/core/src/ops/arith.rs index 133ae04f02618..565bccf589826 100644 --- a/core/src/ops/arith.rs +++ b/core/src/ops/arith.rs @@ -73,6 +73,7 @@ append_const_msg )] #[doc(alias = "+")] +#[cfg_attr(not(bootstrap), const_trait)] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -94,6 +95,7 @@ pub trait Add { macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(bootstrap)] impl Add for $t { type Output = $t; @@ -103,6 +105,17 @@ macro_rules! add_impl { fn add(self, other: $t) -> $t { self + other } } + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(bootstrap))] + impl const Add for $t { + type Output = $t; + + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + fn add(self, other: $t) -> $t { self + other } + } + forward_ref_binop! { impl Add, add for $t, $t } )*) } diff --git a/core/src/ops/deref.rs b/core/src/ops/deref.rs index 1ef9990c00af8..e9bb40d0fdd17 100644 --- a/core/src/ops/deref.rs +++ b/core/src/ops/deref.rs @@ -133,6 +133,7 @@ #[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Deref"] +#[cfg_attr(not(bootstrap), const_trait)] pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -147,6 +148,7 @@ pub trait Deref { fn deref(&self) -> &Self::Target; } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Deref for &T { type Target = T; @@ -157,9 +159,21 @@ impl Deref for &T { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl const Deref for &T { + type Target = T; + + #[rustc_diagnostic_item = "noop_method_deref"] + fn deref(&self) -> &T { + *self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl !DerefMut for &T {} +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Deref for &mut T { type Target = T; @@ -169,6 +183,16 @@ impl Deref for &mut T { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl const Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + /// Used for mutable dereferencing operations, like in `*v = 1;`. /// /// In addition to being used for explicit dereferencing operations with the @@ -258,9 +282,23 @@ impl Deref for &mut T { /// *x = 'b'; /// assert_eq!('b', x.value); /// ``` +#[cfg(not(bootstrap))] +#[lang = "deref_mut"] +#[doc(alias = "*")] +#[stable(feature = "rust1", since = "1.0.0")] +#[const_trait] +pub trait DerefMut: ~const Deref { + /// Mutably dereferences the value. + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_mut_method"] + fn deref_mut(&mut self) -> &mut Self::Target; +} + +/// Bootstrap #[lang = "deref_mut"] #[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(bootstrap)] pub trait DerefMut: Deref { /// Mutably dereferences the value. #[stable(feature = "rust1", since = "1.0.0")] @@ -268,6 +306,7 @@ pub trait DerefMut: Deref { fn deref_mut(&mut self) -> &mut Self::Target; } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl DerefMut for &mut T { fn deref_mut(&mut self) -> &mut T { @@ -275,6 +314,14 @@ impl DerefMut for &mut T { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl const DerefMut for &mut T { + fn deref_mut(&mut self) -> &mut T { + *self + } +} + /// Perma-unstable marker trait. Indicates that the type has a well-behaved [`Deref`] /// (and, if applicable, [`DerefMut`]) implementation. This is relied on for soundness /// of deref patterns. @@ -294,14 +341,98 @@ unsafe impl DerefPure for &T {} #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for &mut T {} +/// Indicates that a struct can be used as a method receiver. +/// That is, a type can use this type as a type of `self`, like this: +/// ```compile_fail +/// # // This is currently compile_fail because the compiler-side parts +/// # // of arbitrary_self_types are not implemented +/// use std::ops::Receiver; +/// +/// struct SmartPointer(T); +/// +/// impl Receiver for SmartPointer { +/// type Target = T; +/// } +/// +/// struct MyContainedType; +/// +/// impl MyContainedType { +/// fn method(self: SmartPointer) { +/// // ... +/// } +/// } +/// +/// fn main() { +/// let ptr = SmartPointer(MyContainedType); +/// ptr.method(); +/// } +/// ``` +/// This trait is blanket implemented for any type which implements +/// [`Deref`], which includes stdlib pointer types like `Box`,`Rc`, `&T`, +/// and `Pin

`. For that reason, it's relatively rare to need to +/// implement this directly. You'll typically do this only if you need +/// to implement a smart pointer type which can't implement [`Deref`]; perhaps +/// because you're interfacing with another programming language and can't +/// guarantee that references comply with Rust's aliasing rules. +/// +/// When looking for method candidates, Rust will explore a chain of possible +/// `Receiver`s, so for example each of the following methods work: +/// ``` +/// use std::boxed::Box; +/// use std::rc::Rc; +/// +/// // Both `Box` and `Rc` (indirectly) implement Receiver +/// +/// struct MyContainedType; +/// +/// fn main() { +/// let t = Rc::new(Box::new(MyContainedType)); +/// t.method_a(); +/// t.method_b(); +/// t.method_c(); +/// } +/// +/// impl MyContainedType { +/// fn method_a(&self) { +/// +/// } +/// fn method_b(self: &Box) { +/// +/// } +/// fn method_c(self: &Rc>) { +/// +/// } +/// } +/// ``` +#[lang = "receiver"] +#[cfg(not(bootstrap))] +#[unstable(feature = "arbitrary_self_types", issue = "44874")] +pub trait Receiver { + /// The target type on which the method may be called. + #[cfg(not(bootstrap))] + #[rustc_diagnostic_item = "receiver_target"] + #[lang = "receiver_target"] + #[unstable(feature = "arbitrary_self_types", issue = "44874")] + type Target: ?Sized; +} + +#[cfg(not(bootstrap))] +#[unstable(feature = "arbitrary_self_types", issue = "44874")] +impl Receiver for P +where + P: Deref, +{ + type Target = T; +} + /// Indicates that a struct can be used as a method receiver, without the /// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box`, /// `Rc`, `&T`, and `Pin

`. /// /// This trait will shortly be removed and replaced with a more generic /// facility based around the current "arbitrary self types" unstable feature. -/// That new facility will use a replacement trait called `Receiver` which is -/// why this is now named `LegacyReceiver`. +/// That new facility will use the replacement trait above called `Receiver` +/// which is why this is now named `LegacyReceiver`. #[cfg_attr(bootstrap, lang = "receiver")] #[cfg_attr(not(bootstrap), lang = "legacy_receiver")] #[unstable(feature = "legacy_receiver_trait", issue = "none")] diff --git a/core/src/ops/drop.rs b/core/src/ops/drop.rs index c6083a121d107..a6f63ad68d695 100644 --- a/core/src/ops/drop.rs +++ b/core/src/ops/drop.rs @@ -203,7 +203,7 @@ /// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] -// FIXME(effects) #[const_trait] +// FIXME(const_trait_impl) #[const_trait] pub trait Drop { /// Executes the destructor for this type. /// diff --git a/core/src/ops/function.rs b/core/src/ops/function.rs index 3a3d3fcf1da64..e9014458b48ea 100644 --- a/core/src/ops/function.rs +++ b/core/src/ops/function.rs @@ -72,7 +72,7 @@ use crate::marker::Tuple; )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(effects) #[const_trait] +// FIXME(const_trait_impl) #[const_trait] pub trait Fn: FnMut { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -159,7 +159,7 @@ pub trait Fn: FnMut { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(effects) #[const_trait] +// FIXME(const_trait_impl) #[const_trait] pub trait FnMut: FnOnce { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -238,7 +238,7 @@ pub trait FnMut: FnOnce { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(effects) #[const_trait] +// FIXME(const_trait_impl) #[const_trait] pub trait FnOnce { /// The returned type after the call operator is used. #[lang = "fn_once_output"] diff --git a/core/src/ops/mod.rs b/core/src/ops/mod.rs index c9f47e5daadd6..cea1f84f3fd60 100644 --- a/core/src/ops/mod.rs +++ b/core/src/ops/mod.rs @@ -170,6 +170,9 @@ pub use self::coroutine::{Coroutine, CoroutineState}; pub use self::deref::DerefPure; #[unstable(feature = "legacy_receiver_trait", issue = "none")] pub use self::deref::LegacyReceiver; +#[unstable(feature = "arbitrary_self_types", issue = "44874")] +#[cfg(not(bootstrap))] +pub use self::deref::Receiver; #[stable(feature = "rust1", since = "1.0.0")] pub use self::deref::{Deref, DerefMut}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/core/src/option.rs b/core/src/option.rs index 2aa4f1723680f..29d1956af9559 100644 --- a/core/src/option.rs +++ b/core/src/option.rs @@ -563,6 +563,7 @@ use crate::pin::Pin; use crate::{cmp, convert, hint, mem, slice}; /// The `Option` type. See [the module level documentation](self) for more. +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[derive(Copy, Eq, Debug, Hash)] #[rustc_diagnostic_item = "Option"] #[lang = "Option"] @@ -737,7 +738,7 @@ impl Option { #[inline] #[must_use] #[stable(feature = "pin", since = "1.33.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + #[rustc_const_stable(feature = "const_option_ext", since = "CURRENT_RUSTC_VERSION")] pub const fn as_pin_ref(self: Pin<&Self>) -> Option> { // FIXME(const-hack): use `map` once that is possible match Pin::get_ref(self).as_ref() { @@ -754,7 +755,7 @@ impl Option { #[inline] #[must_use] #[stable(feature = "pin", since = "1.33.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + #[rustc_const_stable(feature = "const_option_ext", since = "CURRENT_RUSTC_VERSION")] pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option> { // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`. // `x` is guaranteed to be pinned because it comes from `self` which is pinned. @@ -801,7 +802,7 @@ impl Option { #[inline] #[must_use] #[stable(feature = "option_as_slice", since = "1.75.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + #[rustc_const_stable(feature = "const_option_ext", since = "CURRENT_RUSTC_VERSION")] pub const fn as_slice(&self) -> &[T] { // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to @@ -856,7 +857,7 @@ impl Option { #[inline] #[must_use] #[stable(feature = "option_as_slice", since = "1.75.0")] - #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] + #[rustc_const_stable(feature = "const_option_ext", since = "CURRENT_RUSTC_VERSION")] pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to diff --git a/core/src/panic.rs b/core/src/panic.rs index c95a000561c35..179aadf0c286c 100644 --- a/core/src/panic.rs +++ b/core/src/panic.rs @@ -189,3 +189,60 @@ pub unsafe trait PanicPayload: crate::fmt::Display { None } } + +/// Helper macro for panicking in a `const fn`. +/// Invoke as: +/// ```rust,ignore (just an example) +/// core::macros::const_panic!("boring message", "flavored message {a} {b:?}", a: u32 = foo.len(), b: Something = bar); +/// ``` +/// where the first message will be printed in const-eval, +/// and the second message will be printed at runtime. +// All uses of this macro are FIXME(const-hack). +#[unstable(feature = "panic_internals", issue = "none")] +#[doc(hidden)] +pub macro const_panic { + ($const_msg:literal, $runtime_msg:literal, $($arg:ident : $ty:ty = $val:expr),* $(,)?) => {{ + // Wrap call to `const_eval_select` in a function so that we can + // add the `rustc_allow_const_fn_unstable`. This is okay to do + // because both variants will panic, just with different messages. + #[rustc_allow_const_fn_unstable(const_eval_select)] + #[inline(always)] // inline the wrapper + #[track_caller] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_panic", since = "CURRENT_RUSTC_VERSION"))] + const fn do_panic($($arg: $ty),*) -> ! { + $crate::intrinsics::const_eval_select!( + @capture { $($arg: $ty = $arg),* } -> !: + #[noinline] + if const #[track_caller] #[inline] { // Inline this, to prevent codegen + $crate::panic!($const_msg) + } else #[track_caller] #[cfg_attr(bootstrap, inline)] { // Do not inline this, it makes perf worse + $crate::panic!($runtime_msg) + } + ) + } + + do_panic($($val),*) + }}, + // We support leaving away the `val` expressions for *all* arguments + // (but not for *some* arguments, that's too tricky). + ($const_msg:literal, $runtime_msg:literal, $($arg:ident : $ty:ty),* $(,)?) => { + $crate::panic::const_panic!( + $const_msg, + $runtime_msg, + $($arg: $ty = $arg),* + ) + }, +} + +/// A version of `assert` that prints a non-formatting message in const contexts. +/// +/// See [`const_panic!`]. +#[unstable(feature = "panic_internals", issue = "none")] +#[doc(hidden)] +pub macro const_assert { + ($condition: expr, $const_msg:literal, $runtime_msg:literal, $($arg:tt)*) => {{ + if !$crate::intrinsics::likely($condition) { + $crate::panic::const_panic!($const_msg, $runtime_msg, $($arg)*) + } + }} +} diff --git a/core/src/panic/panic_info.rs b/core/src/panic/panic_info.rs index 1d950eb362504..230a9918dbf3e 100644 --- a/core/src/panic/panic_info.rs +++ b/core/src/panic/panic_info.rs @@ -165,10 +165,9 @@ impl<'a> PanicMessage<'a> { /// /// See [`fmt::Arguments::as_str`] for details. #[stable(feature = "panic_info_message", since = "1.81.0")] - #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] + #[rustc_const_stable(feature = "const_arguments_as_str", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] pub const fn as_str(&self) -> Option<&'static str> { self.message.as_str() } diff --git a/core/src/panicking.rs b/core/src/panicking.rs index 9071d6719a30e..f603eb2971f6d 100644 --- a/core/src/panicking.rs +++ b/core/src/panicking.rs @@ -29,6 +29,7 @@ )] use crate::fmt; +use crate::intrinsics::const_eval_select; use crate::panic::{Location, PanicInfo}; #[cfg(feature = "panic_immediate_abort")] @@ -89,40 +90,35 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable #[rustc_allow_const_fn_unstable(const_eval_select)] pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { - #[inline] // this should always be inlined into `panic_nounwind_fmt` - #[track_caller] - fn runtime(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { - if cfg!(feature = "panic_immediate_abort") { - super::intrinsics::abort() + const_eval_select!( + @capture { fmt: fmt::Arguments<'_>, force_no_backtrace: bool } -> !: + if const #[track_caller] { + // We don't unwind anyway at compile-time so we can call the regular `panic_fmt`. + panic_fmt(fmt) + } else #[track_caller] { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + // that gets resolved to the `#[panic_handler]` function. + extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo<'_>) -> !; + } + + // PanicInfo with the `can_unwind` flag set to false forces an abort. + let pi = PanicInfo::new( + &fmt, + Location::caller(), + /* can_unwind */ false, + force_no_backtrace, + ); + + // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. + unsafe { panic_impl(&pi) } } - - // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call - // that gets resolved to the `#[panic_handler]` function. - extern "Rust" { - #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo<'_>) -> !; - } - - // PanicInfo with the `can_unwind` flag set to false forces an abort. - let pi = PanicInfo::new( - &fmt, - Location::caller(), - /* can_unwind */ false, - force_no_backtrace, - ); - - // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. - unsafe { panic_impl(&pi) } - } - - #[inline] - #[track_caller] - const fn comptime(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! { - // We don't unwind anyway at compile-time so we can call the regular `panic_fmt`. - panic_fmt(fmt); - } - - super::intrinsics::const_eval_select((fmt, force_no_backtrace), comptime, runtime); + ) } // Next we define a bunch of higher-level wrappers that all bottom out in the two core functions diff --git a/core/src/pin.rs b/core/src/pin.rs index 254b306fcaafe..c14c49a0d92f9 100644 --- a/core/src/pin.rs +++ b/core/src/pin.rs @@ -1214,7 +1214,8 @@ impl> Pin { /// assert_eq!(*r, 5); /// ``` #[inline(always)] - #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const fn into_inner(pin: Pin) -> Ptr { pin.__pointer @@ -1503,7 +1504,8 @@ impl Pin { /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. #[inline(always)] - #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const unsafe fn into_inner_unchecked(pin: Pin) -> Ptr { pin.__pointer diff --git a/core/src/primitive_docs.rs b/core/src/primitive_docs.rs index 4a6fca5085c42..e105ceadff757 100644 --- a/core/src/primitive_docs.rs +++ b/core/src/primitive_docs.rs @@ -1746,11 +1746,10 @@ mod prim_ref {} /// alignment, they might be passed in different registers and hence not be ABI-compatible. /// /// ABI compatibility as a concern only arises in code that alters the type of function pointers, -/// code that imports functions via `extern` blocks, and in code that combines `#[target_feature]` -/// with `extern fn`. Altering the type of function pointers is wildly unsafe (as in, a lot more -/// unsafe than even [`transmute_copy`][mem::transmute_copy]), and should only occur in the most -/// exceptional circumstances. Most Rust code just imports functions via `use`. `#[target_feature]` -/// is also used rarely. So, most likely you do not have to worry about ABI compatibility. +/// and code that imports functions via `extern` blocks. Altering the type of function pointers is +/// wildly unsafe (as in, a lot more unsafe than even [`transmute_copy`][mem::transmute_copy]), and +/// should only occur in the most exceptional circumstances. Most Rust code just imports functions +/// via `use`. So, most likely you do not have to worry about ABI compatibility. /// /// But assuming such circumstances, what are the rules? For this section, we are only considering /// the ABI of direct Rust-to-Rust calls (with both definition and callsite visible to the @@ -1762,9 +1761,8 @@ mod prim_ref {} /// types from `core::ffi` or `libc`**. /// /// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string, -/// must take the same number of arguments, the individual argument types and the return types must -/// be ABI-compatible, and the target feature requirements must be met (see the subsection below for -/// the last point). The ABI string is declared via `extern "ABI" fn(...) -> ...`; note that +/// must take the same number of arguments, and the individual argument types and the return types +/// must be ABI-compatible. The ABI string is declared via `extern "ABI" fn(...) -> ...`; note that /// `fn name(...) -> ...` implicitly uses the `"Rust"` ABI string and `extern fn name(...) -> ...` /// implicitly uses the `"C"` ABI string. /// @@ -1834,24 +1832,6 @@ mod prim_ref {} /// Behavior since transmuting `None::>` to `NonZero` violates the non-zero /// requirement. /// -/// #### Requirements concerning target features -/// -/// Under some conditions, the signature used by the caller and the callee can be ABI-incompatible -/// even if the exact same ABI string and types are being used. As an example, the -/// `std::arch::x86_64::__m256` type has a different `extern "C"` ABI when the `avx` feature is -/// enabled vs when it is not enabled. -/// -/// Therefore, to ensure ABI compatibility when code using different target features is combined -/// (such as via `#[target_feature]`), we further require that one of the following conditions is -/// met: -/// -/// - The function uses the `"Rust"` ABI string (which is the default without `extern`). -/// - Caller and callee are using the exact same set of target features. For the callee we consider -/// the features enabled (via `#[target_feature]` and `-C target-feature`/`-C target-cpu`) at the -/// declaration site; for the caller we consider the features enabled at the call site. -/// - Neither any argument nor the return value involves a SIMD type (`#[repr(simd)]`) that is not -/// behind a pointer indirection (i.e., `*mut __m256` is fine, but `(i32, __m256)` is not). -/// /// ### Trait implementations /// /// In this documentation the shorthand `fn(T₁, T₂, …, Tₙ)` is used to represent non-variadic diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 57a7c0fc0925c..0dbe819acb1b9 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -29,30 +29,29 @@ impl *const T { /// assert!(!ptr.is_null()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_const_is_null"] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] pub const fn is_null(self) -> bool { - #[inline] - fn runtime_impl(ptr: *const u8) -> bool { - ptr.addr() == 0 - } - - #[inline] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] - const fn const_impl(ptr: *const u8) -> bool { - match (ptr).guaranteed_eq(null_mut()) { - Some(res) => res, - // To remain maximally convervative, we stop execution when we don't - // know whether the pointer is null or not. - // We can *not* return `false` here, that would be unsound in `NonNull::new`! - None => panic!("null-ness of this pointer cannot be determined in const context"), - } - } - // Compare via a cast to a thin pointer, so fat pointers are only // considering their "data" part for null-ness. - const_eval_select((self as *const u8,), const_impl, runtime_impl) + let ptr = self as *const u8; + const_eval_select!( + @capture { ptr: *const u8 } -> bool: + // This use of `const_raw_ptr_comparison` has been explicitly blessed by t-lang. + if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] { + match (ptr).guaranteed_eq(null_mut()) { + Some(res) => res, + // To remain maximally convervative, we stop execution when we don't + // know whether the pointer is null or not. + // We can *not* return `false` here, that would be unsound in `NonNull::new`! + None => panic!("null-ness of this pointer cannot be determined in const context"), + } + } else { + ptr.addr() == 0 + } + ) } /// Casts to a pointer of another type. @@ -240,7 +239,6 @@ impl *const T { /// /// The pointer can be later reconstructed with [`from_raw_parts`]. #[unstable(feature = "ptr_metadata", issue = "81513")] - #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn to_raw_parts(self) -> (*const (), ::Metadata) { (self.cast(), metadata(self)) @@ -284,7 +282,7 @@ impl *const T { /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> { // SAFETY: the caller must guarantee that `self` is valid @@ -316,7 +314,6 @@ impl *const T { /// ``` // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized. #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] - #[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] #[inline] #[must_use] pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T { @@ -412,22 +409,21 @@ impl *const T { #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { - #[inline] - fn runtime(this: *const (), count: isize, size: usize) -> bool { - // We know `size <= isize::MAX` so the `as` cast here is not lossy. - let Some(byte_offset) = count.checked_mul(size as isize) else { - return false; - }; - let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); - !overflow - } - - const fn comptime(_: *const (), _: isize, _: usize) -> bool { - true - } - // We can use const_eval_select here because this is only for UB checks. - intrinsics::const_eval_select((this, count, size), comptime, runtime) + const_eval_select!( + @capture { this: *const (), count: isize, size: usize } -> bool: + if const { + true + } else { + // `size` is the size of a Rust type, so we know that + // `size <= isize::MAX` and thus `as` cast here is not lossy. + let Some(byte_offset) = count.checked_mul(size as isize) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); + !overflow + } + ) } ub_checks::assert_unsafe_precondition!( @@ -765,14 +761,14 @@ impl *const T { { #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_ptr_ge(this: *const (), origin: *const ()) -> bool { - fn runtime(this: *const (), origin: *const ()) -> bool { - this >= origin - } - const fn comptime(_: *const (), _: *const ()) -> bool { - true - } - - intrinsics::const_eval_select((this, origin), comptime, runtime) + const_eval_select!( + @capture { this: *const (), origin: *const () } -> bool: + if const { + true + } else { + this >= origin + } + ) } ub_checks::assert_unsafe_precondition!( @@ -926,20 +922,18 @@ impl *const T { #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { - #[inline] - fn runtime(this: *const (), count: usize, size: usize) -> bool { - let Some(byte_offset) = count.checked_mul(size) else { - return false; - }; - let (_, overflow) = this.addr().overflowing_add(byte_offset); - byte_offset <= (isize::MAX as usize) && !overflow - } - - const fn comptime(_: *const (), _: usize, _: usize) -> bool { - true - } - - intrinsics::const_eval_select((this, count, size), comptime, runtime) + const_eval_select!( + @capture { this: *const (), count: usize, size: usize } -> bool: + if const { + true + } else { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add(byte_offset); + byte_offset <= (isize::MAX as usize) && !overflow + } + ) } #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. @@ -1035,19 +1029,17 @@ impl *const T { #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { - #[inline] - fn runtime(this: *const (), count: usize, size: usize) -> bool { - let Some(byte_offset) = count.checked_mul(size) else { - return false; - }; - byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset - } - - const fn comptime(_: *const (), _: usize, _: usize) -> bool { - true - } - - intrinsics::const_eval_select((this, count, size), comptime, runtime) + const_eval_select!( + @capture { this: *const (), count: usize, size: usize } -> bool: + if const { + true + } else { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset + } + ) } #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. @@ -1360,15 +1352,6 @@ impl *const T { /// beyond the allocation that the pointer points into. It is up to the caller to ensure that /// the returned offset is correct in all terms other than alignment. /// - /// When this is called during compile-time evaluation (which is unstable), the implementation - /// may return `usize::MAX` in cases where that can never happen at runtime. This is because the - /// actual alignment of pointers is not known yet during compile-time, so an offset with - /// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8; - /// N]` might be allocated at an odd or an even address, but at compile-time this is not yet - /// known, so the execution has to be correct for either choice. It is therefore impossible to - /// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual - /// for unstable APIs.) - /// /// # Panics /// /// The function panics if `align` is not a power-of-two. @@ -1397,8 +1380,7 @@ impl *const T { #[must_use] #[inline] #[stable(feature = "align_offset", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] - pub const fn align_offset(self, align: usize) -> usize + pub fn align_offset(self, align: usize) -> usize where T: Sized, { @@ -1433,94 +1415,10 @@ impl *const T { /// assert!(ptr.is_aligned()); /// assert!(!ptr.wrapping_byte_add(1).is_aligned()); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// is never aligned if cast to a type with a stricter alignment than the reference's - /// underlying allocation. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// assert!(ptr.is_aligned()); - /// - /// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = ptr.wrapping_add(1).cast::(); - /// assert!(!ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.cast::().is_aligned()); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::().is_aligned()); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.cast::().is_aligned(), - /// runtime_ptr.wrapping_add(1).cast::().is_aligned(), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let ptr = 40 as *const AlignedI32; - /// assert!(ptr.is_aligned()); - /// - /// // For pointers with a known address, runtime and compiletime behavior are identical. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = ptr.wrapping_add(1).cast::(); - /// assert!(ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] #[stable(feature = "pointer_is_aligned", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned(self) -> bool + pub fn is_aligned(self) -> bool where T: Sized, { @@ -1557,105 +1455,15 @@ impl *const T { /// /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *const u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned_to(self, align: usize) -> bool { + pub fn is_aligned_to(self, align: usize) -> bool { if !align.is_power_of_two() { panic!("is_aligned_to: align is not a power-of-two"); } - #[inline] - fn runtime_impl(ptr: *const (), align: usize) -> bool { - ptr.addr() & (align - 1) == 0 - } - - #[inline] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - const fn const_impl(ptr: *const (), align: usize) -> bool { - // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. - ptr.align_offset(align) == 0 - } - - // The cast to `()` is used to - // 1. deal with fat pointers; and - // 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset. - const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) + self.addr() & (align - 1) == 0 } } @@ -1714,7 +1522,6 @@ impl *const [T] { /// ``` #[inline] #[unstable(feature = "slice_ptr_get", issue = "74265")] - #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] pub const fn as_ptr(self) -> *const T { self as *const T } @@ -1814,7 +1621,6 @@ impl *const [T; N] { /// ``` #[inline] #[unstable(feature = "array_ptr_get", issue = "119834")] - #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")] pub const fn as_ptr(self) -> *const T { self as *const T } @@ -1832,7 +1638,6 @@ impl *const [T; N] { /// ``` #[inline] #[unstable(feature = "array_ptr_get", issue = "119834")] - #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")] pub const fn as_slice(self) -> *const [T] { self } diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index 7c2205fdcd1c3..805edddfe6312 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -1103,9 +1103,9 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { count: usize = count, ) => { let zero_size = size == 0 || count == 0; - ub_checks::is_aligned_and_not_null(x, align, zero_size) - && ub_checks::is_aligned_and_not_null(y, align, zero_size) - && ub_checks::is_nonoverlapping(x, y, size, count) + ub_checks::maybe_is_aligned_and_not_null(x, align, zero_size) + && ub_checks::maybe_is_aligned_and_not_null(y, align, zero_size) + && ub_checks::maybe_is_nonoverlapping(x, y, size, count) } ); @@ -1216,7 +1216,7 @@ pub const unsafe fn replace(dst: *mut T, src: T) -> T { addr: *const () = dst as *const (), align: usize = align_of::(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); mem::replace(&mut *dst, src) } @@ -1369,7 +1369,7 @@ pub const unsafe fn read(src: *const T) -> T { addr: *const () = src as *const (), align: usize = align_of::(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); crate::intrinsics::read_via_copy(src) } @@ -1407,9 +1407,8 @@ pub const unsafe fn read(src: *const T) -> T { /// As a result, using `&packed.unaligned as *const FieldType` causes immediate /// *undefined behavior* in your program. /// -/// Instead you must use the [`ptr::addr_of!`](addr_of) macro to -/// create the pointer. You may use that returned pointer together with this -/// function. +/// Instead you must use the `&raw const` syntax to create the pointer. +/// You may use that constructed pointer together with this function. /// /// An example of what not to do and how this relates to `read_unaligned` is: /// @@ -1427,7 +1426,7 @@ pub const unsafe fn read(src: *const T) -> T { /// /// // Take the address of a 32-bit integer which is not aligned. /// // In contrast to `&packed.unaligned as *const _`, this has no undefined behavior. -/// let unaligned = std::ptr::addr_of!(packed.unaligned); +/// let unaligned = &raw const packed.unaligned; /// /// let v = unsafe { std::ptr::read_unaligned(unaligned) }; /// assert_eq!(v, 0x01020304); @@ -1574,7 +1573,7 @@ pub const unsafe fn write(dst: *mut T, src: T) { addr: *mut () = dst as *mut (), align: usize = align_of::(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); intrinsics::write_via_move(dst, src) } @@ -1615,9 +1614,8 @@ pub const unsafe fn write(dst: *mut T, src: T) { /// As a result, using `&packed.unaligned as *const FieldType` causes immediate /// *undefined behavior* in your program. /// -/// Instead, you must use the [`ptr::addr_of_mut!`](addr_of_mut) -/// macro to create the pointer. You may use that returned pointer together with -/// this function. +/// Instead, you must use the `&raw mut` syntax to create the pointer. +/// You may use that constructed pointer together with this function. /// /// An example of how to do it and how this relates to `write_unaligned` is: /// @@ -1632,7 +1630,7 @@ pub const unsafe fn write(dst: *mut T, src: T) { /// /// // Take the address of a 32-bit integer which is not aligned. /// // In contrast to `&packed.unaligned as *mut _`, this has no undefined behavior. -/// let unaligned = std::ptr::addr_of_mut!(packed.unaligned); +/// let unaligned = &raw mut packed.unaligned; /// /// unsafe { std::ptr::write_unaligned(unaligned, 42) }; /// @@ -1747,7 +1745,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { addr: *const () = src as *const (), align: usize = align_of::(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); intrinsics::volatile_load(src) } @@ -1827,7 +1825,7 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { addr: *mut () = dst as *mut (), align: usize = align_of::(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); intrinsics::volatile_store(dst, src); } @@ -1852,9 +1850,7 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { /// /// Any questions go to @nagisa. #[allow(ptr_to_integer_transmute_in_consts)] -#[lang = "align_offset"] -#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] -pub(crate) const unsafe fn align_offset(p: *const T, a: usize) -> usize { +pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <= // 1, where the method versions of these operations are not inlined. use intrinsics::{ @@ -1915,11 +1911,7 @@ pub(crate) const unsafe fn align_offset(p: *const T, a: usize) -> usiz let stride = mem::size_of::(); - // SAFETY: This is just an inlined `p.addr()` (which is not - // a `const fn` so we cannot call it). - // During const eval, we hook this function to ensure that the pointer never - // has provenance, making this sound. - let addr: usize = unsafe { mem::transmute(p) }; + let addr: usize = p.addr(); // SAFETY: `a` is a power-of-two, therefore non-zero. let a_minus_one = unsafe { unchecked_sub(a, 1) }; diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 7aa6a309a06b5..f0204bd0f773d 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -29,7 +29,7 @@ impl *mut T { /// assert!(!ptr.is_null()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_is_null"] #[inline] pub const fn is_null(self) -> bool { @@ -225,7 +225,6 @@ impl *mut T { /// /// The pointer can be later reconstructed with [`from_raw_parts_mut`]. #[unstable(feature = "ptr_metadata", issue = "81513")] - #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn to_raw_parts(self) -> (*mut (), ::Metadata) { (self.cast(), super::metadata(self)) @@ -272,7 +271,7 @@ impl *mut T { /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> { // SAFETY: the caller must guarantee that `self` is valid for a @@ -306,7 +305,6 @@ impl *mut T { /// ``` // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized. #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] - #[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] #[inline] #[must_use] pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T { @@ -407,23 +405,21 @@ impl *mut T { #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { - #[inline] - fn runtime(this: *const (), count: isize, size: usize) -> bool { - // `size` is the size of a Rust type, so we know that - // `size <= isize::MAX` and thus `as` cast here is not lossy. - let Some(byte_offset) = count.checked_mul(size as isize) else { - return false; - }; - let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); - !overflow - } - - const fn comptime(_: *const (), _: isize, _: usize) -> bool { - true - } - // We can use const_eval_select here because this is only for UB checks. - intrinsics::const_eval_select((this, count, size), comptime, runtime) + const_eval_select!( + @capture { this: *const (), count: isize, size: usize } -> bool: + if const { + true + } else { + // `size` is the size of a Rust type, so we know that + // `size <= isize::MAX` and thus `as` cast here is not lossy. + let Some(byte_offset) = count.checked_mul(size as isize) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); + !overflow + } + ) } ub_checks::assert_unsafe_precondition!( @@ -623,7 +619,7 @@ impl *mut T { /// println!("{s:?}"); // It'll print: "[4, 2, 3]". /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { // SAFETY: the caller must guarantee that `self` is be valid for @@ -659,7 +655,6 @@ impl *mut T { /// ``` // FIXME: mention it in the docs for `as_mut` and `as_uninit_mut` once stabilized. #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] - #[rustc_const_unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] #[inline] #[must_use] pub const unsafe fn as_mut_unchecked<'a>(self) -> &'a mut T { @@ -1006,20 +1001,18 @@ impl *mut T { #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { - #[inline] - fn runtime(this: *const (), count: usize, size: usize) -> bool { - let Some(byte_offset) = count.checked_mul(size) else { - return false; - }; - let (_, overflow) = this.addr().overflowing_add(byte_offset); - byte_offset <= (isize::MAX as usize) && !overflow - } - - const fn comptime(_: *const (), _: usize, _: usize) -> bool { - true - } - - intrinsics::const_eval_select((this, count, size), comptime, runtime) + const_eval_select!( + @capture { this: *const (), count: usize, size: usize } -> bool: + if const { + true + } else { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add(byte_offset); + byte_offset <= (isize::MAX as usize) && !overflow + } + ) } #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. @@ -1115,19 +1108,17 @@ impl *mut T { #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { - #[inline] - fn runtime(this: *const (), count: usize, size: usize) -> bool { - let Some(byte_offset) = count.checked_mul(size) else { - return false; - }; - byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset - } - - const fn comptime(_: *const (), _: usize, _: usize) -> bool { - true - } - - intrinsics::const_eval_select((this, count, size), comptime, runtime) + const_eval_select!( + @capture { this: *const (), count: usize, size: usize } -> bool: + if const { + true + } else { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset + } + ) } #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. @@ -1639,8 +1630,7 @@ impl *mut T { #[must_use] #[inline] #[stable(feature = "align_offset", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] - pub const fn align_offset(self, align: usize) -> usize + pub fn align_offset(self, align: usize) -> usize where T: Sized, { @@ -1678,95 +1668,10 @@ impl *mut T { /// assert!(ptr.is_aligned()); /// assert!(!ptr.wrapping_byte_add(1).is_aligned()); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// is never aligned if cast to a type with a stricter alignment than the reference's - /// underlying allocation. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let mut data = AlignedI32(42); - /// let ptr = &mut data as *mut AlignedI32; - /// assert!(ptr.is_aligned()); - /// - /// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = ptr.wrapping_add(1).cast::(); - /// assert!(!ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// // Also, note that mutable references are not allowed in the final value of constants. - /// const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut(); - /// const _: () = assert!(!COMPTIME_PTR.cast::().is_aligned()); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::().is_aligned()); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.cast::().is_aligned(), - /// runtime_ptr.wrapping_add(1).cast::().is_aligned(), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let ptr = 40 as *mut AlignedI32; - /// assert!(ptr.is_aligned()); - /// - /// // For pointers with a known address, runtime and compiletime behavior are identical. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = ptr.wrapping_add(1).cast::(); - /// assert!(ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] #[stable(feature = "pointer_is_aligned", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned(self) -> bool + pub fn is_aligned(self) -> bool where T: Sized, { @@ -1803,106 +1708,15 @@ impl *mut T { /// /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let mut data = AlignedI32(42); - /// let ptr = &mut data as *mut AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// // Also, note that mutable references are not allowed in the final value of constants. - /// const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut(); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *mut u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned_to(self, align: usize) -> bool { + pub fn is_aligned_to(self, align: usize) -> bool { if !align.is_power_of_two() { panic!("is_aligned_to: align is not a power-of-two"); } - #[inline] - fn runtime_impl(ptr: *mut (), align: usize) -> bool { - ptr.addr() & (align - 1) == 0 - } - - #[inline] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - const fn const_impl(ptr: *mut (), align: usize) -> bool { - // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. - ptr.align_offset(align) == 0 - } - - // The cast to `()` is used to - // 1. deal with fat pointers; and - // 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset. - const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) + self.addr() & (align - 1) == 0 } } @@ -2059,7 +1873,6 @@ impl *mut [T] { /// ``` #[inline(always)] #[unstable(feature = "slice_ptr_get", issue = "74265")] - #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] pub const fn as_mut_ptr(self) -> *mut T { self as *mut T } @@ -2215,7 +2028,6 @@ impl *mut [T; N] { /// ``` #[inline] #[unstable(feature = "array_ptr_get", issue = "119834")] - #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")] pub const fn as_mut_ptr(self) -> *mut T { self as *mut T } @@ -2236,7 +2048,6 @@ impl *mut [T; N] { /// ``` #[inline] #[unstable(feature = "array_ptr_get", issue = "119834")] - #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")] pub const fn as_mut_slice(self) -> *mut [T] { self } diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index afc0c0123fa92..b69f8a4b9d3ea 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -131,7 +131,6 @@ impl NonNull { #[inline] #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_ref<'a>(self) -> &'a MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. @@ -155,7 +154,6 @@ impl NonNull { #[inline] #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_mut<'a>(self) -> &'a mut MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. @@ -230,7 +228,6 @@ impl NonNull { /// Converts a reference to a `NonNull` pointer. #[unstable(feature = "non_null_from_ref", issue = "130823")] - #[rustc_const_unstable(feature = "non_null_from_ref", issue = "130823")] #[inline] pub const fn from_ref(r: &T) -> Self { // SAFETY: A reference cannot be null. @@ -239,7 +236,6 @@ impl NonNull { /// Converts a mutable reference to a `NonNull` pointer. #[unstable(feature = "non_null_from_ref", issue = "130823")] - #[rustc_const_unstable(feature = "non_null_from_ref", issue = "130823")] #[inline] pub const fn from_mut(r: &mut T) -> Self { // SAFETY: A mutable reference cannot be null. @@ -253,10 +249,9 @@ impl NonNull { /// /// [`std::ptr::from_raw_parts`]: crate::ptr::from_raw_parts #[unstable(feature = "ptr_metadata", issue = "81513")] - #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn from_raw_parts( - data_pointer: NonNull<()>, + data_pointer: NonNull, metadata: ::Metadata, ) -> NonNull { // SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_pointer` is. @@ -269,7 +264,6 @@ impl NonNull { /// /// The pointer can be later reconstructed with [`NonNull::from_raw_parts`]. #[unstable(feature = "ptr_metadata", issue = "81513")] - #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1198,8 +1192,7 @@ impl NonNull { #[inline] #[must_use] #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] - pub const fn align_offset(self, align: usize) -> usize + pub fn align_offset(self, align: usize) -> usize where T: Sized, { @@ -1230,98 +1223,10 @@ impl NonNull { /// assert!(ptr.is_aligned()); /// assert!(!NonNull::new(ptr.as_ptr().wrapping_byte_add(1)).unwrap().is_aligned()); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// is never aligned if cast to a type with a stricter alignment than the reference's - /// underlying allocation. - /// - /// ``` - /// #![feature(const_nonnull_new)] - /// #![feature(const_pointer_is_aligned)] - /// use std::ptr::NonNull; - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let data = [AlignedI32(42), AlignedI32(42)]; - /// let ptr = NonNull::::new(&data[0] as *const _ as *mut _).unwrap(); - /// assert!(ptr.is_aligned()); - /// - /// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = unsafe { ptr.add(1).cast::() }; - /// assert!(!ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.cast::().is_aligned()); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::().is_aligned()); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.cast::().is_aligned(), - /// runtime_ptr.wrapping_add(1).cast::().is_aligned(), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// #![feature(const_nonnull_new)] - /// use std::ptr::NonNull; - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let ptr = NonNull::new(40 as *mut AlignedI32).unwrap(); - /// assert!(ptr.is_aligned()); - /// - /// // For pointers with a known address, runtime and compiletime behavior are identical. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = NonNull::new(ptr.as_ptr().wrapping_add(1)).unwrap().cast::(); - /// assert!(ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[inline] #[must_use] #[stable(feature = "pointer_is_aligned", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned(self) -> bool + pub fn is_aligned(self) -> bool where T: Sized, { @@ -1358,85 +1263,10 @@ impl NonNull { /// /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *const u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[inline] #[must_use] #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned_to(self, align: usize) -> bool { + pub fn is_aligned_to(self, align: usize) -> bool { self.pointer.is_aligned_to(align) } } @@ -1545,7 +1375,6 @@ impl NonNull<[T]> { #[inline] #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] - #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] #[rustc_never_returns_null_ptr] pub const fn as_mut_ptr(self) -> *mut T { self.as_non_null_ptr().as_ptr() @@ -1591,7 +1420,6 @@ impl NonNull<[T]> { #[inline] #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> &'a [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice`. unsafe { slice::from_raw_parts(self.cast().as_ptr(), self.len()) } @@ -1656,7 +1484,6 @@ impl NonNull<[T]> { #[inline] #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice_mut<'a>(self) -> &'a mut [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice_mut`. unsafe { slice::from_raw_parts_mut(self.cast().as_ptr(), self.len()) } diff --git a/core/src/result.rs b/core/src/result.rs index 330d1eb14edb0..b450123c5aa90 100644 --- a/core/src/result.rs +++ b/core/src/result.rs @@ -520,6 +520,7 @@ use crate::{convert, fmt, hint}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// /// See the [module documentation](self) for details. +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[rustc_diagnostic_item = "Result"] diff --git a/core/src/slice/ascii.rs b/core/src/slice/ascii.rs index 21e0460072fb3..17ad4fd8f677f 100644 --- a/core/src/slice/ascii.rs +++ b/core/src/slice/ascii.rs @@ -3,6 +3,7 @@ use core::ascii::EscapeDefault; use crate::fmt::{self, Write}; +use crate::intrinsics::const_eval_select; use crate::{ascii, iter, mem, ops}; #[cfg(not(test))] @@ -51,10 +52,30 @@ impl [u8] { /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporaries. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_eq_ignore_ascii_case", issue = "131719")] #[must_use] #[inline] - pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { - self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b)) + pub const fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { + if self.len() != other.len() { + return false; + } + + // FIXME(const-hack): This implementation can be reverted when + // `core::iter::zip` is allowed in const. The original implementation: + // self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b)) + let mut a = self; + let mut b = other; + + while let ([first_a, rest_a @ ..], [first_b, rest_b @ ..]) = (a, b) { + if first_a.eq_ignore_ascii_case(&first_b) { + a = rest_a; + b = rest_b; + } else { + return false; + } + } + + true } /// Converts this slice to its ASCII upper case equivalent in-place. @@ -346,89 +367,91 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool { /// If any of these loads produces something for which `contains_nonascii` /// (above) returns true, then we know the answer is false. #[inline] -#[rustc_allow_const_fn_unstable(const_raw_ptr_comparison, const_pointer_is_aligned)] // only in a debug assertion -#[rustc_allow_const_fn_unstable(const_align_offset)] // behavior does not change when `align_offset` fails +#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior const fn is_ascii(s: &[u8]) -> bool { - const USIZE_SIZE: usize = mem::size_of::(); - - let len = s.len(); - let align_offset = s.as_ptr().align_offset(USIZE_SIZE); - - // If we wouldn't gain anything from the word-at-a-time implementation, fall - // back to a scalar loop. - // - // We also do this for architectures where `size_of::()` isn't - // sufficient alignment for `usize`, because it's a weird edge case. - if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { - return is_ascii_simple(s); - } - - // We always read the first word unaligned, which means `align_offset` is - // 0, we'd read the same value again for the aligned read. - let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; + // The runtime version behaves the same as the compiletime version, it's + // just more optimized. + const_eval_select!( + @capture { s: &[u8] } -> bool: + if const { + is_ascii_simple(s) + } else { + const USIZE_SIZE: usize = mem::size_of::(); + + let len = s.len(); + let align_offset = s.as_ptr().align_offset(USIZE_SIZE); + + // If we wouldn't gain anything from the word-at-a-time implementation, fall + // back to a scalar loop. + // + // We also do this for architectures where `size_of::()` isn't + // sufficient alignment for `usize`, because it's a weird edge case. + if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { + return is_ascii_simple(s); + } - let start = s.as_ptr(); - // SAFETY: We verify `len < USIZE_SIZE` above. - let first_word = unsafe { (start as *const usize).read_unaligned() }; + // We always read the first word unaligned, which means `align_offset` is + // 0, we'd read the same value again for the aligned read. + let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; - if contains_nonascii(first_word) { - return false; - } - // We checked this above, somewhat implicitly. Note that `offset_to_aligned` - // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked - // above. - debug_assert!(offset_to_aligned <= len); - - // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the - // middle chunk of the slice. - let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; - - // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. - let mut byte_pos = offset_to_aligned; - - // Paranoia check about alignment, since we're about to do a bunch of - // unaligned loads. In practice this should be impossible barring a bug in - // `align_offset` though. - // While this method is allowed to spuriously fail in CTFE, if it doesn't - // have alignment information it should have given a `usize::MAX` for - // `align_offset` earlier, sending things through the scalar path instead of - // this one, so this check should pass if it's reachable. - debug_assert!(word_ptr.is_aligned_to(mem::align_of::())); - - // Read subsequent words until the last aligned word, excluding the last - // aligned word by itself to be done in tail check later, to ensure that - // tail is always one `usize` at most to extra branch `byte_pos == len`. - while byte_pos < len - USIZE_SIZE { - // Sanity check that the read is in bounds - debug_assert!(byte_pos + USIZE_SIZE <= len); - // And that our assumptions about `byte_pos` hold. - debug_assert!(matches!( - word_ptr.cast::().guaranteed_eq(start.wrapping_add(byte_pos)), - // These are from the same allocation, so will hopefully always be - // known to match even in CTFE, but if it refuses to compare them - // that's ok since it's just a debug check anyway. - None | Some(true), - )); - - // SAFETY: We know `word_ptr` is properly aligned (because of - // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end - let word = unsafe { word_ptr.read() }; - if contains_nonascii(word) { - return false; - } + let start = s.as_ptr(); + // SAFETY: We verify `len < USIZE_SIZE` above. + let first_word = unsafe { (start as *const usize).read_unaligned() }; - byte_pos += USIZE_SIZE; - // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that - // after this `add`, `word_ptr` will be at most one-past-the-end. - word_ptr = unsafe { word_ptr.add(1) }; - } + if contains_nonascii(first_word) { + return false; + } + // We checked this above, somewhat implicitly. Note that `offset_to_aligned` + // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked + // above. + debug_assert!(offset_to_aligned <= len); + + // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the + // middle chunk of the slice. + let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; + + // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. + let mut byte_pos = offset_to_aligned; + + // Paranoia check about alignment, since we're about to do a bunch of + // unaligned loads. In practice this should be impossible barring a bug in + // `align_offset` though. + // While this method is allowed to spuriously fail in CTFE, if it doesn't + // have alignment information it should have given a `usize::MAX` for + // `align_offset` earlier, sending things through the scalar path instead of + // this one, so this check should pass if it's reachable. + debug_assert!(word_ptr.is_aligned_to(mem::align_of::())); + + // Read subsequent words until the last aligned word, excluding the last + // aligned word by itself to be done in tail check later, to ensure that + // tail is always one `usize` at most to extra branch `byte_pos == len`. + while byte_pos < len - USIZE_SIZE { + // Sanity check that the read is in bounds + debug_assert!(byte_pos + USIZE_SIZE <= len); + // And that our assumptions about `byte_pos` hold. + debug_assert!(word_ptr.cast::() == start.wrapping_add(byte_pos)); + + // SAFETY: We know `word_ptr` is properly aligned (because of + // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end + let word = unsafe { word_ptr.read() }; + if contains_nonascii(word) { + return false; + } + + byte_pos += USIZE_SIZE; + // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that + // after this `add`, `word_ptr` will be at most one-past-the-end. + word_ptr = unsafe { word_ptr.add(1) }; + } - // Sanity check to ensure there really is only one `usize` left. This should - // be guaranteed by our loop condition. - debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); + // Sanity check to ensure there really is only one `usize` left. This should + // be guaranteed by our loop condition. + debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); - // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. - let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; + // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. + let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; - !contains_nonascii(last_word) + !contains_nonascii(last_word) + } + ) } diff --git a/core/src/slice/index.rs b/core/src/slice/index.rs index 231ab7396adfd..aafa19c0dd3d3 100644 --- a/core/src/slice/index.rs +++ b/core/src/slice/index.rs @@ -1,6 +1,6 @@ //! Indexing implementations for `[T]`. -use crate::intrinsics::const_eval_select; +use crate::panic::const_panic; use crate::ub_checks::assert_unsafe_precondition; use crate::{ops, range}; @@ -31,67 +31,37 @@ where #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { - // FIXME(const-hack): once integer formatting in panics is possible, we - // should use the same implementation at compiletime and runtime. - const_eval_select((index, len), slice_start_index_len_fail_ct, slice_start_index_len_fail_rt) -} - -#[inline] -#[track_caller] -fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! { - panic!("range start index {index} out of range for slice of length {len}"); -} - -#[inline] -#[track_caller] -const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { - panic!("slice start index is out of range for slice"); + const_panic!( + "slice start index is out of range for slice", + "range start index {index} out of range for slice of length {len}", + index: usize, + len: usize, + ) } #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { - // FIXME(const-hack): once integer formatting in panics is possible, we - // should use the same implementation at compiletime and runtime. - const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt) -} - -#[inline] -#[track_caller] -fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! { - panic!("range end index {index} out of range for slice of length {len}"); -} - -#[inline] -#[track_caller] -const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { - panic!("slice end index is out of range for slice"); + const_panic!( + "slice end index is out of range for slice", + "range end index {index} out of range for slice of length {len}", + index: usize, + len: usize, + ) } #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_index_order_fail(index: usize, end: usize) -> ! { - // FIXME(const-hack): once integer formatting in panics is possible, we - // should use the same implementation at compiletime and runtime. - const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) -} - -#[inline] -#[track_caller] -fn slice_index_order_fail_rt(index: usize, end: usize) -> ! { - panic!("slice index starts at {index} but ends at {end}"); -} - -#[inline] -#[track_caller] -const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! { - panic!("slice index start is larger than end"); + const_panic!( + "slice index start is larger than end", + "slice index starts at {index} but ends at {end}", + index: usize, + end: usize, + ) } #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] diff --git a/core/src/slice/memchr.rs b/core/src/slice/memchr.rs index 5760462326261..339adad1b17bf 100644 --- a/core/src/slice/memchr.rs +++ b/core/src/slice/memchr.rs @@ -1,6 +1,7 @@ // Original implementation taken from rust-memchr. // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch +use crate::intrinsics::const_eval_select; use crate::mem; const LO_USIZE: usize = usize::repeat_u8(0x01); @@ -50,58 +51,64 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option { None } -#[rustc_allow_const_fn_unstable(const_cmp)] -#[rustc_allow_const_fn_unstable(const_align_offset)] +#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn memchr_aligned(x: u8, text: &[u8]) -> Option { - // Scan for a single byte value by reading two `usize` words at a time. - // - // Split `text` in three parts - // - unaligned initial part, before the first word aligned address in text - // - body, scan by 2 words at a time - // - the last remaining part, < 2 word size - - // search up to an aligned boundary - let len = text.len(); - let ptr = text.as_ptr(); - let mut offset = ptr.align_offset(USIZE_BYTES); - - if offset > 0 { - // FIXME(const-hack, fee1-dead): replace with min - offset = if offset < len { offset } else { len }; - // FIXME(const-hack, fee1-dead): replace with range slicing - // SAFETY: offset is within bounds - let slice = unsafe { super::from_raw_parts(text.as_ptr(), offset) }; - if let Some(index) = memchr_naive(x, slice) { - return Some(index); - } - } - - // search the body of the text - let repeated_x = usize::repeat_u8(x); - while offset <= len - 2 * USIZE_BYTES { - // SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes - // between the offset and the end of the slice. - unsafe { - let u = *(ptr.add(offset) as *const usize); - let v = *(ptr.add(offset + USIZE_BYTES) as *const usize); + // The runtime version behaves the same as the compiletime version, it's + // just more optimized. + const_eval_select!( + @capture { x: u8, text: &[u8] } -> Option: + if const { + memchr_naive(x, text) + } else { + // Scan for a single byte value by reading two `usize` words at a time. + // + // Split `text` in three parts + // - unaligned initial part, before the first word aligned address in text + // - body, scan by 2 words at a time + // - the last remaining part, < 2 word size + + // search up to an aligned boundary + let len = text.len(); + let ptr = text.as_ptr(); + let mut offset = ptr.align_offset(USIZE_BYTES); + + if offset > 0 { + offset = offset.min(len); + let slice = &text[..offset]; + if let Some(index) = memchr_naive(x, slice) { + return Some(index); + } + } - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; + // search the body of the text + let repeated_x = usize::repeat_u8(x); + while offset <= len - 2 * USIZE_BYTES { + // SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes + // between the offset and the end of the slice. + unsafe { + let u = *(ptr.add(offset) as *const usize); + let v = *(ptr.add(offset + USIZE_BYTES) as *const usize); + + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; + } + } + offset += USIZE_BYTES * 2; } - } - offset += USIZE_BYTES * 2; - } - // Find the byte after the point the body loop stopped. - // FIXME(const-hack): Use `?` instead. - // FIXME(const-hack, fee1-dead): use range slicing - // SAFETY: offset is within bounds - let slice = unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) }; - if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None } + // Find the byte after the point the body loop stopped. + // FIXME(const-hack): Use `?` instead. + // FIXME(const-hack, fee1-dead): use range slicing + let slice = + // SAFETY: offset is within bounds + unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) }; + if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None } + } + ) } /// Returns the last index matching the byte `x` in `text`. diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 52d2179b04de1..c855f963771ed 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -735,6 +735,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -765,6 +766,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] #[must_use] pub const fn as_mut_ptr(&mut self) -> *mut T { @@ -4097,7 +4099,23 @@ impl [T] { where T: PartialOrd, { - self.is_sorted_by(|a, b| a <= b) + // This odd number works the best. 32 + 1 extra due to overlapping chunk boundaries. + const CHUNK_SIZE: usize = 33; + if self.len() < CHUNK_SIZE { + return self.windows(2).all(|w| w[0] <= w[1]); + } + let mut i = 0; + // Check in chunks for autovectorization. + while i < self.len() - CHUNK_SIZE { + let chunk = &self[i..i + CHUNK_SIZE]; + if !chunk.windows(2).fold(true, |acc, w| acc & (w[0] <= w[1])) { + return false; + } + // We need to ensure that chunk boundaries are also sorted. + // Overlap the next chunk with the last element of our last chunk. + i += CHUNK_SIZE - 1; + } + self[i..].windows(2).all(|w| w[0] <= w[1]) } /// Checks if the elements of this slice are sorted using the given comparator function. @@ -4578,8 +4596,8 @@ impl [T] { panic!("elements are zero-sized"); } - let self_start = self.as_ptr() as usize; - let elem_start = element as *const T as usize; + let self_start = self.as_ptr().addr(); + let elem_start = ptr::from_ref(element).addr(); let byte_offset = elem_start.wrapping_sub(self_start); @@ -4631,8 +4649,8 @@ impl [T] { panic!("elements are zero-sized"); } - let self_start = self.as_ptr() as usize; - let subslice_start = subslice.as_ptr() as usize; + let self_start = self.as_ptr().addr(); + let subslice_start = subslice.as_ptr().addr(); let byte_start = subslice_start.wrapping_sub(self_start); diff --git a/core/src/slice/raw.rs b/core/src/slice/raw.rs index 89840881c4d90..319b76899bf8e 100644 --- a/core/src/slice/raw.rs +++ b/core/src/slice/raw.rs @@ -132,7 +132,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] align: usize = align_of::(), len: usize = len, ) => - ub_checks::is_aligned_and_not_null(data, align, false) + ub_checks::maybe_is_aligned_and_not_null(data, align, false) && ub_checks::is_valid_allocation_size(size, len) ); &*ptr::slice_from_raw_parts(data, len) @@ -186,7 +186,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m align: usize = align_of::(), len: usize = len, ) => - ub_checks::is_aligned_and_not_null(data, align, false) + ub_checks::maybe_is_aligned_and_not_null(data, align, false) && ub_checks::is_valid_allocation_size(size, len) ); &mut *ptr::slice_from_raw_parts_mut(data, len) diff --git a/core/src/slice/sort/shared/smallsort.rs b/core/src/slice/sort/shared/smallsort.rs index 6adf779a72f0c..09f898309bd65 100644 --- a/core/src/slice/sort/shared/smallsort.rs +++ b/core/src/slice/sort/shared/smallsort.rs @@ -102,7 +102,7 @@ impl UnstableSmallSortTypeImpl for T { } } -/// FIXME(effects) use original ipnsort approach with choose_unstable_small_sort, +/// FIXME(const_trait_impl) use original ipnsort approach with choose_unstable_small_sort, /// as found here . pub(crate) trait UnstableSmallSortFreezeTypeImpl: Sized + FreezeMarker { fn small_sort_threshold() -> usize; diff --git a/core/src/str/converts.rs b/core/src/str/converts.rs index c997e5e443dac..c7bae42765f4e 100644 --- a/core/src/str/converts.rs +++ b/core/src/str/converts.rs @@ -82,7 +82,6 @@ use crate::{mem, ptr}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] -#[rustc_allow_const_fn_unstable(str_internals)] #[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` @@ -218,7 +217,6 @@ pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { #[inline] #[must_use] #[unstable(feature = "str_from_raw_parts", issue = "119206")] -#[rustc_const_unstable(feature = "str_from_raw_parts", issue = "119206")] pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { &*ptr::from_raw_parts(ptr, len) } @@ -237,7 +235,6 @@ pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { #[inline] #[must_use] #[unstable(feature = "str_from_raw_parts", issue = "119206")] -#[rustc_const_unstable(feature = "const_str_from_raw_parts_mut", issue = "119206")] pub const unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut str { // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. unsafe { &mut *ptr::from_raw_parts_mut(ptr, len) } diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index 58d6e07de8da6..4629b770cb46d 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -373,6 +373,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -390,6 +391,7 @@ impl str { #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[must_use] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut u8 { @@ -2400,7 +2402,7 @@ impl str { /// /// # Examples /// - /// Basic usage + /// Basic usage: /// /// ``` /// let four: u32 = "4".parse().unwrap(); @@ -2474,9 +2476,10 @@ impl str { /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_eq_ignore_ascii_case", issue = "131719")] #[must_use] #[inline] - pub fn eq_ignore_ascii_case(&self, other: &str) -> bool { + pub const fn eq_ignore_ascii_case(&self, other: &str) -> bool { self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) } diff --git a/core/src/str/pattern.rs b/core/src/str/pattern.rs index 665c9fc67d01e..52e2364893eb1 100644 --- a/core/src/str/pattern.rs +++ b/core/src/str/pattern.rs @@ -886,8 +886,8 @@ impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} /// # Examples /// /// ``` -/// assert_eq!("Hello world".find(&['l', 'l'] as &[_]), Some(2)); -/// assert_eq!("Hello world".find(&['l', 'l'][..]), Some(2)); +/// assert_eq!("Hello world".find(&['o', 'l'][..]), Some(2)); +/// assert_eq!("Hello world".find(&['h', 'w'][..]), Some(6)); /// ``` impl<'b> Pattern for &'b [char] { pattern_methods!('a, CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher); diff --git a/core/src/str/validations.rs b/core/src/str/validations.rs index cca8ff74dda8b..0f724dd961329 100644 --- a/core/src/str/validations.rs +++ b/core/src/str/validations.rs @@ -1,6 +1,7 @@ //! Operations related to UTF-8 validation. use super::Utf8Error; +use crate::intrinsics::const_eval_select; use crate::mem; /// Returns the initial codepoint accumulator for the first byte. @@ -122,15 +123,25 @@ const fn contains_nonascii(x: usize) -> bool { /// Walks through `v` checking that it's a valid UTF-8 sequence, /// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`. #[inline(always)] -#[rustc_const_unstable(feature = "str_internals", issue = "none")] +#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { let mut index = 0; let len = v.len(); - let usize_bytes = mem::size_of::(); - let ascii_block_size = 2 * usize_bytes; + const USIZE_BYTES: usize = mem::size_of::(); + + let ascii_block_size = 2 * USIZE_BYTES; let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 }; - let align = v.as_ptr().align_offset(usize_bytes); + // Below, we safely fall back to a slower codepath if the offset is `usize::MAX`, + // so the end-to-end behavior is the same at compiletime and runtime. + let align = const_eval_select!( + @capture { v: &[u8] } -> usize: + if const { + usize::MAX + } else { + v.as_ptr().align_offset(USIZE_BYTES) + } + ); while index < len { let old_offset = index; @@ -209,11 +220,11 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // Ascii case, try to skip forward quickly. // When the pointer is aligned, read 2 words of data per iteration // until we find a word containing a non-ascii byte. - if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 { + if align != usize::MAX && align.wrapping_sub(index) % USIZE_BYTES == 0 { let ptr = v.as_ptr(); while index < blocks_end { // SAFETY: since `align - index` and `ascii_block_size` are - // multiples of `usize_bytes`, `block = ptr.add(index)` is + // multiples of `USIZE_BYTES`, `block = ptr.add(index)` is // always aligned with a `usize` so it's safe to dereference // both `block` and `block.add(1)`. unsafe { diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index 93b4ad5c1c941..7f2a5424787f7 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -469,7 +469,7 @@ impl AtomicBool { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -1264,7 +1264,7 @@ impl AtomicPtr { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -2263,7 +2263,7 @@ macro_rules! atomic_int { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } diff --git a/core/src/sync/exclusive.rs b/core/src/sync/exclusive.rs index af25f13973918..340b0b79e40a3 100644 --- a/core/src/sync/exclusive.rs +++ b/core/src/sync/exclusive.rs @@ -130,7 +130,6 @@ impl Exclusive { /// access to the underlying value, but _pinned_ `Exclusive`s only /// produce _pinned_ access to the underlying value. #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { @@ -154,7 +153,6 @@ impl Exclusive { /// a _pinned mutable_ reference to a `T`. This allows you to skip /// building an `Exclusive` with [`Exclusive::new`]. #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive> { diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index fb7af8234ddb1..34673707f010a 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -253,7 +253,6 @@ impl<'a> Context<'a> { /// Returns a reference to the [`LocalWaker`] for the current task. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_unstable(feature = "local_waker", issue = "118959")] pub const fn local_waker(&self) -> &'a LocalWaker { &self.local_waker } @@ -261,7 +260,6 @@ impl<'a> Context<'a> { /// Returns a reference to the extension data for the current task. #[inline] #[unstable(feature = "context_ext", issue = "123392")] - #[rustc_const_unstable(feature = "context_ext", issue = "123392")] pub const fn ext(&mut self) -> &mut dyn Any { // FIXME: this field makes Context extra-weird about unwind safety // can we justify AssertUnwindSafe if we stabilize this? do we care? @@ -337,7 +335,6 @@ impl<'a> ContextBuilder<'a> { /// Creates a ContextBuilder from an existing Context. #[inline] #[unstable(feature = "context_ext", issue = "123392")] - #[rustc_const_unstable(feature = "context_ext", issue = "123392")] pub const fn from(cx: &'a mut Context<'_>) -> Self { let ext = match &mut cx.ext.0 { ExtData::Some(ext) => ExtData::Some(*ext), @@ -355,7 +352,6 @@ impl<'a> ContextBuilder<'a> { /// Sets the value for the waker on `Context`. #[inline] #[unstable(feature = "context_ext", issue = "123392")] - #[rustc_const_unstable(feature = "context_ext", issue = "123392")] pub const fn waker(self, waker: &'a Waker) -> Self { Self { waker, ..self } } @@ -363,7 +359,6 @@ impl<'a> ContextBuilder<'a> { /// Sets the value for the local waker on `Context`. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_unstable(feature = "local_waker", issue = "118959")] pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self { Self { local_waker, ..self } } @@ -371,7 +366,6 @@ impl<'a> ContextBuilder<'a> { /// Sets the value for the extension data on `Context`. #[inline] #[unstable(feature = "context_ext", issue = "123392")] - #[rustc_const_unstable(feature = "context_ext", issue = "123392")] pub const fn ext(self, data: &'a mut dyn Any) -> Self { Self { ext: ExtData::Some(data), ..self } } @@ -834,7 +828,6 @@ impl LocalWaker { #[inline] #[must_use] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_unstable(feature = "local_waker", issue = "118959")] pub const unsafe fn from_raw(waker: RawWaker) -> LocalWaker { Self { waker } } diff --git a/core/src/time.rs b/core/src/time.rs index 5081e777af464..2d93148bac09f 100644 --- a/core/src/time.rs +++ b/core/src/time.rs @@ -883,7 +883,6 @@ impl Duration { #[unstable(feature = "duration_millis_float", issue = "122451")] #[must_use] #[inline] - #[rustc_const_unstable(feature = "duration_millis_float", issue = "122451")] pub const fn as_millis_f64(&self) -> f64 { (self.secs as f64) * (MILLIS_PER_SEC as f64) + (self.nanos.0 as f64) / (NANOS_PER_MILLI as f64) @@ -904,7 +903,6 @@ impl Duration { #[unstable(feature = "duration_millis_float", issue = "122451")] #[must_use] #[inline] - #[rustc_const_unstable(feature = "duration_millis_float", issue = "122451")] pub const fn as_millis_f32(&self) -> f32 { (self.secs as f32) * (MILLIS_PER_SEC as f32) + (self.nanos.0 as f32) / (NANOS_PER_MILLI as f32) diff --git a/core/src/ub_checks.rs b/core/src/ub_checks.rs index 91566439adeae..3e6110c9c88a7 100644 --- a/core/src/ub_checks.rs +++ b/core/src/ub_checks.rs @@ -64,8 +64,6 @@ macro_rules! assert_unsafe_precondition { #[rustc_no_mir_inline] #[inline] #[rustc_nounwind] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] - #[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks const fn precondition_check($($name:$ty),*) { if !$e { ::core::panicking::panic_nounwind( @@ -95,20 +93,18 @@ pub use intrinsics::ub_checks as check_library_ub; #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] pub(crate) const fn check_language_ub() -> bool { - #[inline] - fn runtime() -> bool { - // Disable UB checks in Miri. - !cfg!(miri) - } - - #[inline] - const fn comptime() -> bool { - // Always disable UB checks. - false - } - // Only used for UB checks so we may const_eval_select. - intrinsics::ub_checks() && const_eval_select((), comptime, runtime) + intrinsics::ub_checks() + && const_eval_select!( + @capture { } -> bool: + if const { + // Always disable UB checks. + false + } else { + // Disable UB checks in Miri. + !cfg!(miri) + } + ) } /// Checks whether `ptr` is properly aligned with respect to the given alignment, and @@ -118,9 +114,21 @@ pub(crate) const fn check_language_ub() -> bool { /// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the /// check is anyway not executed in `const`. #[inline] -#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] -pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool { - ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) +#[rustc_allow_const_fn_unstable(const_eval_select)] +pub(crate) const fn maybe_is_aligned_and_not_null( + ptr: *const (), + align: usize, + is_zst: bool, +) -> bool { + // This is just for safety checks so we can const_eval_select. + const_eval_select!( + @capture { ptr: *const (), align: usize, is_zst: bool } -> bool: + if const { + is_zst || !ptr.is_null() + } else { + ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) + } + ) } #[inline] @@ -135,33 +143,30 @@ pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool { /// Note that in const-eval this function just returns `true` and therefore must /// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`. #[inline] -#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] -pub(crate) const fn is_nonoverlapping( +#[rustc_allow_const_fn_unstable(const_eval_select)] +pub(crate) const fn maybe_is_nonoverlapping( src: *const (), dst: *const (), size: usize, count: usize, ) -> bool { - #[inline] - fn runtime(src: *const (), dst: *const (), size: usize, count: usize) -> bool { - let src_usize = src.addr(); - let dst_usize = dst.addr(); - let Some(size) = size.checked_mul(count) else { - crate::panicking::panic_nounwind( - "is_nonoverlapping: `size_of::() * count` overflows a usize", - ) - }; - let diff = src_usize.abs_diff(dst_usize); - // If the absolute distance between the ptrs is at least as big as the size of the buffer, - // they do not overlap. - diff >= size - } - - #[inline] - const fn comptime(_: *const (), _: *const (), _: usize, _: usize) -> bool { - true - } - // This is just for safety checks so we can const_eval_select. - const_eval_select((src, dst, size, count), comptime, runtime) + const_eval_select!( + @capture { src: *const (), dst: *const (), size: usize, count: usize } -> bool: + if const { + true + } else { + let src_usize = src.addr(); + let dst_usize = dst.addr(); + let Some(size) = size.checked_mul(count) else { + crate::panicking::panic_nounwind( + "is_nonoverlapping: `size_of::() * count` overflows a usize", + ) + }; + let diff = src_usize.abs_diff(dst_usize); + // If the absolute distance between the ptrs is at least as big as the size of the buffer, + // they do not overlap. + diff >= size + } + ) } diff --git a/core/src/unicode/unicode_data.rs b/core/src/unicode/unicode_data.rs index cba53bf5054e6..7f4826402eb53 100644 --- a/core/src/unicode/unicode_data.rs +++ b/core/src/unicode/unicode_data.rs @@ -1,7 +1,7 @@ -///! This file is generated by src/tools/unicode-table-generator; do not edit manually! +///! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually! -#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline(always)] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))] const fn bitset_search< const N: usize, const CHUNK_SIZE: usize, @@ -424,7 +424,7 @@ pub mod lowercase { (5, 187), (6, 78), (7, 132), ]; - #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))] pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, @@ -549,7 +549,7 @@ pub mod uppercase { (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), ]; - #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))] pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, @@ -575,7 +575,7 @@ pub mod white_space { 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; #[inline] - pub fn lookup(c: char) -> bool { + pub const fn lookup(c: char) -> bool { match c as u32 >> 8 { 0 => WHITESPACE_MAP[c as usize & 0xff] & 1 != 0, 22 => c as u32 == 0x1680, diff --git a/core/tests/clone.rs b/core/tests/clone.rs index 71a328733b7c4..054b1d3d4986c 100644 --- a/core/tests/clone.rs +++ b/core/tests/clone.rs @@ -28,7 +28,7 @@ fn test_clone_to_uninit_slice_success() { let mut storage: MaybeUninit<[String; 3]> = MaybeUninit::uninit(); let b: [String; 3] = unsafe { - a[..].clone_to_uninit(storage.as_mut_ptr() as *mut [String]); + a[..].clone_to_uninit(storage.as_mut_ptr().cast()); storage.assume_init() }; @@ -70,7 +70,7 @@ fn test_clone_to_uninit_slice_drops_on_panic() { let mut storage: MaybeUninit<[CountsDropsAndPanics; 3]> = MaybeUninit::uninit(); // This should panic halfway through unsafe { - a[..].clone_to_uninit(storage.as_mut_ptr() as *mut [CountsDropsAndPanics]); + a[..].clone_to_uninit(storage.as_mut_ptr().cast()); } }) .unwrap_err(); @@ -89,13 +89,13 @@ fn test_clone_to_uninit_str() { let a = "hello"; let mut storage: MaybeUninit<[u8; 5]> = MaybeUninit::uninit(); - unsafe { a.clone_to_uninit(storage.as_mut_ptr() as *mut [u8] as *mut str) }; + unsafe { a.clone_to_uninit(storage.as_mut_ptr().cast()) }; assert_eq!(a.as_bytes(), unsafe { storage.assume_init() }.as_slice()); let mut b: Box = "world".into(); assert_eq!(a.len(), b.len()); assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b)) }; + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; assert_eq!(a, &*b); } @@ -104,13 +104,13 @@ fn test_clone_to_uninit_cstr() { let a = c"hello"; let mut storage: MaybeUninit<[u8; 6]> = MaybeUninit::uninit(); - unsafe { a.clone_to_uninit(storage.as_mut_ptr() as *mut [u8] as *mut CStr) }; + unsafe { a.clone_to_uninit(storage.as_mut_ptr().cast()) }; assert_eq!(a.to_bytes_with_nul(), unsafe { storage.assume_init() }.as_slice()); let mut b: Box = c"world".into(); assert_eq!(a.count_bytes(), b.count_bytes()); assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b)) }; + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; assert_eq!(a, &*b); } diff --git a/core/tests/iter/traits/step.rs b/core/tests/iter/traits/step.rs index 3d82a40cd2941..bf935af397c71 100644 --- a/core/tests/iter/traits/step.rs +++ b/core/tests/iter/traits/step.rs @@ -2,26 +2,37 @@ use core::iter::*; #[test] fn test_steps_between() { - assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize)); - assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize)); - assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize)); - assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize)); - assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize)); - assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize)); + assert_eq!(Step::steps_between(&20_u8, &200_u8), (180_usize, Some(180_usize))); + assert_eq!(Step::steps_between(&-20_i8, &80_i8), (100_usize, Some(100_usize))); + assert_eq!(Step::steps_between(&-120_i8, &80_i8), (200_usize, Some(200_usize))); + assert_eq!( + Step::steps_between(&20_u32, &4_000_100_u32), + (4_000_080_usize, Some(4_000_080_usize)) + ); + assert_eq!(Step::steps_between(&-20_i32, &80_i32), (100_usize, Some(100_usize))); + assert_eq!( + Step::steps_between(&-2_000_030_i32, &2_000_050_i32), + (4_000_080_usize, Some(4_000_080_usize)) + ); // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms - assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize)); - assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize)); + assert_eq!(Step::steps_between(&20_u128, &200_u128), (180_usize, Some(180_usize))); + assert_eq!(Step::steps_between(&-20_i128, &80_i128), (100_usize, Some(100_usize))); if cfg!(target_pointer_width = "64") { - assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX)); + assert_eq!( + Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), + (usize::MAX, Some(usize::MAX)) + ); } - assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None); - assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None); + assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), (usize::MAX, None)); + assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), (usize::MAX, None)); assert_eq!( Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,), - None, + (usize::MAX, None), ); + + assert_eq!(Step::steps_between(&100_u32, &10_u32), (0, None)); } #[test] diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 2a9f1660a629e..f7825571cd7a8 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_three_way_compare))] #![cfg_attr(bootstrap, feature(strict_provenance))] #![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] @@ -16,18 +17,10 @@ #![feature(cell_update)] #![feature(clone_to_uninit)] #![feature(const_align_of_val_raw)] -#![feature(const_align_offset)] -#![feature(const_bigint_helper_methods)] #![feature(const_black_box)] #![feature(const_eval_select)] -#![feature(const_hash)] #![feature(const_heap)] #![feature(const_nonnull_new)] -#![feature(const_num_midpoint)] -#![feature(const_option_ext)] -#![feature(const_pin_2)] -#![feature(const_pointer_is_aligned)] -#![feature(const_three_way_compare)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] diff --git a/core/tests/nonzero.rs b/core/tests/nonzero.rs index d728513a4e297..43c279053d829 100644 --- a/core/tests/nonzero.rs +++ b/core/tests/nonzero.rs @@ -354,3 +354,14 @@ fn test_signed_nonzero_neg() { assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); } + +#[test] +fn test_nonzero_fmt() { + let i = format!("{0}, {0:?}, {0:x}, {0:X}, {0:#x}, {0:#X}, {0:o}, {0:b}, {0:e}, {0:E}", 42); + let nz = format!( + "{0}, {0:?}, {0:x}, {0:X}, {0:#x}, {0:#X}, {0:o}, {0:b}, {0:e}, {0:E}", + NonZero::new(42).unwrap() + ); + + assert_eq!(i, nz); +} diff --git a/core/tests/ptr.rs b/core/tests/ptr.rs index 78d1b137e63f5..91f8c977d088a 100644 --- a/core/tests/ptr.rs +++ b/core/tests/ptr.rs @@ -359,22 +359,6 @@ fn align_offset_zst() { } } -#[test] -fn align_offset_zst_const() { - const { - // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at - // all, because no amount of elements will align the pointer. - let mut p = 1; - while p < 1024 { - assert!(ptr::without_provenance::<()>(p).align_offset(p) == 0); - if p != 1 { - assert!(ptr::without_provenance::<()>(p + 1).align_offset(p) == !0); - } - p = (p + 1).next_power_of_two(); - } - } -} - #[test] fn align_offset_stride_one() { // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to @@ -396,25 +380,6 @@ fn align_offset_stride_one() { } } -#[test] -fn align_offset_stride_one_const() { - const { - // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to - // number of bytes. - let mut align = 1; - while align < 1024 { - let mut ptr = 1; - while ptr < 2 * align { - let expected = ptr % align; - let offset = if expected == 0 { 0 } else { align - expected }; - assert!(ptr::without_provenance::(ptr).align_offset(align) == offset); - ptr += 1; - } - align = (align + 1).next_power_of_two(); - } - } -} - #[test] fn align_offset_various_strides() { unsafe fn test_stride(ptr: *const T, align: usize) -> bool { @@ -495,192 +460,6 @@ fn align_offset_various_strides() { assert!(!x); } -#[test] -fn align_offset_various_strides_const() { - const unsafe fn test_stride(ptr: *const T, numptr: usize, align: usize) { - let mut expected = usize::MAX; - // Naive but definitely correct way to find the *first* aligned element of stride::. - let mut el = 0; - while el < align { - if (numptr + el * ::std::mem::size_of::()) % align == 0 { - expected = el; - break; - } - el += 1; - } - let got = ptr.align_offset(align); - assert!(got == expected); - } - - const { - // For pointers of stride != 1, we verify the algorithm against the naivest possible - // implementation - let mut align = 1; - let limit = 32; - while align < limit { - let mut ptr = 1; - while ptr < 4 * align { - unsafe { - #[repr(packed)] - struct A3(#[allow(dead_code)] u16, #[allow(dead_code)] u8); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - struct A4(#[allow(dead_code)] u32); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A5(#[allow(dead_code)] u32, #[allow(dead_code)] u8); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A6(#[allow(dead_code)] u32, #[allow(dead_code)] u16); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A7( - #[allow(dead_code)] u32, - #[allow(dead_code)] u16, - #[allow(dead_code)] u8, - ); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A8(#[allow(dead_code)] u32, #[allow(dead_code)] u32); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A9( - #[allow(dead_code)] u32, - #[allow(dead_code)] u32, - #[allow(dead_code)] u8, - ); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A10( - #[allow(dead_code)] u32, - #[allow(dead_code)] u32, - #[allow(dead_code)] u16, - ); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - test_stride::(ptr::without_provenance::(ptr), ptr, align); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - } - ptr += 1; - } - align = (align + 1).next_power_of_two(); - } - } -} - -#[test] -fn align_offset_with_provenance_const() { - const { - // On some platforms (e.g. msp430-none-elf), the alignment of `i32` is less than 4. - #[repr(align(4))] - struct AlignedI32(i32); - - let data = AlignedI32(42); - - // `stride % align == 0` (usual case) - - let ptr: *const i32 = &data.0; - assert!(ptr.align_offset(1) == 0); - assert!(ptr.align_offset(2) == 0); - assert!(ptr.align_offset(4) == 0); - assert!(ptr.align_offset(8) == usize::MAX); - assert!(ptr.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr.wrapping_byte_add(1).align_offset(2) == usize::MAX); - assert!(ptr.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr.wrapping_byte_add(2).align_offset(4) == usize::MAX); - assert!(ptr.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr.wrapping_byte_add(3).align_offset(2) == usize::MAX); - - assert!(ptr.wrapping_add(42).align_offset(4) == 0); - assert!(ptr.wrapping_add(42).align_offset(8) == usize::MAX); - - let ptr1: *const i8 = ptr.cast(); - assert!(ptr1.align_offset(1) == 0); - assert!(ptr1.align_offset(2) == 0); - assert!(ptr1.align_offset(4) == 0); - assert!(ptr1.align_offset(8) == usize::MAX); - assert!(ptr1.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr1.wrapping_byte_add(1).align_offset(2) == 1); - assert!(ptr1.wrapping_byte_add(1).align_offset(4) == 3); - assert!(ptr1.wrapping_byte_add(1).align_offset(8) == usize::MAX); - assert!(ptr1.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr1.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr1.wrapping_byte_add(2).align_offset(4) == 2); - assert!(ptr1.wrapping_byte_add(2).align_offset(8) == usize::MAX); - assert!(ptr1.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr1.wrapping_byte_add(3).align_offset(2) == 1); - assert!(ptr1.wrapping_byte_add(3).align_offset(4) == 1); - assert!(ptr1.wrapping_byte_add(3).align_offset(8) == usize::MAX); - - let ptr2: *const i16 = ptr.cast(); - assert!(ptr2.align_offset(1) == 0); - assert!(ptr2.align_offset(2) == 0); - assert!(ptr2.align_offset(4) == 0); - assert!(ptr2.align_offset(8) == usize::MAX); - assert!(ptr2.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr2.wrapping_byte_add(1).align_offset(2) == usize::MAX); - assert!(ptr2.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr2.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr2.wrapping_byte_add(2).align_offset(4) == 1); - assert!(ptr2.wrapping_byte_add(2).align_offset(8) == usize::MAX); - assert!(ptr2.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr2.wrapping_byte_add(3).align_offset(2) == usize::MAX); - - let ptr3: *const i64 = ptr.cast(); - assert!(ptr3.align_offset(1) == 0); - assert!(ptr3.align_offset(2) == 0); - assert!(ptr3.align_offset(4) == 0); - assert!(ptr3.align_offset(8) == usize::MAX); - assert!(ptr3.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr3.wrapping_byte_add(1).align_offset(2) == usize::MAX); - - // `stride % align != 0` (edge case) - - let ptr4: *const [u8; 3] = ptr.cast(); - assert!(ptr4.align_offset(1) == 0); - assert!(ptr4.align_offset(2) == 0); - assert!(ptr4.align_offset(4) == 0); - assert!(ptr4.align_offset(8) == usize::MAX); - assert!(ptr4.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr4.wrapping_byte_add(1).align_offset(2) == 1); - assert!(ptr4.wrapping_byte_add(1).align_offset(4) == 1); - assert!(ptr4.wrapping_byte_add(1).align_offset(8) == usize::MAX); - assert!(ptr4.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr4.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr4.wrapping_byte_add(2).align_offset(4) == 2); - assert!(ptr4.wrapping_byte_add(2).align_offset(8) == usize::MAX); - assert!(ptr4.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr4.wrapping_byte_add(3).align_offset(2) == 1); - assert!(ptr4.wrapping_byte_add(3).align_offset(4) == 3); - assert!(ptr4.wrapping_byte_add(3).align_offset(8) == usize::MAX); - - let ptr5: *const [u8; 5] = ptr.cast(); - assert!(ptr5.align_offset(1) == 0); - assert!(ptr5.align_offset(2) == 0); - assert!(ptr5.align_offset(4) == 0); - assert!(ptr5.align_offset(8) == usize::MAX); - assert!(ptr5.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr5.wrapping_byte_add(1).align_offset(2) == 1); - assert!(ptr5.wrapping_byte_add(1).align_offset(4) == 3); - assert!(ptr5.wrapping_byte_add(1).align_offset(8) == usize::MAX); - assert!(ptr5.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr5.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr5.wrapping_byte_add(2).align_offset(4) == 2); - assert!(ptr5.wrapping_byte_add(2).align_offset(8) == usize::MAX); - assert!(ptr5.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr5.wrapping_byte_add(3).align_offset(2) == 1); - assert!(ptr5.wrapping_byte_add(3).align_offset(4) == 1); - assert!(ptr5.wrapping_byte_add(3).align_offset(8) == usize::MAX); - } -} - #[test] fn align_offset_issue_103361() { #[cfg(target_pointer_width = "64")] @@ -693,23 +472,6 @@ fn align_offset_issue_103361() { let _ = ptr::without_provenance::(SIZE).align_offset(SIZE); } -#[test] -fn align_offset_issue_103361_const() { - #[cfg(target_pointer_width = "64")] - const SIZE: usize = 1 << 47; - #[cfg(target_pointer_width = "32")] - const SIZE: usize = 1 << 30; - #[cfg(target_pointer_width = "16")] - const SIZE: usize = 1 << 13; - struct HugeSize(#[allow(dead_code)] [u8; SIZE - 1]); - - const { - assert!(ptr::without_provenance::(SIZE - 1).align_offset(SIZE) == SIZE - 1); - assert!(ptr::without_provenance::(SIZE).align_offset(SIZE) == 0); - assert!(ptr::without_provenance::(SIZE + 1).align_offset(SIZE) == 1); - } -} - #[test] fn is_aligned() { let data = 42; @@ -726,25 +488,6 @@ fn is_aligned() { assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); } -#[test] -fn is_aligned_const() { - const { - let data = 42; - let ptr: *const i32 = &data; - assert!(ptr.is_aligned()); - assert!(ptr.is_aligned_to(1)); - assert!(ptr.is_aligned_to(2)); - assert!(ptr.is_aligned_to(4)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(1)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); - assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); - - // At comptime neither `ptr` nor `ptr+1` is aligned to 8. - assert!(!ptr.is_aligned_to(8)); - assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - } -} - #[test] fn offset_from() { let mut a = [0; 5]; diff --git a/profiler_builtins/Cargo.toml b/profiler_builtins/Cargo.toml index 5b10fb5a2bd3f..9aadefce3b39e 100644 --- a/profiler_builtins/Cargo.toml +++ b/profiler_builtins/Cargo.toml @@ -13,4 +13,4 @@ core = { path = "../core" } compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [build-dependencies] -cc = "1.0.97" +cc = "1.2" diff --git a/rustc-std-workspace-core/README.md b/rustc-std-workspace-core/README.md index 40e0b62afabfb..55a36e741065f 100644 --- a/rustc-std-workspace-core/README.md +++ b/rustc-std-workspace-core/README.md @@ -27,3 +27,6 @@ it'll look like when Cargo invokes the compiler, satisfying the implicit `extern crate core` directive injected by the compiler. + +The sources for the crates.io version can be found in +[`src/rustc-std-workspace`](../../src/rustc-std-workspace). diff --git a/std/Cargo.toml b/std/Cargo.toml index 9b66fc8f92147..c1ab70b714a4c 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -17,15 +17,11 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.136" } +compiler_builtins = { version = "=0.1.138" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', ] } -# FIXME(#127890): `object` depends on `memchr`, but `memchr` > v2.5 causes -# issues with LTO. This dependency is not used directly, but pin it here so -# it resolves to 2.5. To be removed once rust-lang/rust#127890 is fixed. -memchr = { version = "=2.5.0", default-features = false, features = ["rustc-dep-of-std"] } std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = [ 'rustc-dep-of-std', ] } @@ -38,7 +34,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false } addr2line = { version = "0.22.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.161", default-features = false, features = [ +libc = { version = "0.2.162", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } diff --git a/std/build.rs b/std/build.rs index 032326556bd5b..8dc326a3dde6a 100644 --- a/std/build.rs +++ b/std/build.rs @@ -122,19 +122,24 @@ fn main() { _ if is_miri => true, // Unsupported ("arm64ec", _) => false, - // ABI and precision bugs - // - ("powerpc" | "powerpc64", _) => false, + // Selection bug + ("mips64" | "mips64r6", _) => false, // Selection bug ("nvptx64", _) => false, + // ABI bugs et al. (full + // list at ) + ("powerpc" | "powerpc64", _) => false, // ABI unsupported ("sparc", _) => false, + // Stack alignment bug . NB: tests may + // not fail if our compiler-builtins is linked. + ("x86", _) => false, // MinGW ABI bugs ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, - // 64-bit Linux is about the only platform to have f128 symbols by default - (_, "linux") if target_pointer_width == 64 => true, - // Almost all OSs are missing symbol. compiler-builtins will have to add them. - _ => false, + // There are no known problems on other platforms, so the only requirement is that symbols + // are available. `compiler-builtins` provides all symbols required for core `f128` + // support, so this should work for everything else. + _ => true, }; // Configure platforms that have reliable basics but may have unreliable math. diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index ded4f404d781e..24bbc2f32cf6d 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -880,7 +880,11 @@ where self.base.get(k) } - /// Returns the key-value pair corresponding to the supplied key. + /// Returns the key-value pair corresponding to the supplied key. This is + /// potentially useful: + /// - for key types where non-identical keys can be considered equal; + /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or + /// - for getting a reference to a key with the same lifetime as the collection. /// /// The supplied key may be any borrowed form of the map's key type, but /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for @@ -890,11 +894,39 @@ where /// /// ``` /// use std::collections::HashMap; + /// use std::hash::{Hash, Hasher}; + /// + /// #[derive(Clone, Copy, Debug)] + /// struct S { + /// id: u32, + /// # #[allow(unused)] // prevents a "field `name` is never read" error + /// name: &'static str, // ignored by equality and hashing operations + /// } + /// + /// impl PartialEq for S { + /// fn eq(&self, other: &S) -> bool { + /// self.id == other.id + /// } + /// } + /// + /// impl Eq for S {} + /// + /// impl Hash for S { + /// fn hash(&self, state: &mut H) { + /// self.id.hash(state); + /// } + /// } + /// + /// let j_a = S { id: 1, name: "Jessica" }; + /// let j_b = S { id: 1, name: "Jess" }; + /// let p = S { id: 2, name: "Paul" }; + /// assert_eq!(j_a, j_b); /// /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); - /// assert_eq!(map.get_key_value(&2), None); + /// map.insert(j_a, "Paris"); + /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris"))); + /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case + /// assert_eq!(map.get_key_value(&p), None); /// ``` #[inline] #[stable(feature = "map_get_key_value", since = "1.40.0")] diff --git a/std/src/collections/hash/map/tests.rs b/std/src/collections/hash/map/tests.rs index b79ad1c3119ff..a275488a55602 100644 --- a/std/src/collections/hash/map/tests.rs +++ b/std/src/collections/hash/map/tests.rs @@ -5,7 +5,7 @@ use super::Entry::{Occupied, Vacant}; use super::HashMap; use crate::assert_matches::assert_matches; use crate::cell::RefCell; -use crate::hash::RandomState; +use crate::hash::{BuildHasher, BuildHasherDefault, DefaultHasher, RandomState}; use crate::test_helpers::test_rng; // https://github.com/rust-lang/rust/issues/62301 @@ -1124,6 +1124,26 @@ fn from_array() { #[test] fn const_with_hasher() { - const X: HashMap<(), (), ()> = HashMap::with_hasher(()); - assert_eq!(X.len(), 0); + const X: HashMap<(), (), BuildHasherDefault> = + HashMap::with_hasher(BuildHasherDefault::new()); + let mut x = X; + assert_eq!(x.len(), 0); + x.insert((), ()); + assert_eq!(x.len(), 1); + + // It *is* possible to do this without using the `BuildHasherDefault` type. + struct MyBuildDefaultHasher; + impl BuildHasher for MyBuildDefaultHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> Self::Hasher { + DefaultHasher::new() + } + } + + const Y: HashMap<(), (), MyBuildDefaultHasher> = HashMap::with_hasher(MyBuildDefaultHasher); + let mut y = Y; + assert_eq!(y.len(), 0); + y.insert((), ()); + assert_eq!(y.len(), 1); } diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index e1e0eb36d23f0..f86bcdb4796ec 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -757,6 +757,47 @@ where self.base.get_or_insert_with(value, f) } + /// Gets the given value's corresponding entry in the set for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry::*; + /// + /// let mut singles = HashSet::new(); + /// let mut dupes = HashSet::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// if let Vacant(dupe_entry) = dupes.entry(ch) { + /// // We haven't already seen a duplicate, so + /// // check if we've at least seen it once. + /// match singles.entry(ch) { + /// Vacant(single_entry) => { + /// // We found a new character for the first time. + /// single_entry.insert() + /// } + /// Occupied(single_entry) => { + /// // We've already seen this once, "move" it to dupes. + /// single_entry.remove(); + /// dupe_entry.insert(); + /// } + /// } + /// } + /// } + /// + /// assert!(!singles.contains(&'t') && dupes.contains(&'t')); + /// assert!(singles.contains(&'u') && !dupes.contains(&'u')); + /// assert!(!singles.contains(&'v') && !dupes.contains(&'v')); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn entry(&mut self, value: T) -> Entry<'_, T, S> { + map_entry(self.base.entry(value)) + } + /// Returns `true` if `self` has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. /// @@ -935,6 +976,14 @@ where } } +#[inline] +fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> { + match raw { + base::Entry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), + base::Entry::Vacant(base) => Entry::Vacant(VacantEntry { base }), + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for HashSet where @@ -1865,6 +1914,406 @@ where } } +/// A view into a single entry in a set, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashSet`]. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`entry`]: struct.HashSet.html#method.entry +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::HashSet; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// assert_eq!(set.len(), 3); +/// +/// // Existing value (insert) +/// let entry = set.entry("a"); +/// let _raw_o = entry.insert(); +/// assert_eq!(set.len(), 3); +/// // Nonexistent value (insert) +/// set.entry("d").insert(); +/// +/// // Existing value (or_insert) +/// set.entry("b").or_insert(); +/// // Nonexistent value (or_insert) +/// set.entry("e").or_insert(); +/// +/// println!("Our HashSet: {:?}", set); +/// +/// let mut vec: Vec<_> = set.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub enum Entry<'a, T, S> { + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::from(["a", "b"]); + /// + /// match set.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, T, S>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// + /// match set.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, T, S>), +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl fmt::Debug for Entry<'_, T, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::{Entry, HashSet}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// +/// let _entry_o = set.entry("a").insert(); +/// assert_eq!(set.len(), 3); +/// +/// // Existing key +/// match set.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(set.len(), 3); +/// +/// // Existing key (take) +/// match set.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove(), "c"); +/// } +/// } +/// assert_eq!(set.get(&"c"), None); +/// assert_eq!(set.len(), 2); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub struct OccupiedEntry<'a, T, S> { + base: base::OccupiedEntry<'a, T, S>, +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl fmt::Debug for OccupiedEntry<'_, T, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry").field("value", self.get()).finish() + } +} + +/// A view into a vacant entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::{Entry, HashSet}; +/// +/// let mut set = HashSet::<&str>::new(); +/// +/// let entry_v = match set.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(); +/// assert!(set.contains("a") && set.len() == 1); +/// +/// // Nonexistent key (insert) +/// match set.entry("b") { +/// Entry::Vacant(view) => view.insert(), +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(set.contains("b") && set.len() == 2); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub struct VacantEntry<'a, T, S> { + base: base::VacantEntry<'a, T, S>, +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl fmt::Debug for VacantEntry<'_, T, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.get()).finish() + } +} + +impl<'a, T, S> Entry<'a, T, S> { + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// let entry = set.entry("horseyland").insert(); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn insert(self) -> OccupiedEntry<'a, T, S> + where + T: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert_entry(), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// // nonexistent key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// + /// // existing key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// assert_eq!(set.len(), 1); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn or_insert(self) + where + T: Hash, + S: BuildHasher, + { + if let Entry::Vacant(entry) = self { + entry.insert(); + } + } + + /// Returns a reference to this entry's value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// // existing key + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(set.entry("horseland").get(), &"horseland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + match *self { + Entry::Occupied(ref entry) => entry.get(), + Entry::Vacant(ref entry) => entry.get(), + } + } +} + +impl OccupiedEntry<'_, T, S> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// match set.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + self.base.get() + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry; + /// + /// let mut set = HashSet::new(); + /// // The set is empty + /// assert!(set.is_empty() && set.capacity() == 0); + /// + /// set.entry("poneyland").or_insert(); + /// let capacity_before_remove = set.capacity(); + /// + /// if let Entry::Occupied(o) = set.entry("poneyland") { + /// assert_eq!(o.remove(), "poneyland"); + /// } + /// + /// assert_eq!(set.contains("poneyland"), false); + /// // Now set hold none elements but capacity is equal to the old one + /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn remove(self) -> T { + self.base.remove() + } +} + +impl<'a, T, S> VacantEntry<'a, T, S> { + /// Gets a reference to the value that would be used when inserting + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + self.base.get() + } + + /// Take ownership of the value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// + /// match set.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"), + /// } + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn into_value(self) -> T { + self.base.into_value() + } + + /// Sets the value of the entry with the VacantEntry's value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry; + /// + /// let mut set = HashSet::new(); + /// + /// if let Entry::Vacant(o) = set.entry("poneyland") { + /// o.insert(); + /// } + /// assert!(set.contains("poneyland")); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn insert(self) + where + T: Hash, + S: BuildHasher, + { + self.base.insert(); + } + + #[inline] + fn insert_entry(self) -> OccupiedEntry<'a, T, S> + where + T: Hash, + S: BuildHasher, + { + OccupiedEntry { base: self.base.insert() } + } +} + #[allow(dead_code)] fn assert_covariance() { fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { diff --git a/std/src/env.rs b/std/src/env.rs index d732a15117e9e..27f4daba44bf6 100644 --- a/std/src/env.rs +++ b/std/src/env.rs @@ -653,19 +653,28 @@ pub fn home_dir() -> Option { /// may result in "insecure temporary file" security vulnerabilities. Consider /// using a crate that securely creates temporary files or directories. /// +/// Note that the returned value may be a symbolic link, not a directory. +/// /// # Platform-specific behavior /// /// On Unix, returns the value of the `TMPDIR` environment variable if it is -/// set, otherwise for non-Android it returns `/tmp`. On Android, since there -/// is no global temporary folder (it is usually allocated per-app), it returns -/// `/data/local/tmp`. +/// set, otherwise the value is OS-specific: +/// - On Android, there is no global temporary folder (it is usually allocated +/// per-app), it returns `/data/local/tmp`. +/// - On Darwin-based OSes (macOS, iOS, etc) it returns the directory provided +/// by `confstr(_CS_DARWIN_USER_TEMP_DIR, ...)`, as recommended by [Apple's +/// security guidelines][appledoc]. +/// - On all other unix-based OSes, it returns `/tmp`. +/// /// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] / /// [`GetTempPath`][GetTempPath], which this function uses internally. +/// /// Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior /// [GetTempPath2]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a /// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha +/// [appledoc]: https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10 /// /// ```no_run /// use std::env; diff --git a/std/src/f128.rs b/std/src/f128.rs index 229f979b5b10b..e93e915159e40 100644 --- a/std/src/f128.rs +++ b/std/src/f128.rs @@ -188,104 +188,6 @@ impl f128 { self - self.trunc() } - /// Computes the absolute value of `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #[cfg(reliable_f128)] { - /// - /// let x = 3.5_f128; - /// let y = -3.5_f128; - /// - /// assert_eq!(x.abs(), x); - /// assert_eq!(y.abs(), -y); - /// - /// assert!(f128::NAN.abs().is_nan()); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub const fn abs(self) -> Self { - // FIXME(f16_f128): replace with `intrinsics::fabsf128` when available - // We don't do this now because LLVM has lowering bugs for f128 math. - Self::from_bits(self.to_bits() & !(1 << 127)) - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - NaN if the number is NaN - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { - /// - /// let f = 3.5_f128; - /// - /// assert_eq!(f.signum(), 1.0); - /// assert_eq!(f128::NEG_INFINITY.signum(), -1.0); - /// - /// assert!(f128::NAN.signum().is_nan()); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub const fn signum(self) -> f128 { - if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) } - } - - /// Returns a number composed of the magnitude of `self` and the sign of - /// `sign`. - /// - /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. - /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is - /// returned. - /// - /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note - /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust - /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the - /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable - /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more - /// info. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #[cfg(reliable_f128_math)] { - /// - /// let f = 3.5_f128; - /// - /// assert_eq!(f.copysign(0.42), 3.5_f128); - /// assert_eq!(f.copysign(-0.42), -3.5_f128); - /// assert_eq!((-f).copysign(0.42), 3.5_f128); - /// assert_eq!((-f).copysign(-0.42), -3.5_f128); - /// - /// assert!(f128::NAN.copysign(1.0).is_nan()); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub const fn copysign(self, sign: f128) -> f128 { - unsafe { intrinsics::copysignf128(self, sign) } - } - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// diff --git a/std/src/f128/tests.rs b/std/src/f128/tests.rs index 7051c051bf723..cbcf9f96239bb 100644 --- a/std/src/f128/tests.rs +++ b/std/src/f128/tests.rs @@ -2,7 +2,10 @@ #![cfg(reliable_f128)] use crate::f128::consts; -use crate::num::{FpCategory as Fp, *}; +use crate::num::FpCategory as Fp; +#[cfg(reliable_f128_math)] +use crate::ops::Rem; +use crate::ops::{Add, Div, Mul, Sub}; // Note these tolerances make sense around zero, but not for more extreme exponents. @@ -53,7 +56,22 @@ macro_rules! assert_f128_biteq { #[test] fn test_num_f128() { - test_num(10f128, 2f128); + // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` + // function is available on all platforms. + let ten = 10f128; + let two = 2f128; + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_num_f128_rem() { + let ten = 10f128; + let two = 2f128; + assert_eq!(ten.rem(two), ten % two); } #[test] diff --git a/std/src/f16.rs b/std/src/f16.rs index bed21cda1cd91..5b7fcaa28e064 100644 --- a/std/src/f16.rs +++ b/std/src/f16.rs @@ -188,103 +188,6 @@ impl f16 { self - self.trunc() } - /// Computes the absolute value of `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #[cfg(reliable_f16)] { - /// - /// let x = 3.5_f16; - /// let y = -3.5_f16; - /// - /// assert_eq!(x.abs(), x); - /// assert_eq!(y.abs(), -y); - /// - /// assert!(f16::NAN.abs().is_nan()); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub const fn abs(self) -> Self { - // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available - Self::from_bits(self.to_bits() & !(1 << 15)) - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - NaN if the number is NaN - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { - /// - /// let f = 3.5_f16; - /// - /// assert_eq!(f.signum(), 1.0); - /// assert_eq!(f16::NEG_INFINITY.signum(), -1.0); - /// - /// assert!(f16::NAN.signum().is_nan()); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub const fn signum(self) -> f16 { - if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) } - } - - /// Returns a number composed of the magnitude of `self` and the sign of - /// `sign`. - /// - /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. - /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is - /// returned. - /// - /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note - /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust - /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the - /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable - /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more - /// info. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #[cfg(reliable_f16_math)] { - /// - /// let f = 3.5_f16; - /// - /// assert_eq!(f.copysign(0.42), 3.5_f16); - /// assert_eq!(f.copysign(-0.42), -3.5_f16); - /// assert_eq!((-f).copysign(0.42), 3.5_f16); - /// assert_eq!((-f).copysign(-0.42), -3.5_f16); - /// - /// assert!(f16::NAN.copysign(1.0).is_nan()); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub const fn copysign(self, sign: f16) -> f16 { - unsafe { intrinsics::copysignf16(self, sign) } - } - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// diff --git a/std/src/f32.rs b/std/src/f32.rs index 30cf4e1f756e0..7cb285bbff5f7 100644 --- a/std/src/f32.rs +++ b/std/src/f32.rs @@ -176,90 +176,6 @@ impl f32 { self - self.trunc() } - /// Computes the absolute value of `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// let x = 3.5_f32; - /// let y = -3.5_f32; - /// - /// assert_eq!(x.abs(), x); - /// assert_eq!(y.abs(), -y); - /// - /// assert!(f32::NAN.abs().is_nan()); - /// ``` - #[rustc_allow_incoherent_impl] - #[must_use = "method returns a new number and does not mutate the original value"] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[inline] - pub const fn abs(self) -> f32 { - unsafe { intrinsics::fabsf32(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - NaN if the number is NaN - /// - /// # Examples - /// - /// ``` - /// let f = 3.5_f32; - /// - /// assert_eq!(f.signum(), 1.0); - /// assert_eq!(f32::NEG_INFINITY.signum(), -1.0); - /// - /// assert!(f32::NAN.signum().is_nan()); - /// ``` - #[rustc_allow_incoherent_impl] - #[must_use = "method returns a new number and does not mutate the original value"] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[inline] - pub const fn signum(self) -> f32 { - if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) } - } - - /// Returns a number composed of the magnitude of `self` and the sign of - /// `sign`. - /// - /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. - /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is - /// returned. - /// - /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note - /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust - /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the - /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable - /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more - /// info. - /// - /// # Examples - /// - /// ``` - /// let f = 3.5_f32; - /// - /// assert_eq!(f.copysign(0.42), 3.5_f32); - /// assert_eq!(f.copysign(-0.42), -3.5_f32); - /// assert_eq!((-f).copysign(0.42), 3.5_f32); - /// assert_eq!((-f).copysign(-0.42), -3.5_f32); - /// - /// assert!(f32::NAN.copysign(1.0).is_nan()); - /// ``` - #[rustc_allow_incoherent_impl] - #[must_use = "method returns a new number and does not mutate the original value"] - #[inline] - #[stable(feature = "copysign", since = "1.35.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - pub const fn copysign(self, sign: f32) -> f32 { - unsafe { intrinsics::copysignf32(self, sign) } - } - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// diff --git a/std/src/f64.rs b/std/src/f64.rs index 51d5476b372d2..47163c272de32 100644 --- a/std/src/f64.rs +++ b/std/src/f64.rs @@ -176,90 +176,6 @@ impl f64 { self - self.trunc() } - /// Computes the absolute value of `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// let x = 3.5_f64; - /// let y = -3.5_f64; - /// - /// assert_eq!(x.abs(), x); - /// assert_eq!(y.abs(), -y); - /// - /// assert!(f64::NAN.abs().is_nan()); - /// ``` - #[rustc_allow_incoherent_impl] - #[must_use = "method returns a new number and does not mutate the original value"] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[inline] - pub const fn abs(self) -> f64 { - unsafe { intrinsics::fabsf64(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - NaN if the number is NaN - /// - /// # Examples - /// - /// ``` - /// let f = 3.5_f64; - /// - /// assert_eq!(f.signum(), 1.0); - /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); - /// - /// assert!(f64::NAN.signum().is_nan()); - /// ``` - #[rustc_allow_incoherent_impl] - #[must_use = "method returns a new number and does not mutate the original value"] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[inline] - pub const fn signum(self) -> f64 { - if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) } - } - - /// Returns a number composed of the magnitude of `self` and the sign of - /// `sign`. - /// - /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`. - /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is - /// returned. - /// - /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note - /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust - /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the - /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable - /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more - /// info. - /// - /// # Examples - /// - /// ``` - /// let f = 3.5_f64; - /// - /// assert_eq!(f.copysign(0.42), 3.5_f64); - /// assert_eq!(f.copysign(-0.42), -3.5_f64); - /// assert_eq!((-f).copysign(0.42), 3.5_f64); - /// assert_eq!((-f).copysign(-0.42), -3.5_f64); - /// - /// assert!(f64::NAN.copysign(1.0).is_nan()); - /// ``` - #[rustc_allow_incoherent_impl] - #[must_use = "method returns a new number and does not mutate the original value"] - #[stable(feature = "copysign", since = "1.35.0")] - #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] - #[inline] - pub const fn copysign(self, sign: f64) -> f64 { - unsafe { intrinsics::copysignf64(self, sign) } - } - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index 2243f100643df..328185d1f2b0c 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -112,7 +112,7 @@ impl crate::sealed::Sealed for OsString {} /// [conversions]: super#conversions #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] -// `OsStr::from_inner` current implementation relies +// `OsStr::from_inner` and `impl CloneToUninit for OsStr` current implementation relies // on `OsStr` being layout-compatible with `Slice`. // However, `OsStr` layout is considered an implementation detail and must not be relied upon. #[repr(transparent)] @@ -550,11 +550,15 @@ impl OsString { OsStr::from_inner_mut(self.inner.leak()) } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Truncate the the `OsString` to the specified length. + /// + /// # Panics + /// Panics if `len` does not lie on a valid `OsStr` boundary + /// (as described in [`OsStr::slice_encoded_bytes`]). #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + #[unstable(feature = "os_string_truncate", issue = "133262")] + pub fn truncate(&mut self, len: usize) { + self.as_os_str().inner.check_public_boundary(len); self.inner.truncate(len); } @@ -1225,6 +1229,15 @@ impl From<&OsStr> for Box { } } +#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut OsStr> for Box { + /// Copies the string into a newly allocated [Box]<[OsStr]>. + #[inline] + fn from(s: &mut OsStr) -> Box { + Self::from(&*s) + } +} + #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { /// Converts a `Cow<'a, OsStr>` into a [Box]<[OsStr]>, @@ -1269,9 +1282,9 @@ impl Clone for Box { unsafe impl CloneToUninit for OsStr { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { - // SAFETY: we're just a wrapper around a platform-specific Slice - unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around a platform-specific Slice + unsafe { self.inner.clone_to_uninit(dst) } } } @@ -1296,6 +1309,15 @@ impl From<&OsStr> for Arc { } } +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut OsStr> for Arc { + /// Copies the string into a newly allocated [Arc]<[OsStr]>. + #[inline] + fn from(s: &mut OsStr) -> Arc { + Arc::from(&*s) + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { /// Converts an [`OsString`] into an [Rc]<[OsStr]> by moving the [`OsString`] @@ -1317,6 +1339,15 @@ impl From<&OsStr> for Rc { } } +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut OsStr> for Rc { + /// Copies the string into a newly allocated [Rc]<[OsStr]>. + #[inline] + fn from(s: &mut OsStr) -> Rc { + Rc::from(&*s) + } +} + #[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From for Cow<'a, OsStr> { /// Moves the string into a [`Cow::Owned`]. diff --git a/std/src/ffi/os_str/tests.rs b/std/src/ffi/os_str/tests.rs index 67147934b4db3..cbec44c862646 100644 --- a/std/src/ffi/os_str/tests.rs +++ b/std/src/ffi/os_str/tests.rs @@ -294,12 +294,12 @@ fn clone_to_uninit() { let a = OsStr::new("hello.txt"); let mut storage = vec![MaybeUninit::::uninit(); size_of_val::(a)]; - unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut OsStr) }; + unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) }; assert_eq!(a.as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) }); let mut b: Box = OsStr::new("world.exe").into(); assert_eq!(size_of_val::(a), size_of_val::(&b)); assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b)) }; + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; assert_eq!(a, &*b); } diff --git a/std/src/fs.rs b/std/src/fs.rs index 3079c8b1d905a..d846a4e5f0916 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -624,6 +624,223 @@ impl File { self.inner.datasync() } + /// Acquire an exclusive advisory lock on the file. Blocks until the lock can be acquired. + /// + /// This acquires an exclusive advisory lock; no other file handle to this file may acquire + /// another lock. + /// + /// If this file handle, or a clone of it, already holds an advisory lock the exact behavior is + /// unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then an exclusive lock is held. + /// + /// If the file not open for writing, it is unspecified whether this function returns an error. + /// + /// Note, this is an advisory lock meant to interact with [`lock_shared`], [`try_lock`], + /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] + /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag, + /// and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` flag. Note that, + /// this [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// [`lock_shared`]: File::lock_shared + /// [`try_lock`]: File::try_lock + /// [`try_lock_shared`]: File::try_lock_shared + /// [`unlock`]: File::unlock + /// [`read`]: Read::read + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.lock()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn lock(&self) -> io::Result<()> { + self.inner.lock() + } + + /// Acquire a shared advisory lock on the file. Blocks until the lock can be acquired. + /// + /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but + /// none may hold an exclusive lock. + /// + /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is + /// unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then a shared lock is held. + /// + /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], + /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] + /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag, + /// and the `LockFileEx` function on Windows. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// [`lock`]: File::lock + /// [`try_lock`]: File::try_lock + /// [`try_lock_shared`]: File::try_lock_shared + /// [`unlock`]: File::unlock + /// [`read`]: Read::read + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.lock_shared()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn lock_shared(&self) -> io::Result<()> { + self.inner.lock_shared() + } + + /// Acquire an exclusive advisory lock on the file. Returns `Ok(false)` if the file is locked. + /// + /// This acquires an exclusive advisory lock; no other file handle to this file may acquire + /// another lock. + /// + /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is + /// unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then an exclusive lock is held. + /// + /// If the file not open for writing, it is unspecified whether this function returns an error. + /// + /// Note, this is an advisory lock meant to interact with [`lock`], [`lock_shared`], + /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] + /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and + /// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` + /// and `LOCKFILE_FAIL_IMMEDIATELY` flags. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// [`lock`]: File::lock + /// [`lock_shared`]: File::lock_shared + /// [`try_lock_shared`]: File::try_lock_shared + /// [`unlock`]: File::unlock + /// [`read`]: Read::read + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.try_lock()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn try_lock(&self) -> io::Result { + self.inner.try_lock() + } + + /// Acquire a shared advisory lock on the file. + /// Returns `Ok(false)` if the file is exclusively locked. + /// + /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but + /// none may hold an exclusive lock. + /// + /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is + /// unspecified and platform dependent, including the possibility that it will deadlock. + /// However, if this method returns, then a shared lock is held. + /// + /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], + /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`] + /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and + /// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the + /// `LOCKFILE_FAIL_IMMEDIATELY` flag. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// [`lock`]: File::lock + /// [`lock_shared`]: File::lock_shared + /// [`try_lock`]: File::try_lock + /// [`unlock`]: File::unlock + /// [`read`]: Read::read + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.try_lock_shared()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn try_lock_shared(&self) -> io::Result { + self.inner.try_lock_shared() + } + + /// Release all locks on the file. + /// + /// All remaining locks are released when the file handle, and all clones of it, are dropped. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `flock` function on Unix with the `LOCK_UN` flag, + /// and the `UnlockFile` function on Windows. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_lock)] + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// f.lock()?; + /// f.unlock()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_lock", issue = "130994")] + pub fn unlock(&self) -> io::Result<()> { + self.inner.unlock() + } + /// Truncates or extends the underlying file, updating the size of /// this file to become `size`. /// @@ -2521,6 +2738,10 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// Removes an empty directory. /// +/// If you want to remove a directory that is not empty, as well as all +/// of its contents recursively, consider using [`remove_dir_all`] +/// instead. +/// /// # Platform-specific behavior /// /// This function currently corresponds to the `rmdir` function on Unix @@ -2583,8 +2804,9 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// See [`fs::remove_file`] and [`fs::remove_dir`]. /// -/// `remove_dir_all` will fail if `remove_dir` or `remove_file` fail on any constituent paths, including the root path. +/// `remove_dir_all` will fail if `remove_dir` or `remove_file` fail on any constituent paths, including the root `path`. /// As a result, the directory you are deleting must exist, meaning that this function is not idempotent. +/// Additionally, `remove_dir_all` will also fail if the `path` is not a directory. /// /// Consider ignoring the error if validating the removal is not required for your use case. /// diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index 0672fe6f7718a..018e19586418e 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -203,6 +203,152 @@ fn file_test_io_seek_and_write() { assert!(read_str == final_msg); } +#[test] +#[cfg(any( + windows, + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", +))] +fn file_lock_multiple_shared() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_multiple_shared_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // Check that we can acquire concurrent shared locks + check!(f1.lock_shared()); + check!(f2.lock_shared()); + check!(f1.unlock()); + check!(f2.unlock()); + assert!(check!(f1.try_lock_shared())); + assert!(check!(f2.try_lock_shared())); +} + +#[test] +#[cfg(any( + windows, + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", +))] +fn file_lock_blocking() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_blocking_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // Check that shared locks block exclusive locks + check!(f1.lock_shared()); + assert!(!check!(f2.try_lock())); + check!(f1.unlock()); + + // Check that exclusive locks block shared locks + check!(f1.lock()); + assert!(!check!(f2.try_lock_shared())); +} + +#[test] +#[cfg(any( + windows, + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", +))] +fn file_lock_drop() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_dup_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // Check that locks are released when the File is dropped + check!(f1.lock_shared()); + assert!(!check!(f2.try_lock())); + drop(f1); + assert!(check!(f2.try_lock())); +} + +#[test] +#[cfg(any( + windows, + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", +))] +fn file_lock_dup() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_dup_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // Check that locks are not dropped if the File has been cloned + check!(f1.lock_shared()); + assert!(!check!(f2.try_lock())); + let cloned = check!(f1.try_clone()); + drop(f1); + assert!(!check!(f2.try_lock())); + drop(cloned) +} + +#[test] +#[cfg(windows)] +fn file_lock_double_unlock() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_double_unlock_test.txt"); + let f1 = check!(File::create(filename)); + let f2 = check!(OpenOptions::new().write(true).open(filename)); + + // On Windows a file handle may acquire both a shared and exclusive lock. + // Check that both are released by unlock() + check!(f1.lock()); + check!(f1.lock_shared()); + assert!(!check!(f2.try_lock())); + check!(f1.unlock()); + assert!(check!(f2.try_lock())); +} + +#[test] +#[cfg(windows)] +fn file_lock_blocking_async() { + use crate::thread::{sleep, spawn}; + const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; + + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_lock_blocking_async.txt"); + let f1 = check!(File::create(filename)); + let f2 = + check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(filename)); + + check!(f1.lock()); + + // Ensure that lock() is synchronous when the file is opened for asynchronous IO + let t = spawn(move || { + check!(f2.lock()); + }); + sleep(Duration::from_secs(1)); + assert!(!t.is_finished()); + check!(f1.unlock()); + t.join().unwrap(); + + // Ensure that lock_shared() is synchronous when the file is opened for asynchronous IO + let f2 = + check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(filename)); + check!(f1.lock()); + + // Ensure that lock() is synchronous when the file is opened for asynchronous IO + let t = spawn(move || { + check!(f2.lock_shared()); + }); + sleep(Duration::from_secs(1)); + assert!(!t.is_finished()); + check!(f1.unlock()); + t.join().unwrap(); +} + #[test] fn file_test_io_seek_shakedown() { // 01234567890123 diff --git a/std/src/hash/random.rs b/std/src/hash/random.rs index 40f3a90f60c8a..236803b24a2ec 100644 --- a/std/src/hash/random.rs +++ b/std/src/hash/random.rs @@ -105,9 +105,8 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] #[inline] #[allow(deprecated)] - #[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[must_use] - pub const fn new() -> DefaultHasher { + pub fn new() -> DefaultHasher { DefaultHasher(SipHasher13::new_with_keys(0, 0)) } } diff --git a/std/src/io/cursor.rs b/std/src/io/cursor.rs index 9f913eae09544..fbfdb4fa02323 100644 --- a/std/src/io/cursor.rs +++ b/std/src/io/cursor.rs @@ -153,7 +153,8 @@ impl Cursor { /// let reference = buff.get_mut(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn get_mut(&mut self) -> &mut T { &mut self.inner } @@ -200,7 +201,8 @@ impl Cursor { /// assert_eq!(buff.position(), 4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_position(&mut self, pos: u64) { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn set_position(&mut self, pos: u64) { self.pos = pos; } } diff --git a/std/src/io/error.rs b/std/src/io/error.rs index adf103e9430b8..5d7adcace5247 100644 --- a/std/src/io/error.rs +++ b/std/src/io/error.rs @@ -818,10 +818,12 @@ impl Error { /// Consumes the `Error`, returning its inner error (if any). /// - /// If this [`Error`] was constructed via [`new`] then this function will - /// return [`Some`], otherwise it will return [`None`]. + /// If this [`Error`] was constructed via [`new`] or [`other`], + /// then this function will return [`Some`], + /// otherwise it will return [`None`]. /// /// [`new`]: Error::new + /// [`other`]: Error::other /// /// # Examples /// diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 71dfd0676c942..21e7077495450 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -1340,6 +1340,25 @@ impl<'a> IoSliceMut<'a> { bufs[0].advance(left); } } + + /// Get the underlying bytes as a mutable slice with the original lifetime. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_slice_as_bytes)] + /// use std::io::IoSliceMut; + /// + /// let mut data = *b"abcdef"; + /// let io_slice = IoSliceMut::new(&mut data); + /// io_slice.into_slice()[0] = b'A'; + /// + /// assert_eq!(&data, b"Abcdef"); + /// ``` + #[unstable(feature = "io_slice_as_bytes", issue = "132818")] + pub const fn into_slice(self) -> &'a mut [u8] { + self.0.into_slice() + } } #[stable(feature = "iovec", since = "1.36.0")] @@ -1482,6 +1501,32 @@ impl<'a> IoSlice<'a> { bufs[0].advance(left); } } + + /// Get the underlying bytes as a slice with the original lifetime. + /// + /// This doesn't borrow from `self`, so is less restrictive than calling + /// `.deref()`, which does. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_slice_as_bytes)] + /// use std::io::IoSlice; + /// + /// let data = b"abcdef"; + /// + /// let mut io_slice = IoSlice::new(data); + /// let tail = &io_slice.as_slice()[3..]; + /// + /// // This works because `tail` doesn't borrow `io_slice` + /// io_slice = IoSlice::new(tail); + /// + /// assert_eq!(io_slice.as_slice(), b"def"); + /// ``` + #[unstable(feature = "io_slice_as_bytes", issue = "132818")] + pub const fn as_slice(self) -> &'a [u8] { + self.0.as_slice() + } } #[stable(feature = "iovec", since = "1.36.0")] diff --git a/std/src/io/tests.rs b/std/src/io/tests.rs index 56b71c47dc73c..89e806c08911c 100644 --- a/std/src/io/tests.rs +++ b/std/src/io/tests.rs @@ -531,6 +531,20 @@ fn io_slice_advance_slices_beyond_total_length() { assert!(bufs.is_empty()); } +#[test] +fn io_slice_as_slice() { + let buf = [1; 8]; + let slice = IoSlice::new(&buf).as_slice(); + assert_eq!(slice, buf); +} + +#[test] +fn io_slice_into_slice() { + let mut buf = [1; 8]; + let slice = IoSliceMut::new(&mut buf).into_slice(); + assert_eq!(slice, [1; 8]); +} + /// Creates a new writer that reads from at most `n_bufs` and reads /// `per_call` bytes (in total) per call to write. fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { diff --git a/std/src/keyword_docs.rs b/std/src/keyword_docs.rs index 30d43c8bbfd8c..4302e24781ee8 100644 --- a/std/src/keyword_docs.rs +++ b/std/src/keyword_docs.rs @@ -1448,6 +1448,9 @@ mod self_upper_keyword {} /// in a multithreaded context. As such, all accesses to mutable `static`s /// require an [`unsafe`] block. /// +/// When possible, it's often better to use a non-mutable `static` with an +/// interior mutable type such as [`Mutex`], [`OnceLock`], or an [atomic]. +/// /// Despite their unsafety, mutable `static`s are necessary in many contexts: /// they can be used to represent global state shared by the whole program or in /// [`extern`] blocks to bind to variables from C libraries. @@ -1468,7 +1471,10 @@ mod self_upper_keyword {} /// [`extern`]: keyword.extern.html /// [`mut`]: keyword.mut.html /// [`unsafe`]: keyword.unsafe.html +/// [`Mutex`]: sync::Mutex +/// [`OnceLock`]: sync::OnceLock /// [`RefCell`]: cell::RefCell +/// [atomic]: sync::atomic /// [Reference]: ../reference/items/static-items.html mod static_keyword {} diff --git a/std/src/lib.rs b/std/src/lib.rs index d0dd991a93395..ee6fceb024fd7 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -32,14 +32,12 @@ //! //! Once you are familiar with the contents of the standard library you may //! begin to find the verbosity of the prose distracting. At this stage in your -//! development you may want to press the -//! -//! Summary button near the -//! top of the page to collapse it into a more skimmable view. +//! development you may want to press the +//! " Summary" +//! button near the top of the page to collapse it into a more skimmable view. //! //! While you are looking at the top of the page, also notice the -//! source link. Rust's API documentation comes with the source +//! "Source" link. Rust's API documentation comes with the source //! code and you are encouraged to read it. The standard library source is //! generally high quality and a peek behind the curtains is //! often enlightening. @@ -176,9 +174,6 @@ //! //! - after-main use of thread-locals, which also affects additional features: //! - [`thread::current()`] -//! - [`thread::scope()`] -//! - [`sync::mpmc`] -//! - [`sync::mpsc`] //! - before-main stdio file descriptors are not guaranteed to be open on unix platforms //! //! @@ -290,7 +285,6 @@ #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(concat_idents)] -#![feature(const_float_methods)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] @@ -328,6 +322,7 @@ // Library features (core): // tidy-alphabetical-start #![feature(array_chunks)] +#![feature(build_hasher_default_const_new)] #![feature(c_str_module)] #![feature(char_internals)] #![feature(clone_to_uninit)] @@ -415,7 +410,6 @@ // Only for const-ness: // tidy-alphabetical-start #![feature(const_collections_with_hasher)] -#![feature(const_hash)] #![feature(thread_local_internals)] // tidy-alphabetical-end // @@ -660,6 +654,8 @@ pub mod arch { pub use std_detect::is_aarch64_feature_detected; #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] pub use std_detect::is_arm_feature_detected; + #[unstable(feature = "is_loongarch_feature_detected", issue = "117425")] + pub use std_detect::is_loongarch_feature_detected; #[unstable(feature = "is_riscv_feature_detected", issue = "111192")] pub use std_detect::is_riscv_feature_detected; #[stable(feature = "simd_x86", since = "1.27.0")] diff --git a/std/src/os/darwin/fs.rs b/std/src/os/darwin/fs.rs index 2d154b214b5f0..5740c86e62183 100644 --- a/std/src/os/darwin/fs.rs +++ b/std/src/os/darwin/fs.rs @@ -1,7 +1,8 @@ -#![allow(dead_code)] +//! Darwin-specific extension traits to [`fs`]. +//! +//! [`fs`]: crate::fs +#![stable(feature = "metadata_ext", since = "1.1.0")] -#[allow(deprecated)] -use super::raw; use crate::fs::{self, Metadata}; use crate::sealed::Sealed; use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; @@ -25,7 +26,10 @@ pub trait MetadataExt { methods of this trait" )] #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; + // Only available on macOS and iOS, since they were stably exposed there. + #[cfg(any(doc, target_os = "macos", target_os = "ios"))] + #[doc(cfg(any(target_os = "macos", target_os = "ios")))] + fn as_raw_stat(&self) -> &super::raw::stat; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; @@ -77,8 +81,9 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for Metadata { #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } + #[cfg(any(doc, target_os = "macos", target_os = "ios"))] + fn as_raw_stat(&self) -> &super::raw::stat { + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const super::raw::stat) } } fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 diff --git a/std/src/os/darwin/mod.rs b/std/src/os/darwin/mod.rs index 03401fe8895b9..7a057ddb861b7 100644 --- a/std/src/os/darwin/mod.rs +++ b/std/src/os/darwin/mod.rs @@ -13,7 +13,10 @@ //! `aarch64-apple-darwin` target names, which are mostly named that way for //! legacy reasons. -pub(crate) mod fs; +#![stable(feature = "os_darwin", since = "CURRENT_RUSTC_VERSION")] +#![doc(cfg(target_vendor = "apple"))] + +pub mod fs; // deprecated, but used for public reexport under `std::os::unix::raw`, as // well as `std::os::macos`/`std::os::ios`, because those modules precede the // decision to remove these. diff --git a/std/src/os/fd/owned.rs b/std/src/os/fd/owned.rs index 2d087c03b04b4..388b8a88a1a48 100644 --- a/std/src/os/fd/owned.rs +++ b/std/src/os/fd/owned.rs @@ -173,16 +173,17 @@ impl Drop for OwnedFd { #[inline] fn drop(&mut self) { unsafe { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // opened after we closed ours. - // However, this is usually justified, as some of the major Unices - // do make sure to always close the FD, even when `close()` is interrupted, - // and the scenario is rare to begin with. - // Helpful link to an epic discussion by POSIX workgroup: - // http://austingroupbugs.net/view.php?id=529 + // Note that errors are ignored when closing a file descriptor. According to POSIX 2024, + // we can and indeed should retry `close` on `EINTR` + // (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/close.html), + // but it is not clear yet how well widely-used implementations are conforming with this + // mandate since older versions of POSIX left the state of the FD after an `EINTR` + // unspecified. Ignoring errors is "fine" because some of the major Unices (in + // particular, Linux) do make sure to always close the FD, even when `close()` is + // interrupted, and the scenario is rare to begin with. If we retried on a + // not-POSIX-compliant implementation, the consequences could be really bad since we may + // close the wrong FD. Helpful link to an epic discussion by POSIX workgroup that led to + // the latest POSIX wording: http://austingroupbugs.net/view.php?id=529 #[cfg(not(target_os = "hermit"))] { #[cfg(unix)] diff --git a/std/src/os/ios/mod.rs b/std/src/os/ios/mod.rs index 52d592ed95afa..bd18fc2fa0ca9 100644 --- a/std/src/os/ios/mod.rs +++ b/std/src/os/ios/mod.rs @@ -4,10 +4,8 @@ #[stable(feature = "metadata_ext", since = "1.1.0")] pub mod fs { - #[doc(inline)] #[stable(feature = "file_set_times", since = "1.75.0")] pub use crate::os::darwin::fs::FileTimesExt; - #[doc(inline)] #[stable(feature = "metadata_ext", since = "1.1.0")] pub use crate::os::darwin::fs::MetadataExt; } diff --git a/std/src/os/macos/mod.rs b/std/src/os/macos/mod.rs index 59fe90834c2b4..0681c9b714816 100644 --- a/std/src/os/macos/mod.rs +++ b/std/src/os/macos/mod.rs @@ -4,10 +4,8 @@ #[stable(feature = "metadata_ext", since = "1.1.0")] pub mod fs { - #[doc(inline)] #[stable(feature = "file_set_times", since = "1.75.0")] pub use crate::os::darwin::fs::FileTimesExt; - #[doc(inline)] #[stable(feature = "metadata_ext", since = "1.1.0")] pub use crate::os::darwin::fs::MetadataExt; } diff --git a/std/src/os/mod.rs b/std/src/os/mod.rs index 6701173d1e005..e28a1c3e6d5f4 100644 --- a/std/src/os/mod.rs +++ b/std/src/os/mod.rs @@ -15,7 +15,16 @@ pub mod raw; // documented don't compile (missing things in `libc` which is empty), // so just omit them with an empty module and add the "unstable" attribute. -// unix, linux, wasi and windows are handled a bit differently. +// darwin, unix, linux, wasi and windows are handled a bit differently. +#[cfg(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +))] +#[unstable(issue = "none", feature = "std_internals")] +pub mod darwin {} #[cfg(all( doc, any( @@ -53,6 +62,17 @@ pub mod wasi {} #[unstable(issue = "none", feature = "std_internals")] pub mod windows {} +// darwin +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] +#[cfg(any(target_vendor = "apple", doc))] +pub mod darwin; + // unix #[cfg(not(all( doc, @@ -105,8 +125,6 @@ pub mod windows; pub mod aix; #[cfg(target_os = "android")] pub mod android; -#[cfg(target_vendor = "apple")] -pub(crate) mod darwin; #[cfg(target_os = "dragonfly")] pub mod dragonfly; #[cfg(target_os = "emscripten")] diff --git a/std/src/os/nuttx/raw.rs b/std/src/os/nuttx/raw.rs index 113079cf4abdc..431e66d69a372 100644 --- a/std/src/os/nuttx/raw.rs +++ b/std/src/os/nuttx/raw.rs @@ -1,4 +1,4 @@ -//! rtems raw type definitions +//! NuttX raw type definitions #![stable(feature = "raw_ext", since = "1.1.0")] #![deprecated( diff --git a/std/src/os/unix/mod.rs b/std/src/os/unix/mod.rs index 5c2ec8ef994d4..2f9dffe8c6561 100644 --- a/std/src/os/unix/mod.rs +++ b/std/src/os/unix/mod.rs @@ -42,7 +42,7 @@ mod platform { #[cfg(target_os = "android")] pub use crate::os::android::*; #[cfg(target_vendor = "apple")] - pub(super) use crate::os::darwin::*; + pub use crate::os::darwin::*; #[cfg(target_os = "dragonfly")] pub use crate::os::dragonfly::*; #[cfg(target_os = "emscripten")] diff --git a/std/src/os/unix/process.rs b/std/src/os/unix/process.rs index ef5adaf229088..7c3fa7d6507e7 100644 --- a/std/src/os/unix/process.rs +++ b/std/src/os/unix/process.rs @@ -143,7 +143,7 @@ pub trait CommandExt: Sealed { /// /// This function, unlike `spawn`, will **not** `fork` the process to create /// a new child. Like spawn, however, the default behavior for the stdio - /// descriptors will be to inherited from the current process. + /// descriptors will be to inherit them from the current process. /// /// # Notes /// diff --git a/std/src/path.rs b/std/src/path.rs index 62125f885b2ff..b0291e3aa196f 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -1762,6 +1762,16 @@ impl From<&Path> for Box { } } +#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut Path> for Box { + /// Creates a boxed [`Path`] from a reference. + /// + /// This will allocate and clone `path` to it. + fn from(path: &mut Path) -> Box { + Self::from(&*path) + } +} + #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { /// Creates a boxed [`Path`] from a clone-on-write pointer. @@ -1990,6 +2000,15 @@ impl From<&Path> for Arc { } } +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut Path> for Arc { + /// Converts a [`Path`] into an [`Arc`] by copying the [`Path`] data into a new [`Arc`] buffer. + #[inline] + fn from(s: &mut Path) -> Arc { + Arc::from(&*s) + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { /// Converts a [`PathBuf`] into an [Rc]<[Path]> by moving the [`PathBuf`] data into @@ -2011,6 +2030,15 @@ impl From<&Path> for Rc { } } +#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +impl From<&mut Path> for Rc { + /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer. + #[inline] + fn from(s: &mut Path) -> Rc { + Rc::from(&*s) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for Path { type Owned = PathBuf; @@ -2100,7 +2128,7 @@ impl AsRef for PathBuf { /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "Path")] #[stable(feature = "rust1", since = "1.0.0")] -// `Path::new` current implementation relies +// `Path::new` and `impl CloneToUninit for Path` current implementation relies // on `Path` being layout-compatible with `OsStr`. // However, `Path` layout is considered an implementation detail and must not be relied upon. #[repr(transparent)] @@ -3142,9 +3170,9 @@ impl Path { unsafe impl CloneToUninit for Path { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { - // SAFETY: Path is just a wrapper around OsStr - unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: Path is just a transparent wrapper around OsStr + unsafe { self.inner.clone_to_uninit(dst) } } } diff --git a/std/src/path/tests.rs b/std/src/path/tests.rs index b75793d2bc990..ff3f7151bb834 100644 --- a/std/src/path/tests.rs +++ b/std/src/path/tests.rs @@ -2068,7 +2068,7 @@ fn clone_to_uninit() { let a = Path::new("hello.txt"); let mut storage = vec![MaybeUninit::::uninit(); size_of_val::(a)]; - unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut Path) }; + unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) }; assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) }); @@ -2076,6 +2076,6 @@ fn clone_to_uninit() { let mut b: Box = Path::new("world.exe").into(); assert_eq!(size_of_val::(a), size_of_val::(&b)); assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b)) }; + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; assert_eq!(a, &*b); } diff --git a/std/src/prelude/common.rs b/std/src/prelude/common.rs index b231bd871b3b4..e4731280ffe35 100644 --- a/std/src/prelude/common.rs +++ b/std/src/prelude/common.rs @@ -12,6 +12,9 @@ pub use crate::marker::{Send, Sized, Sync, Unpin}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; +#[unstable(feature = "async_closure", issue = "62290")] +#[doc(no_inline)] +pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; // Re-exported functions #[stable(feature = "rust1", since = "1.0.0")] diff --git a/std/src/sync/lazy_lock.rs b/std/src/sync/lazy_lock.rs index b05615035d7b1..40510f5613450 100644 --- a/std/src/sync/lazy_lock.rs +++ b/std/src/sync/lazy_lock.rs @@ -226,7 +226,7 @@ impl T> LazyLock { } impl LazyLock { - /// Returns a reference to the value if initialized, or `None` if not. + /// Returns a mutable reference to the value if initialized, or `None` if not. /// /// # Examples /// @@ -255,7 +255,7 @@ impl LazyLock { } } - /// Returns a mutable reference to the value if initialized, or `None` if not. + /// Returns a reference to the value if initialized, or `None` if not. /// /// # Examples /// diff --git a/std/src/sync/mpmc/array.rs b/std/src/sync/mpmc/array.rs index 2c8ba411f3023..a467237fef152 100644 --- a/std/src/sync/mpmc/array.rs +++ b/std/src/sync/mpmc/array.rs @@ -346,7 +346,8 @@ impl Channel { } // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), @@ -397,7 +398,8 @@ impl Channel { } // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), diff --git a/std/src/sync/mpmc/context.rs b/std/src/sync/mpmc/context.rs index 2371d32d4ea0d..51aa7e82e7890 100644 --- a/std/src/sync/mpmc/context.rs +++ b/std/src/sync/mpmc/context.rs @@ -69,7 +69,7 @@ impl Context { inner: Arc::new(Inner { select: AtomicUsize::new(Selected::Waiting.into()), packet: AtomicPtr::new(ptr::null_mut()), - thread: thread::current(), + thread: thread::current_or_unnamed(), thread_id: current_thread_id(), }), } @@ -112,8 +112,11 @@ impl Context { /// Waits until an operation is selected and returns it. /// /// If the deadline is reached, `Selected::Aborted` will be selected. + /// + /// # Safety + /// This may only be called from the thread this `Context` belongs to. #[inline] - pub fn wait_until(&self, deadline: Option) -> Selected { + pub unsafe fn wait_until(&self, deadline: Option) -> Selected { loop { // Check whether an operation has been selected. let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); @@ -126,7 +129,8 @@ impl Context { let now = Instant::now(); if now < end { - thread::park_timeout(end - now); + // SAFETY: guaranteed by caller. + unsafe { self.inner.thread.park_timeout(end - now) }; } else { // The deadline has been reached. Try aborting select. return match self.try_select(Selected::Aborted) { @@ -135,7 +139,8 @@ impl Context { }; } } else { - thread::park(); + // SAFETY: guaranteed by caller. + unsafe { self.inner.thread.park() }; } } } diff --git a/std/src/sync/mpmc/list.rs b/std/src/sync/mpmc/list.rs index 88a8c75f7c8b9..d88914f529142 100644 --- a/std/src/sync/mpmc/list.rs +++ b/std/src/sync/mpmc/list.rs @@ -63,14 +63,14 @@ struct Block { impl Block { /// Creates an empty block. - fn new() -> Block { + fn new() -> Box> { // SAFETY: This is safe because: // [1] `Block::next` (AtomicPtr) may be safely zero initialized. // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. // [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it // holds a MaybeUninit. // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. - unsafe { MaybeUninit::zeroed().assume_init() } + unsafe { Box::new_zeroed().assume_init() } } /// Waits until the next pointer is set. @@ -199,13 +199,13 @@ impl Channel { // If we're going to have to install the next block, allocate it in advance in order to // make the wait for other threads as short as possible. if offset + 1 == BLOCK_CAP && next_block.is_none() { - next_block = Some(Box::new(Block::::new())); + next_block = Some(Block::::new()); } // If this is the first message to be sent into the channel, we need to allocate the // first block and install it. if block.is_null() { - let new = Box::into_raw(Box::new(Block::::new())); + let new = Box::into_raw(Block::::new()); if self .tail @@ -444,7 +444,8 @@ impl Channel { } // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), diff --git a/std/src/sync/mpmc/mod.rs b/std/src/sync/mpmc/mod.rs index 44e146a89bafb..0cf4902d6d59b 100644 --- a/std/src/sync/mpmc/mod.rs +++ b/std/src/sync/mpmc/mod.rs @@ -153,6 +153,7 @@ use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::time::{Duration, Instant}; /// Creates a new asynchronous channel, returning the sender/receiver halves. +/// /// All data sent on the [`Sender`] will become available on the [`Receiver`] in /// the same order as it was sent, and no [`send`] will block the calling thread /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will @@ -201,6 +202,7 @@ pub fn channel() -> (Sender, Receiver) { } /// Creates a new synchronous, bounded channel. +/// /// All data sent on the [`Sender`] will become available on the [`Receiver`] /// in the same order as it was sent. Like asynchronous [`channel`]s, the /// [`Receiver`] will block until a message becomes available. `sync_channel` diff --git a/std/src/sync/mpmc/zero.rs b/std/src/sync/mpmc/zero.rs index 446881291e68e..577997c07a636 100644 --- a/std/src/sync/mpmc/zero.rs +++ b/std/src/sync/mpmc/zero.rs @@ -190,7 +190,8 @@ impl Channel { drop(inner); // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), @@ -257,7 +258,8 @@ impl Channel { drop(inner); // Block the current thread. - let sel = cx.wait_until(deadline); + // SAFETY: the context belongs to the current thread. + let sel = unsafe { cx.wait_until(deadline) }; match sel { Selected::Waiting => unreachable!(), diff --git a/std/src/sync/mpsc/mod.rs b/std/src/sync/mpsc/mod.rs index 83a93a0636956..c86b546e01169 100644 --- a/std/src/sync/mpsc/mod.rs +++ b/std/src/sync/mpsc/mod.rs @@ -483,6 +483,7 @@ pub enum TrySendError { } /// Creates a new asynchronous channel, returning the sender/receiver halves. +/// /// All data sent on the [`Sender`] will become available on the [`Receiver`] in /// the same order as it was sent, and no [`send`] will block the calling thread /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will @@ -527,6 +528,7 @@ pub fn channel() -> (Sender, Receiver) { } /// Creates a new synchronous, bounded channel. +/// /// All data sent on the [`SyncSender`] will become available on the [`Receiver`] /// in the same order as it was sent. Like asynchronous [`channel`]s, the /// [`Receiver`] will block until a message becomes available. `sync_channel` diff --git a/std/src/sync/rwlock.rs b/std/src/sync/rwlock.rs index da2da6f9dfc53..d55d1c80dcae0 100644 --- a/std/src/sync/rwlock.rs +++ b/std/src/sync/rwlock.rs @@ -4,10 +4,10 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; -use crate::mem::ManuallyDrop; +use crate::mem::{ManuallyDrop, forget}; use crate::ops::{Deref, DerefMut}; use crate::ptr::NonNull; -use crate::sync::{LockResult, TryLockError, TryLockResult, poison}; +use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison}; use crate::sys::sync as sys; /// A reader-writer lock @@ -574,8 +574,12 @@ impl From for RwLock { impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { /// Creates a new instance of `RwLockReadGuard` from a `RwLock`. - // SAFETY: if and only if `lock.inner.read()` (or `lock.inner.try_read()`) has been - // successfully called from the same thread before instantiating this object. + /// + /// # Safety + /// + /// This function is safe if and only if the same thread has successfully and safely called + /// `lock.inner.read()`, `lock.inner.try_read()`, or `lock.inner.downgrade()` before + /// instantiating this object. unsafe fn new(lock: &'rwlock RwLock) -> LockResult> { poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard { data: unsafe { NonNull::new_unchecked(lock.data.get()) }, @@ -957,6 +961,68 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { None => Err(orig), } } + + /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. + /// + /// This method will atomically change the state of the [`RwLock`] from exclusive mode into + /// shared mode. This means that it is impossible for a writing thread to get in between a + /// thread calling `downgrade` and the same thread reading whatever it wrote while it had the + /// [`RwLock`] in write mode. + /// + /// Note that since we have the `RwLockWriteGuard`, we know that the [`RwLock`] is already + /// locked for writing, so this method cannot fail. + /// + /// # Example + /// + /// ``` + /// #![feature(rwlock_downgrade)] + /// use std::sync::{Arc, RwLock, RwLockWriteGuard}; + /// + /// // The inner value starts as 0. + /// let rw = Arc::new(RwLock::new(0)); + /// + /// // Put the lock in write mode. + /// let mut main_write_guard = rw.write().unwrap(); + /// + /// let evil = rw.clone(); + /// let handle = std::thread::spawn(move || { + /// // This will not return until the main thread drops the `main_read_guard`. + /// let mut evil_guard = evil.write().unwrap(); + /// + /// assert_eq!(*evil_guard, 1); + /// *evil_guard = 2; + /// }); + /// + /// // After spawning the writer thread, set the inner value to 1. + /// *main_write_guard = 1; + /// + /// // Atomically downgrade the write guard into a read guard. + /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + /// + /// // Since `downgrade` is atomic, the writer thread cannot have set the inner value to 2. + /// assert_eq!(*main_read_guard, 1, "`downgrade` was not atomic"); + /// + /// // Clean up everything now + /// drop(main_read_guard); + /// handle.join().unwrap(); + /// + /// let final_check = rw.read().unwrap(); + /// assert_eq!(*final_check, 2); + /// ``` + #[unstable(feature = "rwlock_downgrade", issue = "128203")] + pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> { + let lock = s.lock; + + // We don't want to call the destructor since that calls `write_unlock`. + forget(s); + + // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write + // mode, satisfying the `downgrade` contract. + unsafe { lock.inner.downgrade() }; + + // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract. + unsafe { RwLockReadGuard::new(lock).unwrap_or_else(PoisonError::into_inner) } + } } impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { diff --git a/std/src/sync/rwlock/tests.rs b/std/src/sync/rwlock/tests.rs index 37a2e41641ac1..29cad4400f189 100644 --- a/std/src/sync/rwlock/tests.rs +++ b/std/src/sync/rwlock/tests.rs @@ -501,3 +501,111 @@ fn panic_while_mapping_write_unlocked_poison() { drop(lock); } + +#[test] +fn test_downgrade_basic() { + let r = RwLock::new(()); + + let write_guard = r.write().unwrap(); + let _read_guard = RwLockWriteGuard::downgrade(write_guard); +} + +#[test] +fn test_downgrade_observe() { + // Taken from the test `test_rwlock_downgrade` from: + // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs + + const W: usize = 20; + const N: usize = 100; + + // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring + // that the value they wrote has not changed after downgrading. + + let rw = Arc::new(RwLock::new(0)); + + // Spawn the writers that will do `W * N` operations and checks. + let handles: Vec<_> = (0..W) + .map(|_| { + let rw = rw.clone(); + thread::spawn(move || { + for _ in 0..N { + // Increment the counter. + let mut write_guard = rw.write().unwrap(); + *write_guard += 1; + let cur_val = *write_guard; + + // Downgrade the lock to read mode, where the value protected cannot be modified. + let read_guard = RwLockWriteGuard::downgrade(write_guard); + assert_eq!(cur_val, *read_guard); + } + }) + }) + .collect(); + + for handle in handles { + handle.join().unwrap(); + } + + assert_eq!(*rw.read().unwrap(), W * N); +} + +#[test] +// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. +// See for details. +#[cfg_attr(all(miri, target_os = "macos"), ignore)] +fn test_downgrade_atomic() { + const NEW_VALUE: i32 = -1; + + // This test checks that `downgrade` is atomic, meaning as soon as a write lock has been + // downgraded, the lock must be in read mode and no other threads can take the write lock to + // modify the protected value. + + // `W` is the number of evil writer threads. + const W: usize = 20; + let rwlock = Arc::new(RwLock::new(0)); + + // Spawns many evil writer threads that will try and write to the locked value before the + // initial writer (who has the exclusive lock) can read after it downgrades. + // If the `RwLock` behaves correctly, then the initial writer should read the value it wrote + // itself as no other thread should be able to mutate the protected value. + + // Put the lock in write mode, causing all future threads trying to access this go to sleep. + let mut main_write_guard = rwlock.write().unwrap(); + + // Spawn all of the evil writer threads. They will each increment the protected value by 1. + let handles: Vec<_> = (0..W) + .map(|_| { + let rwlock = rwlock.clone(); + thread::spawn(move || { + // Will go to sleep since the main thread initially has the write lock. + let mut evil_guard = rwlock.write().unwrap(); + *evil_guard += 1; + }) + }) + .collect(); + + // Wait for a good amount of time so that evil threads go to sleep. + // Note: this is not strictly necessary... + let eternity = crate::time::Duration::from_millis(42); + thread::sleep(eternity); + + // Once everyone is asleep, set the value to `NEW_VALUE`. + *main_write_guard = NEW_VALUE; + + // Atomically downgrade the write guard into a read guard. + let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + + // If the above is not atomic, then it would be possible for an evil thread to get in front of + // this read and change the value to be non-negative. + assert_eq!(*main_read_guard, NEW_VALUE, "`downgrade` was not atomic"); + + // Drop the main read guard and allow the evil writer threads to start incrementing. + drop(main_read_guard); + + for handle in handles { + handle.join().unwrap(); + } + + let final_check = rwlock.read().unwrap(); + assert_eq!(*final_check, W as i32 + NEW_VALUE); +} diff --git a/std/src/sys/alloc/windows.rs b/std/src/sys/alloc/windows.rs index a77dda6e817ba..7e2402afab972 100644 --- a/std/src/sys/alloc/windows.rs +++ b/std/src/sys/alloc/windows.rs @@ -3,7 +3,6 @@ use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ffi::c_void; use crate::mem::MaybeUninit; use crate::ptr; -use crate::sync::atomic::{AtomicPtr, Ordering}; use crate::sys::c; #[cfg(test)] @@ -81,40 +80,18 @@ windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc( // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const c_void) -> c::BOOL); -// Cached handle to the default heap of the current process. -// Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed. -static HEAP: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - -// Get a handle to the default heap of the current process, or null if the operation fails. -// If this operation is successful, `HEAP` will be successfully initialized and contain -// a non-null handle returned by `GetProcessHeap`. -#[inline] -fn init_or_get_process_heap() -> c::HANDLE { - // `HEAP` has not yet been successfully initialized - let heap = unsafe { GetProcessHeap() }; - if !heap.is_null() { - // SAFETY: No locking is needed because within the same process, - // successful calls to `GetProcessHeap` will always return the same value, even on different threads. - HEAP.store(heap, Ordering::Release); - - // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap` - heap - } else { - // Could not get the current process heap. - ptr::null_mut() - } +fn get_process_heap() -> *mut c_void { + // SAFETY: GetProcessHeap simply returns a valid handle or NULL so is always safe to call. + unsafe { GetProcessHeap() } } -/// This is outlined from `process_heap_alloc` so that `process_heap_alloc` -/// does not need any stack allocations. #[inline(never)] -#[cold] -extern "C" fn process_heap_init_and_alloc( - _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc` +fn process_heap_alloc( + _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, flags: u32, bytes: usize, ) -> *mut c_void { - let heap = init_or_get_process_heap(); + let heap = get_process_heap(); if core::intrinsics::unlikely(heap.is_null()) { return ptr::null_mut(); } @@ -122,28 +99,6 @@ extern "C" fn process_heap_init_and_alloc( unsafe { HeapAlloc(heap, flags, bytes) } } -#[inline(never)] -fn process_heap_alloc( - _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, - flags: u32, - bytes: usize, -) -> *mut c_void { - let heap = HEAP.load(Ordering::Relaxed); - if core::intrinsics::likely(!heap.is_null()) { - // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. - unsafe { HeapAlloc(heap, flags, bytes) } - } else { - process_heap_init_and_alloc(MaybeUninit::uninit(), flags, bytes) - } -} - -// Get a non-null handle to the default heap of the current process. -// SAFETY: `HEAP` must have been successfully initialized. -#[inline] -unsafe fn get_process_heap() -> c::HANDLE { - HEAP.load(Ordering::Acquire) -} - // Header containing a pointer to the start of an allocated block. // SAFETY: Size and alignment must be <= `MIN_ALIGN`. #[repr(C)] @@ -232,9 +187,9 @@ unsafe impl GlobalAlloc for System { } }; - // SAFETY: because `ptr` has been successfully allocated with this allocator, - // `HEAP` must have been successfully initialized. - let heap = unsafe { get_process_heap() }; + // because `ptr` has been successfully allocated with this allocator, + // there must be a valid process heap. + let heap = get_process_heap(); // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, // `block` is a pointer to the start of an allocated block. @@ -244,9 +199,9 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN { - // SAFETY: because `ptr` has been successfully allocated with this allocator, - // `HEAP` must have been successfully initialized. - let heap = unsafe { get_process_heap() }; + // because `ptr` has been successfully allocated with this allocator, + // there must be a valid process heap. + let heap = get_process_heap(); // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, // `ptr` is a pointer to the start of an allocated block. diff --git a/std/src/sys/os_str/bytes.rs b/std/src/sys/os_str/bytes.rs index 8e0609fe48c53..5b65d862be102 100644 --- a/std/src/sys/os_str/bytes.rs +++ b/std/src/sys/os_str/bytes.rs @@ -352,8 +352,8 @@ impl Slice { unsafe impl CloneToUninit for Slice { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { - // SAFETY: we're just a wrapper around [u8] - unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around [u8] + unsafe { self.inner.clone_to_uninit(dst) } } } diff --git a/std/src/sys/os_str/wtf8.rs b/std/src/sys/os_str/wtf8.rs index b3834388df68a..a4ad5966afe57 100644 --- a/std/src/sys/os_str/wtf8.rs +++ b/std/src/sys/os_str/wtf8.rs @@ -275,8 +275,8 @@ impl Slice { unsafe impl CloneToUninit for Slice { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { - // SAFETY: we're just a wrapper around Wtf8 - unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around Wtf8 + unsafe { self.inner.clone_to_uninit(dst) } } } diff --git a/std/src/sys/pal/hermit/fs.rs b/std/src/sys/pal/hermit/fs.rs index 70f6981f7175b..17d15ed2e5045 100644 --- a/std/src/sys/pal/hermit/fs.rs +++ b/std/src/sys/pal/hermit/fs.rs @@ -364,6 +364,26 @@ impl File { self.fsync() } + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> io::Result { + unsupported() + } + + pub fn try_lock_shared(&self) -> io::Result { + unsupported() + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + pub fn truncate(&self, _size: u64) -> io::Result<()> { Err(Error::from_raw_os_error(22)) } diff --git a/std/src/sys/pal/hermit/io.rs b/std/src/sys/pal/hermit/io.rs index aad1eef71e9b0..0424a1ac55a29 100644 --- a/std/src/sys/pal/hermit/io.rs +++ b/std/src/sys/pal/hermit/io.rs @@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> { } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub const fn as_slice(&self) -> &'a [u8] { unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } } } @@ -70,6 +70,11 @@ impl<'a> IoSliceMut<'a> { unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } } + #[inline] + pub const fn into_slice(self) -> &'a mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } diff --git a/std/src/sys/pal/solid/fs.rs b/std/src/sys/pal/solid/fs.rs index bce9aa6d99cd1..776a96ff3b7ba 100644 --- a/std/src/sys/pal/solid/fs.rs +++ b/std/src/sys/pal/solid/fs.rs @@ -350,6 +350,26 @@ impl File { self.flush() } + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> io::Result { + unsupported() + } + + pub fn try_lock_shared(&self) -> io::Result { + unsupported() + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + pub fn truncate(&self, _size: u64) -> io::Result<()> { unsupported() } diff --git a/std/src/sys/pal/solid/io.rs b/std/src/sys/pal/solid/io.rs index 4b1f788a492c5..9ef4b7049b690 100644 --- a/std/src/sys/pal/solid/io.rs +++ b/std/src/sys/pal/solid/io.rs @@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> { } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub const fn as_slice(&self) -> &'a [u8] { unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } } } @@ -70,6 +70,11 @@ impl<'a> IoSliceMut<'a> { unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } } + #[inline] + pub const fn into_slice(self) -> &'a mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } diff --git a/std/src/sys/pal/uefi/process.rs b/std/src/sys/pal/uefi/process.rs index 0cc9cecb89db0..1b83f4b0aee88 100644 --- a/std/src/sys/pal/uefi/process.rs +++ b/std/src/sys/pal/uefi/process.rs @@ -18,6 +18,7 @@ use crate::{fmt, io}; #[derive(Debug)] pub struct Command { prog: OsString, + args: Vec, stdout: Option, stderr: Option, } @@ -39,12 +40,11 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string(), stdout: None, stderr: None } + Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None } } - // FIXME: Implement arguments as reverse of parsing algorithm - pub fn arg(&mut self, _arg: &OsStr) { - panic!("unsupported") + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_os_string()); } pub fn env_mut(&mut self) -> &mut CommandEnv { @@ -72,7 +72,7 @@ impl Command { } pub fn get_args(&self) -> CommandArgs<'_> { - panic!("unsupported") + CommandArgs { iter: self.args.iter() } } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -116,6 +116,12 @@ impl Command { pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; + // UEFI adds the bin name by default + if !self.args.is_empty() { + let args = uefi_command_internal::create_args(&self.prog, &self.args); + cmd.set_args(args); + } + // Setup Stdout let stdout = self.stdout.unwrap_or(Stdio::MakePipe); let stdout = Self::create_pipe(stdout)?; @@ -315,7 +321,7 @@ mod uefi_command_internal { stdout: Option>, stderr: Option>, st: OwnedTable, - args: Option>, + args: Option<(*mut u16, usize)>, } impl Image { @@ -449,20 +455,20 @@ mod uefi_command_internal { } } - pub fn set_args(&mut self, args: &OsStr) { + pub fn set_args(&mut self, args: Box<[u16]>) { let loaded_image: NonNull = helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); - let mut args = args.encode_wide().collect::>(); - let args_size = (crate::mem::size_of::() * args.len()) as u32; + let len = args.len(); + let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap(); + let ptr = Box::into_raw(args).as_mut_ptr(); unsafe { - (*loaded_image.as_ptr()).load_options = - args.as_mut_ptr() as *mut crate::ffi::c_void; + (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void; (*loaded_image.as_ptr()).load_options_size = args_size; } - self.args = Some(args); + self.args = Some((ptr, len)); } fn update_st_crc32(&mut self) -> io::Result<()> { @@ -502,6 +508,10 @@ mod uefi_command_internal { ((*bt.as_ptr()).unload_image)(self.handle.as_ptr()); } } + + if let Some((ptr, len)) = self.args { + let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) }; + } } } @@ -681,4 +691,38 @@ mod uefi_command_internal { } } } + + pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { + const QUOTE: u16 = 0x0022; + const SPACE: u16 = 0x0020; + const CARET: u16 = 0x005e; + const NULL: u16 = 0; + + // This is the lower bound on the final length under the assumption that + // the arguments only contain ASCII characters. + let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum()); + + // Wrap program name in quotes to avoid any problems + res.push(QUOTE); + res.extend(prog.encode_wide()); + res.push(QUOTE); + res.push(SPACE); + + for arg in args { + // Wrap the argument in quotes to be treat as single arg + res.push(QUOTE); + for c in arg.encode_wide() { + // CARET in quotes is used to escape CARET or QUOTE + if c == QUOTE || c == CARET { + res.push(CARET); + } + res.push(c); + } + res.push(QUOTE); + + res.push(SPACE); + } + + res.into_boxed_slice() + } } diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index f1f843a5f7ae7..96f99efb21e84 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -1254,6 +1254,123 @@ impl File { } } + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + ))] + pub fn lock(&self) -> io::Result<()> { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX) })?; + return Ok(()); + } + + #[cfg(not(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + )))] + pub fn lock(&self) -> io::Result<()> { + Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock() not supported")) + } + + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + ))] + pub fn lock_shared(&self) -> io::Result<()> { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH) })?; + return Ok(()); + } + + #[cfg(not(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + )))] + pub fn lock_shared(&self) -> io::Result<()> { + Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock_shared() not supported")) + } + + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + ))] + pub fn try_lock(&self) -> io::Result { + let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) }); + if let Err(ref err) = result { + if err.kind() == io::ErrorKind::WouldBlock { + return Ok(false); + } + } + result?; + return Ok(true); + } + + #[cfg(not(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + )))] + pub fn try_lock(&self) -> io::Result { + Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock() not supported")) + } + + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + ))] + pub fn try_lock_shared(&self) -> io::Result { + let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) }); + if let Err(ref err) = result { + if err.kind() == io::ErrorKind::WouldBlock { + return Ok(false); + } + } + result?; + return Ok(true); + } + + #[cfg(not(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + )))] + pub fn try_lock_shared(&self) -> io::Result { + Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported")) + } + + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + ))] + pub fn unlock(&self) -> io::Result<()> { + cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_UN) })?; + return Ok(()); + } + + #[cfg(not(any( + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", + )))] + pub fn unlock(&self) -> io::Result<()> { + Err(io::const_io_error!(io::ErrorKind::Unsupported, "unlock() not supported")) + } + pub fn truncate(&self, size: u64) -> io::Result<()> { let size: off64_t = size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; diff --git a/std/src/sys/pal/unix/io.rs b/std/src/sys/pal/unix/io.rs index 181c35a971eca..0d5a152dc0dc6 100644 --- a/std/src/sys/pal/unix/io.rs +++ b/std/src/sys/pal/unix/io.rs @@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> { } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub const fn as_slice(&self) -> &'a [u8] { unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } } } @@ -70,6 +70,11 @@ impl<'a> IoSliceMut<'a> { unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } } + #[inline] + pub const fn into_slice(self) -> &'a mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } diff --git a/std/src/sys/pal/unix/os.rs b/std/src/sys/pal/unix/os.rs index f983d174ed61c..f207131ddf332 100644 --- a/std/src/sys/pal/unix/os.rs +++ b/std/src/sys/pal/unix/os.rs @@ -698,12 +698,82 @@ pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } } +// Returns the value for [`confstr(key, ...)`][posix_confstr]. Currently only +// used on Darwin, but should work on any unix (in case we need to get +// `_CS_PATH` or `_CS_V[67]_ENV` in the future). +// +// [posix_confstr]: +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html +// +// FIXME: Support `confstr` in Miri. +#[cfg(all(target_vendor = "apple", not(miri)))] +fn confstr(key: c_int, size_hint: Option) -> io::Result { + let mut buf: Vec = Vec::with_capacity(0); + let mut bytes_needed_including_nul = size_hint + .unwrap_or_else(|| { + // Treat "None" as "do an extra call to get the length". In theory + // we could move this into the loop below, but it's hard to do given + // that it isn't 100% clear if it's legal to pass 0 for `len` when + // the buffer isn't null. + unsafe { libc::confstr(key, core::ptr::null_mut(), 0) } + }) + .max(1); + // If the value returned by `confstr` is greater than the len passed into + // it, then the value was truncated, meaning we need to retry. Note that + // while `confstr` results don't seem to change for a process, it's unclear + // if this is guaranteed anywhere, so looping does seem required. + while bytes_needed_including_nul > buf.capacity() { + // We write into the spare capacity of `buf`. This lets us avoid + // changing buf's `len`, which both simplifies `reserve` computation, + // allows working with `Vec` instead of `Vec>`, and + // may avoid a copy, since the Vec knows that none of the bytes are needed + // when reallocating (well, in theory anyway). + buf.reserve(bytes_needed_including_nul); + // `confstr` returns + // - 0 in the case of errors: we break and return an error. + // - The number of bytes written, iff the provided buffer is enough to + // hold the entire value: we break and return the data in `buf`. + // - Otherwise, the number of bytes needed (including nul): we go + // through the loop again. + bytes_needed_including_nul = + unsafe { libc::confstr(key, buf.as_mut_ptr().cast::(), buf.capacity()) }; + } + // `confstr` returns 0 in the case of an error. + if bytes_needed_including_nul == 0 { + return Err(io::Error::last_os_error()); + } + // Safety: `confstr(..., buf.as_mut_ptr(), buf.capacity())` returned a + // non-zero value, meaning `bytes_needed_including_nul` bytes were + // initialized. + unsafe { + buf.set_len(bytes_needed_including_nul); + // Remove the NUL-terminator. + let last_byte = buf.pop(); + // ... and smoke-check that it *was* a NUL-terminator. + assert_eq!(last_byte, Some(0), "`confstr` provided a string which wasn't nul-terminated"); + }; + Ok(OsString::from_vec(buf)) +} + +#[cfg(all(target_vendor = "apple", not(miri)))] +fn darwin_temp_dir() -> PathBuf { + confstr(libc::_CS_DARWIN_USER_TEMP_DIR, Some(64)).map(PathBuf::from).unwrap_or_else(|_| { + // It failed for whatever reason (there are several possible reasons), + // so return the global one. + PathBuf::from("/tmp") + }) +} + pub fn temp_dir() -> PathBuf { crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| { - if cfg!(target_os = "android") { - PathBuf::from("/data/local/tmp") - } else { - PathBuf::from("/tmp") + cfg_if::cfg_if! { + if #[cfg(all(target_vendor = "apple", not(miri)))] { + darwin_temp_dir() + } else if #[cfg(target_os = "android")] { + PathBuf::from("/data/local/tmp") + } else { + PathBuf::from("/tmp") + } } }) } diff --git a/std/src/sys/pal/unix/os/tests.rs b/std/src/sys/pal/unix/os/tests.rs index efc29955b05fe..63a1cc1e94a1d 100644 --- a/std/src/sys/pal/unix/os/tests.rs +++ b/std/src/sys/pal/unix/os/tests.rs @@ -21,3 +21,28 @@ fn test_parse_glibc_version() { assert_eq!(parsed, super::parse_glibc_version(version_str)); } } + +// Smoke check `confstr`, do it for several hint values, to ensure our resizing +// logic is correct. +#[test] +#[cfg(all(target_vendor = "apple", not(miri)))] +fn test_confstr() { + for key in [libc::_CS_DARWIN_USER_TEMP_DIR, libc::_CS_PATH] { + let value_nohint = super::confstr(key, None).unwrap_or_else(|e| { + panic!("confstr({key}, None) failed: {e:?}"); + }); + let end = (value_nohint.len() + 1) * 2; + for hint in 0..end { + assert_eq!( + super::confstr(key, Some(hint)).as_deref().ok(), + Some(&*value_nohint), + "confstr({key}, Some({hint})) failed", + ); + } + } + // Smoke check that we don't loop forever or something if the input was not valid. + for hint in [None, Some(0), Some(1)] { + let hopefully_invalid = 123456789_i32; + assert!(super::confstr(hopefully_invalid, hint).is_err()); + } +} diff --git a/std/src/sys/pal/unix/pipe.rs b/std/src/sys/pal/unix/pipe.rs index f0ebc767badad..4a992e32a9184 100644 --- a/std/src/sys/pal/unix/pipe.rs +++ b/std/src/sys/pal/unix/pipe.rs @@ -23,6 +23,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { target_os = "dragonfly", target_os = "freebsd", target_os = "hurd", + target_os = "illumos", target_os = "linux", target_os = "netbsd", target_os = "openbsd", diff --git a/std/src/sys/pal/unsupported/fs.rs b/std/src/sys/pal/unsupported/fs.rs index 474c9fe97d18d..9585ec24f687d 100644 --- a/std/src/sys/pal/unsupported/fs.rs +++ b/std/src/sys/pal/unsupported/fs.rs @@ -198,6 +198,26 @@ impl File { self.0 } + pub fn lock(&self) -> io::Result<()> { + self.0 + } + + pub fn lock_shared(&self) -> io::Result<()> { + self.0 + } + + pub fn try_lock(&self) -> io::Result { + self.0 + } + + pub fn try_lock_shared(&self) -> io::Result { + self.0 + } + + pub fn unlock(&self) -> io::Result<()> { + self.0 + } + pub fn truncate(&self, _size: u64) -> io::Result<()> { self.0 } diff --git a/std/src/sys/pal/unsupported/io.rs b/std/src/sys/pal/unsupported/io.rs index 6372fca74e0d7..604735d32d51a 100644 --- a/std/src/sys/pal/unsupported/io.rs +++ b/std/src/sys/pal/unsupported/io.rs @@ -15,7 +15,7 @@ impl<'a> IoSlice<'a> { } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub const fn as_slice(&self) -> &'a [u8] { self.0 } } @@ -40,6 +40,11 @@ impl<'a> IoSliceMut<'a> { self.0 } + #[inline] + pub const fn into_slice(self) -> &'a mut [u8] { + self.0 + } + #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { self.0 diff --git a/std/src/sys/pal/wasi/fs.rs b/std/src/sys/pal/wasi/fs.rs index 59ecc45b06a1f..3296c762cca2b 100644 --- a/std/src/sys/pal/wasi/fs.rs +++ b/std/src/sys/pal/wasi/fs.rs @@ -420,6 +420,26 @@ impl File { self.fd.datasync() } + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> io::Result { + unsupported() + } + + pub fn try_lock_shared(&self) -> io::Result { + unsupported() + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + pub fn truncate(&self, size: u64) -> io::Result<()> { self.fd.filestat_set_size(size) } diff --git a/std/src/sys/pal/wasi/io.rs b/std/src/sys/pal/wasi/io.rs index b7c2f03daa048..57f81bc6257cd 100644 --- a/std/src/sys/pal/wasi/io.rs +++ b/std/src/sys/pal/wasi/io.rs @@ -30,7 +30,7 @@ impl<'a> IoSlice<'a> { } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub const fn as_slice(&self) -> &'a [u8] { unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) } } } @@ -67,6 +67,11 @@ impl<'a> IoSliceMut<'a> { unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) } } + #[inline] + pub const fn into_slice(self) -> &'a mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) } + } + #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) } diff --git a/std/src/sys/pal/windows/c/bindings.txt b/std/src/sys/pal/windows/c/bindings.txt index 192c95fd203c6..248ce3c9ff624 100644 --- a/std/src/sys/pal/windows/c/bindings.txt +++ b/std/src/sys/pal/windows/c/bindings.txt @@ -2351,6 +2351,9 @@ Windows.Win32.Storage.FileSystem.GetFinalPathNameByHandleW Windows.Win32.Storage.FileSystem.GetFullPathNameW Windows.Win32.Storage.FileSystem.GetTempPathW Windows.Win32.Storage.FileSystem.INVALID_FILE_ATTRIBUTES +Windows.Win32.Storage.FileSystem.LOCKFILE_EXCLUSIVE_LOCK +Windows.Win32.Storage.FileSystem.LOCKFILE_FAIL_IMMEDIATELY +Windows.Win32.Storage.FileSystem.LockFileEx Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE_CALLBACK_REASON Windows.Win32.Storage.FileSystem.MAXIMUM_REPARSE_DATA_BUFFER_SIZE @@ -2396,6 +2399,7 @@ Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAG_DIRECTORY Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAGS Windows.Win32.Storage.FileSystem.SYNCHRONIZE Windows.Win32.Storage.FileSystem.TRUNCATE_EXISTING +Windows.Win32.Storage.FileSystem.UnlockFile Windows.Win32.Storage.FileSystem.VOLUME_NAME_DOS Windows.Win32.Storage.FileSystem.VOLUME_NAME_GUID Windows.Win32.Storage.FileSystem.VOLUME_NAME_NONE diff --git a/std/src/sys/pal/windows/c/windows_sys.rs b/std/src/sys/pal/windows/c/windows_sys.rs index 52444c2c009ed..19925e59dfe9c 100644 --- a/std/src/sys/pal/windows/c/windows_sys.rs +++ b/std/src/sys/pal/windows/c/windows_sys.rs @@ -65,6 +65,7 @@ windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinit windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL); +windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32); windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL); @@ -96,6 +97,7 @@ windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32) windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> BOOLEAN); windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> BOOLEAN); +windows_targets::link!("kernel32.dll" "system" fn UnlockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestounlocklow : u32, nnumberofbytestounlockhigh : u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT); windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT); @@ -2730,6 +2732,9 @@ pub struct LINGER { pub l_onoff: u16, pub l_linger: u16, } +pub const LOCKFILE_EXCLUSIVE_LOCK: LOCK_FILE_FLAGS = 2u32; +pub const LOCKFILE_FAIL_IMMEDIATELY: LOCK_FILE_FLAGS = 1u32; +pub type LOCK_FILE_FLAGS = u32; pub type LPOVERLAPPED_COMPLETION_ROUTINE = Option< unsafe extern "system" fn( dwerrorcode: u32, diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index 5a9bfccc1fabb..07e4f93a37956 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -346,6 +346,120 @@ impl File { self.fsync() } + fn acquire_lock(&self, flags: c::LOCK_FILE_FLAGS) -> io::Result<()> { + unsafe { + let mut overlapped: c::OVERLAPPED = mem::zeroed(); + let event = c::CreateEventW(ptr::null_mut(), c::FALSE, c::FALSE, ptr::null()); + if event.is_null() { + return Err(io::Error::last_os_error()); + } + overlapped.hEvent = event; + let lock_result = cvt(c::LockFileEx( + self.handle.as_raw_handle(), + flags, + 0, + u32::MAX, + u32::MAX, + &mut overlapped, + )); + + let final_result = match lock_result { + Ok(_) => Ok(()), + Err(err) => { + if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) { + // Wait for the lock to be acquired, and get the lock operation status. + // This can happen asynchronously, if the file handle was opened for async IO + let mut bytes_transferred = 0; + cvt(c::GetOverlappedResult( + self.handle.as_raw_handle(), + &mut overlapped, + &mut bytes_transferred, + c::TRUE, + )) + .map(|_| ()) + } else { + Err(err) + } + } + }; + c::CloseHandle(overlapped.hEvent); + final_result + } + } + + pub fn lock(&self) -> io::Result<()> { + self.acquire_lock(c::LOCKFILE_EXCLUSIVE_LOCK) + } + + pub fn lock_shared(&self) -> io::Result<()> { + self.acquire_lock(0) + } + + pub fn try_lock(&self) -> io::Result { + let result = cvt(unsafe { + let mut overlapped = mem::zeroed(); + c::LockFileEx( + self.handle.as_raw_handle(), + c::LOCKFILE_EXCLUSIVE_LOCK | c::LOCKFILE_FAIL_IMMEDIATELY, + 0, + u32::MAX, + u32::MAX, + &mut overlapped, + ) + }); + + match result { + Ok(_) => Ok(true), + 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) => + { + Ok(false) + } + Err(err) => Err(err), + } + } + + pub fn try_lock_shared(&self) -> io::Result { + let result = cvt(unsafe { + let mut overlapped = mem::zeroed(); + c::LockFileEx( + self.handle.as_raw_handle(), + c::LOCKFILE_FAIL_IMMEDIATELY, + 0, + u32::MAX, + u32::MAX, + &mut overlapped, + ) + }); + + match result { + Ok(_) => Ok(true), + 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) => + { + Ok(false) + } + Err(err) => Err(err), + } + } + + pub fn unlock(&self) -> io::Result<()> { + // Unlock the handle twice because LockFileEx() allows a file handle to acquire + // both an exclusive and shared lock, in which case the documentation states that: + // "...two unlock operations are necessary to unlock the region; the first unlock operation + // unlocks the exclusive lock, the second unlock operation unlocks the shared lock" + cvt(unsafe { c::UnlockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) })?; + let result = + cvt(unsafe { c::UnlockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) }); + match result { + Ok(_) => Ok(()), + Err(err) if err.raw_os_error() == Some(c::ERROR_NOT_LOCKED as i32) => Ok(()), + Err(err) => Err(err), + } + } + pub fn truncate(&self, size: u64) -> io::Result<()> { let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 }; api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result() diff --git a/std/src/sys/pal/windows/io.rs b/std/src/sys/pal/windows/io.rs index 1e7d02908f63d..f2865d2ffc168 100644 --- a/std/src/sys/pal/windows/io.rs +++ b/std/src/sys/pal/windows/io.rs @@ -36,7 +36,7 @@ impl<'a> IoSlice<'a> { } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub const fn as_slice(&self) -> &'a [u8] { unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } } } @@ -74,6 +74,11 @@ impl<'a> IoSliceMut<'a> { unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } } + #[inline] + pub const fn into_slice(self) -> &'a mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } + } + #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } diff --git a/std/src/sys/random/arc4random.rs b/std/src/sys/random/arc4random.rs index ffabaafbee803..32467e9ebaa64 100644 --- a/std/src/sys/random/arc4random.rs +++ b/std/src/sys/random/arc4random.rs @@ -12,7 +12,6 @@ #[cfg(not(any( target_os = "haiku", target_os = "illumos", - target_os = "rtems", target_os = "solaris", target_os = "vita", )))] @@ -22,7 +21,6 @@ use libc::arc4random_buf; #[cfg(any( target_os = "haiku", // See https://git.haiku-os.org/haiku/tree/headers/compatibility/bsd/stdlib.h target_os = "illumos", // See https://www.illumos.org/man/3C/arc4random - target_os = "rtems", // See https://docs.rtems.org/branches/master/bsp-howto/getentropy.html target_os = "solaris", // See https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html target_os = "vita", // See https://github.com/vitasdk/newlib/blob/b89e5bc183b516945f9ee07eef483ecb916e45ff/newlib/libc/include/stdlib.h#L74 ))] diff --git a/std/src/sys/sync/once/queue.rs b/std/src/sys/sync/once/queue.rs index 177d0d7744a6d..87837915b396e 100644 --- a/std/src/sys/sync/once/queue.rs +++ b/std/src/sys/sync/once/queue.rs @@ -93,7 +93,7 @@ const QUEUE_MASK: usize = !STATE_MASK; // use interior mutability. #[repr(align(4))] // Ensure the two lower bits are free to use as state bits. struct Waiter { - thread: Cell>, + thread: Thread, signaled: AtomicBool, next: Cell<*const Waiter>, } @@ -238,7 +238,7 @@ fn wait( return_on_poisoned: bool, ) -> StateAndQueue { let node = &Waiter { - thread: Cell::new(Some(thread::current())), + thread: thread::current_or_unnamed(), signaled: AtomicBool::new(false), next: Cell::new(ptr::null()), }; @@ -277,7 +277,8 @@ fn wait( // can park ourselves, the result could be this thread never gets // unparked. Luckily `park` comes with the guarantee that if it got // an `unpark` just before on an unparked thread it does not park. - thread::park(); + // SAFETY: we retrieved this handle on the current thread above. + unsafe { node.thread.park() } } return state_and_queue.load(Acquire); @@ -309,7 +310,7 @@ impl Drop for WaiterQueue<'_> { let mut queue = to_queue(current); while !queue.is_null() { let next = (*queue).next.get(); - let thread = (*queue).thread.take().unwrap(); + let thread = (*queue).thread.clone(); (*queue).signaled.store(true, Release); thread.unpark(); queue = next; diff --git a/std/src/sys/sync/rwlock/futex.rs b/std/src/sys/sync/rwlock/futex.rs index 447048edf7622..961819cae8d6e 100644 --- a/std/src/sys/sync/rwlock/futex.rs +++ b/std/src/sys/sync/rwlock/futex.rs @@ -18,6 +18,7 @@ pub struct RwLock { const READ_LOCKED: Primitive = 1; const MASK: Primitive = (1 << 30) - 1; const WRITE_LOCKED: Primitive = MASK; +const DOWNGRADE: Primitive = READ_LOCKED.wrapping_sub(WRITE_LOCKED); // READ_LOCKED - WRITE_LOCKED const MAX_READERS: Primitive = MASK - 1; const READERS_WAITING: Primitive = 1 << 30; const WRITERS_WAITING: Primitive = 1 << 31; @@ -53,6 +54,24 @@ fn is_read_lockable(state: Primitive) -> bool { state & MASK < MAX_READERS && !has_readers_waiting(state) && !has_writers_waiting(state) } +#[inline] +fn is_read_lockable_after_wakeup(state: Primitive) -> bool { + // We make a special case for checking if we can read-lock _after_ a reader thread that went to + // sleep has been woken up by a call to `downgrade`. + // + // `downgrade` will wake up all readers and place the lock in read mode. Thus, there should be + // no readers waiting and the lock should be read-locked (not write-locked or unlocked). + // + // Note that we do not check if any writers are waiting. This is because a call to `downgrade` + // implies that the caller wants other readers to read the value protected by the lock. If we + // did not allow readers to acquire the lock before writers after a `downgrade`, then only the + // original writer would be able to read the value, thus defeating the purpose of `downgrade`. + state & MASK < MAX_READERS + && !has_readers_waiting(state) + && !is_write_locked(state) + && !is_unlocked(state) +} + #[inline] fn has_reached_max_readers(state: Primitive) -> bool { state & MASK == MAX_READERS @@ -84,6 +103,9 @@ impl RwLock { } } + /// # Safety + /// + /// The `RwLock` must be read-locked (N readers) in order to call this. #[inline] pub unsafe fn read_unlock(&self) { let state = self.state.fetch_sub(READ_LOCKED, Release) - READ_LOCKED; @@ -100,11 +122,13 @@ impl RwLock { #[cold] fn read_contended(&self) { + let mut has_slept = false; let mut state = self.spin_read(); loop { - // If we can lock it, lock it. - if is_read_lockable(state) { + // If we have just been woken up, first check for a `downgrade` call. + // Otherwise, if we can read-lock it, lock it. + if (has_slept && is_read_lockable_after_wakeup(state)) || is_read_lockable(state) { match self.state.compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) { Ok(_) => return, // Locked! @@ -116,9 +140,7 @@ impl RwLock { } // Check for overflow. - if has_reached_max_readers(state) { - panic!("too many active read locks on RwLock"); - } + assert!(!has_reached_max_readers(state), "too many active read locks on RwLock"); // Make sure the readers waiting bit is set before we go to sleep. if !has_readers_waiting(state) { @@ -132,6 +154,7 @@ impl RwLock { // Wait for the state to change. futex_wait(&self.state, state | READERS_WAITING, None); + has_slept = true; // Spin again after waking up. state = self.spin_read(); @@ -152,6 +175,9 @@ impl RwLock { } } + /// # Safety + /// + /// The `RwLock` must be write-locked (single writer) in order to call this. #[inline] pub unsafe fn write_unlock(&self) { let state = self.state.fetch_sub(WRITE_LOCKED, Release) - WRITE_LOCKED; @@ -163,6 +189,22 @@ impl RwLock { } } + /// # Safety + /// + /// The `RwLock` must be write-locked (single writer) in order to call this. + #[inline] + pub unsafe fn downgrade(&self) { + // Removes all write bits and adds a single read bit. + let state = self.state.fetch_add(DOWNGRADE, Release); + debug_assert!(is_write_locked(state), "RwLock must be write locked to call `downgrade`"); + + if has_readers_waiting(state) { + // Since we had the exclusive lock, nobody else can unset this bit. + self.state.fetch_sub(READERS_WAITING, Relaxed); + futex_wake_all(&self.state); + } + } + #[cold] fn write_contended(&self) { let mut state = self.spin_write(); diff --git a/std/src/sys/sync/rwlock/no_threads.rs b/std/src/sys/sync/rwlock/no_threads.rs index 6965e2e2cabe5..c11e59f719e93 100644 --- a/std/src/sys/sync/rwlock/no_threads.rs +++ b/std/src/sys/sync/rwlock/no_threads.rs @@ -62,4 +62,9 @@ impl RwLock { pub unsafe fn write_unlock(&self) { assert_eq!(self.mode.replace(0), -1); } + + #[inline] + pub unsafe fn downgrade(&self) { + assert_eq!(self.mode.replace(1), -1); + } } diff --git a/std/src/sys/sync/rwlock/queue.rs b/std/src/sys/sync/rwlock/queue.rs index 889961915f4e6..bd15f8ee952c9 100644 --- a/std/src/sys/sync/rwlock/queue.rs +++ b/std/src/sys/sync/rwlock/queue.rs @@ -1,37 +1,38 @@ //! Efficient read-write locking without `pthread_rwlock_t`. //! -//! The readers-writer lock provided by the `pthread` library has a number of -//! problems which make it a suboptimal choice for `std`: +//! The readers-writer lock provided by the `pthread` library has a number of problems which make it +//! a suboptimal choice for `std`: //! -//! * It is non-movable, so it needs to be allocated (lazily, to make the -//! constructor `const`). -//! * `pthread` is an external library, meaning the fast path of acquiring an -//! uncontended lock cannot be inlined. -//! * Some platforms (at least glibc before version 2.25) have buggy implementations -//! that can easily lead to undefined behavior in safe Rust code when not properly -//! guarded against. +//! * It is non-movable, so it needs to be allocated (lazily, to make the constructor `const`). +//! * `pthread` is an external library, meaning the fast path of acquiring an uncontended lock +//! cannot be inlined. +//! * Some platforms (at least glibc before version 2.25) have buggy implementations that can easily +//! lead to undefined behaviour in safe Rust code when not properly guarded against. //! * On some platforms (e.g. macOS), the lock is very slow. //! -//! Therefore, we implement our own `RwLock`! Naively, one might reach for a -//! spinlock, but those [can be quite problematic] when the lock is contended. -//! Instead, this readers-writer lock copies its implementation strategy from -//! the Windows [SRWLOCK] and the [usync] library. Spinning is still used for the -//! fast path, but it is bounded: after spinning fails, threads will locklessly -//! add an information structure containing a [`Thread`] handle into a queue of -//! waiters associated with the lock. The lock owner, upon releasing the lock, -//! will scan through the queue and wake up threads as appropriate, which will -//! then again try to acquire the lock. The resulting [`RwLock`] is: +//! Therefore, we implement our own [`RwLock`]! Naively, one might reach for a spinlock, but those +//! can be quite [problematic] when the lock is contended. //! -//! * adaptive, since it spins before doing any heavywheight parking operations -//! * allocation-free, modulo the per-thread [`Thread`] handle, which is -//! allocated regardless when using threads created by `std` +//! Instead, this [`RwLock`] copies its implementation strategy from the Windows [SRWLOCK] and the +//! [usync] library implementations. +//! +//! Spinning is still used for the fast path, but it is bounded: after spinning fails, threads will +//! locklessly add an information structure ([`Node`]) containing a [`Thread`] handle into a queue +//! of waiters associated with the lock. The lock owner, upon releasing the lock, will scan through +//! the queue and wake up threads as appropriate, and the newly-awoken threads will then try to +//! acquire the lock themselves. +//! +//! The resulting [`RwLock`] is: +//! +//! * adaptive, since it spins before doing any heavyweight parking operations +//! * allocation-free, modulo the per-thread [`Thread`] handle, which is allocated anyways when +//! using threads created by `std` //! * writer-preferring, even if some readers may still slip through -//! * unfair, which reduces context-switching and thus drastically improves -//! performance +//! * unfair, which reduces context-switching and thus drastically improves performance //! //! and also quite fast in most cases. //! -//! [can be quite problematic]: https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html +//! [problematic]: https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html //! [SRWLOCK]: https://learn.microsoft.com/en-us/windows/win32/sync/slim-reader-writer--srw--locks //! [usync]: https://crates.io/crates/usync //! @@ -39,33 +40,37 @@ //! //! ## State //! -//! A single [`AtomicPtr`] is used as state variable. The lowest three bits are used -//! to indicate the meaning of the remaining bits: +//! A single [`AtomicPtr`] is used as state variable. The lowest four bits are used to indicate the +//! meaning of the remaining bits: +//! +//! | [`LOCKED`] | [`QUEUED`] | [`QUEUE_LOCKED`] | [`DOWNGRADED`] | Remaining | | +//! |------------|:-----------|:-----------------|:---------------|:-------------|:----------------------------------------------------------------------------------------------------------------------------| +//! | 0 | 0 | 0 | 0 | 0 | The lock is unlocked, no threads are waiting | +//! | 1 | 0 | 0 | 0 | 0 | The lock is write-locked, no threads waiting | +//! | 1 | 0 | 0 | 0 | n > 0 | The lock is read-locked with n readers | +//! | 0 | 1 | * | 0 | `*mut Node` | The lock is unlocked, but some threads are waiting. Only writers may lock the lock | +//! | 1 | 1 | * | * | `*mut Node` | The lock is locked, but some threads are waiting. If the lock is read-locked, the last queue node contains the reader count | +//! +//! ## Waiter Queue //! -//! | [`LOCKED`] | [`QUEUED`] | [`QUEUE_LOCKED`] | Remaining | | -//! |:-----------|:-----------|:-----------------|:-------------|:----------------------------------------------------------------------------------------------------------------------------| -//! | 0 | 0 | 0 | 0 | The lock is unlocked, no threads are waiting | -//! | 1 | 0 | 0 | 0 | The lock is write-locked, no threads waiting | -//! | 1 | 0 | 0 | n > 0 | The lock is read-locked with n readers | -//! | 0 | 1 | * | `*mut Node` | The lock is unlocked, but some threads are waiting. Only writers may lock the lock | -//! | 1 | 1 | * | `*mut Node` | The lock is locked, but some threads are waiting. If the lock is read-locked, the last queue node contains the reader count | +//! When threads are waiting on the lock (the `QUEUE` bit is set), the lock state points to a queue +//! of waiters, which is implemented as a linked list of nodes stored on the stack to avoid memory +//! allocation. //! -//! ## Waiter queue +//! To enable lock-free enqueuing of new nodes to the queue, the linked list is singly-linked upon +//! creation. //! -//! When threads are waiting on the lock (`QUEUE` is set), the lock state -//! points to a queue of waiters, which is implemented as a linked list of -//! nodes stored on the stack to avoid memory allocation. To enable lockless -//! enqueuing of new nodes to the queue, the linked list is single-linked upon -//! creation. Since when the lock is read-locked, the lock count is stored in -//! the last link of the queue, threads have to traverse the queue to find the -//! last element upon releasing the lock. To avoid having to traverse the whole -//! list again and again, a pointer to the found tail is cached in the (current) -//! first element of the queue. +//! When the lock is read-locked, the lock count (number of readers) is stored in the last link of +//! the queue. Threads have to traverse the queue to find the last element upon releasing the lock. +//! To avoid having to traverse the entire list every time we want to access the reader count, a +//! pointer to the found tail is cached in the (current) first element of the queue. //! -//! Also, while the lock is unfair for performance reasons, it is still best to -//! wake the tail node first, which requires backlinks to previous nodes to be -//! created. This is done at the same time as finding the tail, and thus a set -//! tail field indicates the remaining portion of the queue is initialized. +//! Also, while the lock is unfair for performance reasons, it is still best to wake the tail node +//! first (FIFO ordering). Since we always pop nodes off the tail of the queue, we must store +//! backlinks to previous nodes so that we can update the `tail` field of the (current) first +//! element of the queue. Adding backlinks is done at the same time as finding the tail (via the +//! function [`find_tail_and_add_backlinks`]), and thus encountering a set tail field on a node +//! indicates that all following nodes in the queue are initialized. //! //! TLDR: Here's a diagram of what the queue looks like: //! @@ -89,21 +94,21 @@ //! 3. All nodes preceding this node must have a correct, non-null `next` field. //! 4. All nodes following this node must have a correct, non-null `prev` field. //! -//! Access to the queue is controlled by the `QUEUE_LOCKED` bit, which threads -//! try to set both after enqueuing themselves to eagerly add backlinks to the -//! queue, which drastically improves performance, and after unlocking the lock -//! to wake the next waiter(s). This is done atomically at the same time as the -//! enqueuing/unlocking operation. The thread releasing the `QUEUE_LOCK` bit -//! will check the state of the lock and wake up waiters as appropriate. This -//! guarantees forward-progress even if the unlocking thread could not acquire -//! the queue lock. +//! Access to the queue is controlled by the `QUEUE_LOCKED` bit. Threads will try to set this bit +//! in two cases: one is when a thread enqueues itself and eagerly adds backlinks to the queue +//! (which drastically improves performance), and the other is after a thread unlocks the lock to +//! wake up the next waiter(s). //! -//! ## Memory orderings +//! `QUEUE_LOCKED` is set atomically at the same time as the enqueuing/unlocking operations. The +//! thread releasing the `QUEUE_LOCKED` bit will check the state of the lock (in particular, whether +//! a downgrade was requested using the [`DOWNGRADED`] bit) and wake up waiters as appropriate. This +//! guarantees forward progress even if the unlocking thread could not acquire the queue lock. //! -//! To properly synchronize changes to the data protected by the lock, the lock -//! is acquired and released with [`Acquire`] and [`Release`] ordering, respectively. -//! To propagate the initialization of nodes, changes to the queue lock are also -//! performed using these orderings. +//! ## Memory Orderings +//! +//! To properly synchronize changes to the data protected by the lock, the lock is acquired and +//! released with [`Acquire`] and [`Release`] ordering, respectively. To propagate the +//! initialization of nodes, changes to the queue lock are also performed using these orderings. #![forbid(unsafe_op_in_unsafe_fn)] @@ -113,28 +118,32 @@ use crate::mem; use crate::ptr::{self, NonNull, null_mut, without_provenance_mut}; use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicBool, AtomicPtr}; -use crate::thread::{self, Thread, ThreadId}; - -// Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the -// locking operation will be retried. -// `spin_loop` will be called `2.pow(SPIN_COUNT) - 1` times. -const SPIN_COUNT: usize = 7; +use crate::thread::{self, Thread}; -type State = *mut (); +/// The atomic lock state. type AtomicState = AtomicPtr<()>; +/// The inner lock state. +type State = *mut (); const UNLOCKED: State = without_provenance_mut(0); -const LOCKED: usize = 1; -const QUEUED: usize = 2; -const QUEUE_LOCKED: usize = 4; -const SINGLE: usize = 8; -const MASK: usize = !(QUEUE_LOCKED | QUEUED | LOCKED); +const LOCKED: usize = 1 << 0; +const QUEUED: usize = 1 << 1; +const QUEUE_LOCKED: usize = 1 << 2; +const DOWNGRADED: usize = 1 << 3; +const SINGLE: usize = 1 << 4; +const STATE: usize = DOWNGRADED | QUEUE_LOCKED | QUEUED | LOCKED; +const NODE_MASK: usize = !STATE; + +/// Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the locking operation +/// will be retried. +/// +/// In other words, `spin_loop` will be called `2.pow(SPIN_COUNT) - 1` times. +const SPIN_COUNT: usize = 7; /// Marks the state as write-locked, if possible. #[inline] fn write_lock(state: State) -> Option { - let state = state.wrapping_byte_add(LOCKED); - if state.addr() & LOCKED == LOCKED { Some(state) } else { None } + if state.addr() & LOCKED == 0 { Some(state.map_addr(|addr| addr | LOCKED)) } else { None } } /// Marks the state as read-locked, if possible. @@ -147,13 +156,32 @@ fn read_lock(state: State) -> Option { } } -/// Masks the state, assuming it points to a queue node. +/// Converts a `State` into a `Node` by masking out the bottom bits of the state, assuming that the +/// state points to a queue node. /// /// # Safety +/// /// The state must contain a valid pointer to a queue node. #[inline] unsafe fn to_node(state: State) -> NonNull { - unsafe { NonNull::new_unchecked(state.mask(MASK)).cast() } + unsafe { NonNull::new_unchecked(state.mask(NODE_MASK)).cast() } +} + +/// The representation of a thread waiting on the lock queue. +/// +/// We initialize these `Node`s on thread execution stacks to avoid allocation. +/// +/// Note that we need an alignment of 16 to ensure that the last 4 bits of any +/// pointers to `Node`s are always zeroed (for the bit flags described in the +/// module-level documentation). +#[repr(align(16))] +struct Node { + next: AtomicLink, + prev: AtomicLink, + tail: AtomicLink, + write: bool, + thread: OnceCell, + completed: AtomicBool, } /// An atomic node pointer with relaxed operations. @@ -173,16 +201,6 @@ impl AtomicLink { } } -#[repr(align(8))] -struct Node { - next: AtomicLink, - prev: AtomicLink, - tail: AtomicLink, - write: bool, - thread: OnceCell, - completed: AtomicBool, -} - impl Node { /// Creates a new queue node. fn new(write: bool) -> Node { @@ -198,17 +216,15 @@ impl Node { /// Prepare this node for waiting. fn prepare(&mut self) { - // Fall back to creating an unnamed `Thread` handle to allow locking in - // TLS destructors. - self.thread.get_or_init(|| { - thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new())) - }); + // Fall back to creating an unnamed `Thread` handle to allow locking in TLS destructors. + self.thread.get_or_init(thread::current_or_unnamed); self.completed = AtomicBool::new(false); } - /// Wait until this node is marked as completed. + /// Wait until this node is marked as [`complete`](Node::complete)d by another thread. /// /// # Safety + /// /// May only be called from the thread that created the node. unsafe fn wait(&self) { while !self.completed.load(Acquire) { @@ -218,51 +234,48 @@ impl Node { } } - /// Atomically mark this node as completed. The node may not outlive this call. - unsafe fn complete(this: NonNull) { - // Since the node may be destroyed immediately after the completed flag - // is set, clone the thread handle before that. - let thread = unsafe { this.as_ref().thread.get().unwrap().clone() }; + /// Atomically mark this node as completed. + /// + /// # Safety + /// + /// `node` must point to a valid `Node`, and the node may not outlive this call. + unsafe fn complete(node: NonNull) { + // Since the node may be destroyed immediately after the completed flag is set, clone the + // thread handle before that. + let thread = unsafe { node.as_ref().thread.get().unwrap().clone() }; unsafe { - this.as_ref().completed.store(true, Release); + node.as_ref().completed.store(true, Release); } thread.unpark(); } } -struct PanicGuard; - -impl Drop for PanicGuard { - fn drop(&mut self) { - rtabort!("tried to drop node in intrusive list."); - } -} - -/// Add backlinks to the queue, returning the tail. +/// Traverse the queue and find the tail, adding backlinks to the queue while traversing. /// -/// May be called from multiple threads at the same time, while the queue is not +/// This may be called from multiple threads at the same time as long as the queue is not being /// modified (this happens when unlocking multiple readers). /// /// # Safety +/// /// * `head` must point to a node in a valid queue. -/// * `head` must be or be in front of the head of the queue at the time of the -/// last removal. -/// * The part of the queue starting with `head` must not be modified during this -/// call. -unsafe fn add_backlinks_and_find_tail(head: NonNull) -> NonNull { +/// * `head` must be in front of the previous head node that was used to perform the last removal. +/// * The part of the queue starting with `head` must not be modified during this call. +unsafe fn find_tail_and_add_backlinks(head: NonNull) -> NonNull { let mut current = head; + + // Traverse the queue until we find a node that has a set `tail`. let tail = loop { let c = unsafe { current.as_ref() }; - match c.tail.get() { - Some(tail) => break tail, - // SAFETY: - // All `next` fields before the first node with a `set` tail are - // non-null and valid (invariant 3). - None => unsafe { - let next = c.next.get().unwrap_unchecked(); - next.as_ref().prev.set(Some(current)); - current = next; - }, + if let Some(tail) = c.tail.get() { + break tail; + } + + // SAFETY: All `next` fields before the first node with a set `tail` are non-null and valid + // (by Invariant 3). + unsafe { + let next = c.next.get().unwrap_unchecked(); + next.as_ref().prev.set(Some(current)); + current = next; } }; @@ -272,6 +285,38 @@ unsafe fn add_backlinks_and_find_tail(head: NonNull) -> NonNull { } } +/// [`complete`](Node::complete)s all threads in the queue ending with `tail`. +/// +/// # Safety +/// +/// * `tail` must be a valid tail of a fully linked queue. +/// * The current thread must have exclusive access to that queue. +unsafe fn complete_all(tail: NonNull) { + let mut current = tail; + + // Traverse backwards through the queue (FIFO) and `complete` all of the nodes. + loop { + let prev = unsafe { current.as_ref().prev.get() }; + unsafe { + Node::complete(current); + } + match prev { + Some(prev) => current = prev, + None => return, + } + } +} + +/// A type to guard against the unwinds of stacks that nodes are located on due to panics. +struct PanicGuard; + +impl Drop for PanicGuard { + fn drop(&mut self) { + rtabort!("tried to drop node in intrusive list."); + } +} + +/// The public inner `RwLock` type. pub struct RwLock { state: AtomicState, } @@ -296,11 +341,10 @@ impl RwLock { #[inline] pub fn try_write(&self) -> bool { - // Atomically set the `LOCKED` bit. This is lowered to a single atomic - // instruction on most modern processors (e.g. "lock bts" on x86 and - // "ldseta" on modern AArch64), and therefore is more efficient than - // `fetch_update(lock(true))`, which can spuriously fail if a new node - // is appended to the queue. + // Atomically set the `LOCKED` bit. This is lowered to a single atomic instruction on most + // modern processors (e.g. "lock bts" on x86 and "ldseta" on modern AArch64), and therefore + // is more efficient than `fetch_update(lock(true))`, which can spuriously fail if a new + // node is appended to the queue. self.state.fetch_or(LOCKED, Acquire).addr() & LOCKED == 0 } @@ -313,88 +357,97 @@ impl RwLock { #[cold] fn lock_contended(&self, write: bool) { - let update = if write { write_lock } else { read_lock }; let mut node = Node::new(write); let mut state = self.state.load(Relaxed); let mut count = 0; + let update_fn = if write { write_lock } else { read_lock }; + loop { - if let Some(next) = update(state) { + // Optimistically update the state. + if let Some(next) = update_fn(state) { // The lock is available, try locking it. match self.state.compare_exchange_weak(state, next, Acquire, Relaxed) { Ok(_) => return, Err(new) => state = new, } + continue; } else if state.addr() & QUEUED == 0 && count < SPIN_COUNT { - // If the lock is not available and no threads are queued, spin - // for a while, using exponential backoff to decrease cache - // contention. + // If the lock is not available and no threads are queued, optimistically spin for a + // while, using exponential backoff to decrease cache contention. for _ in 0..(1 << count) { spin_loop(); } state = self.state.load(Relaxed); count += 1; + continue; + } + // The optimistic paths did not succeed, so fall back to parking the thread. + + // First, prepare the node. + node.prepare(); + + // If there are threads queued, this will set the `next` field to be a pointer to the + // first node in the queue. + // If the state is read-locked, this will set `next` to the lock count. + // If it is write-locked, it will set `next` to zero. + node.next.0 = AtomicPtr::new(state.mask(NODE_MASK).cast()); + node.prev = AtomicLink::new(None); + + // Set the `QUEUED` bit and preserve the `LOCKED` and `DOWNGRADED` bit. + let mut next = ptr::from_ref(&node) + .map_addr(|addr| addr | QUEUED | (state.addr() & (DOWNGRADED | LOCKED))) + as State; + + let mut is_queue_locked = false; + if state.addr() & QUEUED == 0 { + // If this is the first node in the queue, set the `tail` field to the node itself + // to ensure there is a valid `tail` field in the queue (Invariants 1 & 2). + // This needs to use `set` to avoid invalidating the new pointer. + node.tail.set(Some(NonNull::from(&node))); } else { - // Fall back to parking. First, prepare the node. - node.prepare(); - - // If there are threads queued, set the `next` field to a - // pointer to the next node in the queue. Otherwise set it to - // the lock count if the state is read-locked or to zero if it - // is write-locked. - node.next.0 = AtomicPtr::new(state.mask(MASK).cast()); - node.prev = AtomicLink::new(None); - let mut next = ptr::from_ref(&node) - .map_addr(|addr| addr | QUEUED | (state.addr() & LOCKED)) - as State; - - if state.addr() & QUEUED == 0 { - // If this is the first node in the queue, set the tail field to - // the node itself to ensure there is a current `tail` field in - // the queue (invariants 1 and 2). This needs to use `set` to - // avoid invalidating the new pointer. - node.tail.set(Some(NonNull::from(&node))); - } else { - // Otherwise, the tail of the queue is not known. - node.tail.set(None); - // Try locking the queue to eagerly add backlinks. - next = next.map_addr(|addr| addr | QUEUE_LOCKED); - } + // Otherwise, the tail of the queue is not known. + node.tail.set(None); - // Register the node, using release ordering to propagate our - // changes to the waking thread. - if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) { - // The state has changed, just try again. - state = new; - continue; - } + // Try locking the queue to eagerly add backlinks. + next = next.map_addr(|addr| addr | QUEUE_LOCKED); - // The node is registered, so the structure must not be - // mutably accessed or destroyed while other threads may - // be accessing it. Guard against unwinds using a panic - // guard that aborts when dropped. - let guard = PanicGuard; + // Track if we changed the `QUEUE_LOCKED` bit from off to on. + is_queue_locked = state.addr() & QUEUE_LOCKED == 0; + } - // If the current thread locked the queue, unlock it again, - // linking it in the process. - if state.addr() & (QUEUE_LOCKED | QUEUED) == QUEUED { - unsafe { - self.unlock_queue(next); - } - } + // Register the node, using release ordering to propagate our changes to the waking + // thread. + if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) { + // The state has changed, just try again. + state = new; + continue; + } + // The node has been registered, so the structure must not be mutably accessed or + // destroyed while other threads may be accessing it. - // Wait until the node is removed from the queue. - // SAFETY: the node was created by the current thread. + // Guard against unwinds using a `PanicGuard` that aborts when dropped. + let guard = PanicGuard; + + // If the current thread locked the queue, unlock it to eagerly adding backlinks. + if is_queue_locked { + // SAFETY: This thread set the `QUEUE_LOCKED` bit above. unsafe { - node.wait(); + self.unlock_queue(next); } + } - // The node was removed from the queue, disarm the guard. - mem::forget(guard); - - // Reload the state and try again. - state = self.state.load(Relaxed); - count = 0; + // Wait until the node is removed from the queue. + // SAFETY: the node was created by the current thread. + unsafe { + node.wait(); } + + // The node was removed from the queue, disarm the guard. + mem::forget(guard); + + // Reload the state and try again. + state = self.state.load(Relaxed); + count = 0; } } @@ -402,39 +455,51 @@ impl RwLock { pub unsafe fn read_unlock(&self) { match self.state.fetch_update(Release, Acquire, |state| { if state.addr() & QUEUED == 0 { + // If there are no threads queued, simply decrement the reader count. let count = state.addr() - (SINGLE | LOCKED); Some(if count > 0 { without_provenance_mut(count | LOCKED) } else { UNLOCKED }) + } else if state.addr() & DOWNGRADED != 0 { + // This thread used to have exclusive access, but requested a downgrade. This has + // not been completed yet, so we still have exclusive access. + // Retract the downgrade request and unlock, but leave waking up new threads to the + // thread that already holds the queue lock. + Some(state.mask(!(DOWNGRADED | LOCKED))) } else { None } }) { Ok(_) => {} - // There are waiters queued and the lock count was moved to the - // tail of the queue. + // There are waiters queued and the lock count was moved to the tail of the queue. Err(state) => unsafe { self.read_unlock_contended(state) }, } } + /// # Safety + /// + /// * There must be threads queued on the lock. + /// * `state` must be a pointer to a node in a valid queue. + /// * There cannot be a `downgrade` in progress. #[cold] unsafe fn read_unlock_contended(&self, state: State) { - // The state was observed with acquire ordering above, so the current - // thread will observe all node initializations. - // SAFETY: - // Because new read-locks cannot be acquired while threads are queued, - // all queue-lock owners will observe the set `LOCKED` bit. Because they - // do not modify the queue while there is a lock owner, the queue will - // not be removed from here. - let tail = unsafe { add_backlinks_and_find_tail(to_node(state)).as_ref() }; + // The state was observed with acquire ordering above, so the current thread will have + // observed all node initializations. + // We also know that no threads can be modifying the queue starting at `state`: because new + // read-locks cannot be acquired while there are any threads queued on the lock, all + // queue-lock owners will observe a set `LOCKED` bit in `self.state` and will not modify + // the queue. The other case that a thread could modify the queue is if a downgrade is in + // progress (removal of the entire queue), but since that is part of this function's safety + // contract, we can guarantee that no other threads can modify the queue. + let tail = unsafe { find_tail_and_add_backlinks(to_node(state)).as_ref() }; + // The lock count is stored in the `next` field of `tail`. - // Decrement it, making sure to observe all changes made to the queue - // by the other lock owners by using acquire-release ordering. + // Decrement it, making sure to observe all changes made to the queue by the other lock + // owners by using acquire-release ordering. let was_last = tail.next.0.fetch_byte_sub(SINGLE, AcqRel).addr() - SINGLE == 0; if was_last { - // SAFETY: - // Other threads cannot read-lock while threads are queued. Also, - // the `LOCKED` bit is still set, so there are no writers. Therefore, - // the current thread exclusively owns the lock. + // SAFETY: Other threads cannot read-lock while threads are queued. Also, the `LOCKED` + // bit is still set, so there are no writers. Thus the current thread exclusively owns + // this lock, even though it is a reader. unsafe { self.unlock_contended(state) } } } @@ -444,49 +509,143 @@ impl RwLock { if let Err(state) = self.state.compare_exchange(without_provenance_mut(LOCKED), UNLOCKED, Release, Relaxed) { - // SAFETY: - // Since other threads cannot acquire the lock, the state can only - // have changed because there are threads queued on the lock. + // SAFETY: Since other threads cannot acquire the lock, the state can only have changed + // because there are threads queued on the lock. unsafe { self.unlock_contended(state) } } } /// # Safety + /// /// * The lock must be exclusively owned by this thread. /// * There must be threads queued on the lock. + /// * `state` must be a pointer to a node in a valid queue. + /// * There cannot be a `downgrade` in progress. #[cold] - unsafe fn unlock_contended(&self, mut state: State) { + unsafe fn unlock_contended(&self, state: State) { + debug_assert_eq!(state.addr() & (DOWNGRADED | QUEUED | LOCKED), QUEUED | LOCKED); + + let mut current = state; + + // We want to atomically release the lock and try to acquire the queue lock. loop { + // First check if the queue lock is already held. + if current.addr() & QUEUE_LOCKED != 0 { + // Another thread holds the queue lock, so let them wake up waiters for us. + let next = current.mask(!LOCKED); + match self.state.compare_exchange_weak(current, next, Release, Relaxed) { + Ok(_) => return, + Err(new) => { + current = new; + continue; + } + } + } + // Atomically release the lock and try to acquire the queue lock. - let next = state.map_addr(|a| (a & !LOCKED) | QUEUE_LOCKED); - match self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) { - // The queue lock was acquired. Release it, waking up the next - // waiter in the process. - Ok(_) if state.addr() & QUEUE_LOCKED == 0 => unsafe { - return self.unlock_queue(next); - }, - // Another thread already holds the queue lock, leave waking up - // waiters to it. - Ok(_) => return, - Err(new) => state = new, + let next = current.map_addr(|addr| (addr & !LOCKED) | QUEUE_LOCKED); + match self.state.compare_exchange_weak(current, next, AcqRel, Relaxed) { + // Now that we have the queue lock, we can wake up the next waiter. + Ok(_) => { + // SAFETY: This thread just acquired the queue lock, and this function's safety + // contract requires that there are threads already queued on the lock. + unsafe { self.unlock_queue(next) }; + return; + } + Err(new) => current = new, } } } - /// Unlocks the queue. If the lock is unlocked, wakes up the next eligible - /// thread(s). + /// # Safety + /// + /// * The lock must be write-locked by this thread. + #[inline] + pub unsafe fn downgrade(&self) { + // Optimistically change the state from write-locked with a single writer and no waiters to + // read-locked with a single reader and no waiters. + if let Err(state) = self.state.compare_exchange( + without_provenance_mut(LOCKED), + without_provenance_mut(SINGLE | LOCKED), + Release, + Relaxed, + ) { + // SAFETY: The only way the state can have changed is if there are threads queued. + // Wake all of them up. + unsafe { self.downgrade_slow(state) } + } + } + + /// Downgrades the lock from write-locked to read-locked in the case that there are threads + /// waiting on the wait queue. + /// + /// This function will either wake up all of the waiters on the wait queue or designate the + /// current holder of the queue lock to wake up all of the waiters instead. Once the waiters + /// wake up, they will continue in the execution loop of `lock_contended`. /// /// # Safety - /// The queue lock must be held by the current thread. + /// + /// * The lock must be write-locked by this thread. + /// * `state` must be a pointer to a node in a valid queue. + /// * There must be threads queued on the lock. + #[cold] + unsafe fn downgrade_slow(&self, mut state: State) { + debug_assert_eq!(state.addr() & (DOWNGRADED | QUEUED | LOCKED), QUEUED | LOCKED); + + // Attempt to wake up all waiters by taking ownership of the entire waiter queue. + loop { + if state.addr() & QUEUE_LOCKED != 0 { + // Another thread already holds the queue lock. Tell it to wake up all waiters. + // If the other thread succeeds in waking up waiters before we release our lock, the + // effect will be just the same as if we had changed the state below. + // Otherwise, the `DOWNGRADED` bit will still be set, meaning that when this thread + // calls `read_unlock` later (because it holds a read lock and must unlock + // eventually), it will realize that the lock is still exclusively locked and act + // accordingly. + let next = state.map_addr(|addr| addr | DOWNGRADED); + match self.state.compare_exchange_weak(state, next, Release, Relaxed) { + Ok(_) => return, + Err(new) => state = new, + } + } else { + // Grab the entire queue by swapping the `state` with a single reader. + let next = ptr::without_provenance_mut(SINGLE | LOCKED); + if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) { + state = new; + continue; + } + + // SAFETY: We have full ownership of this queue now, so nobody else can modify it. + let tail = unsafe { find_tail_and_add_backlinks(to_node(state)) }; + + // Wake up all waiters. + // SAFETY: `tail` was just computed, meaning the whole queue is linked, and we have + // full ownership of the queue, so we have exclusive access. + unsafe { complete_all(tail) }; + + return; + } + } + } + + /// Unlocks the queue. Wakes up all threads if a downgrade was requested, otherwise wakes up the + /// next eligible thread(s) if the lock is unlocked. + /// + /// # Safety + /// + /// * The queue lock must be held by the current thread. + /// * `state` must be a pointer to a node in a valid queue. + /// * There must be threads queued on the lock. unsafe fn unlock_queue(&self, mut state: State) { debug_assert_eq!(state.addr() & (QUEUED | QUEUE_LOCKED), QUEUED | QUEUE_LOCKED); loop { - let tail = unsafe { add_backlinks_and_find_tail(to_node(state)) }; + // SAFETY: Since we have the queue lock, nobody else can be modifying the queue. + let tail = unsafe { find_tail_and_add_backlinks(to_node(state)) }; - if state.addr() & LOCKED == LOCKED { - // Another thread has locked the lock. Leave waking up waiters - // to them by releasing the queue lock. + if state.addr() & (DOWNGRADED | LOCKED) == LOCKED { + // Another thread has locked the lock and no downgrade was requested. + // Leave waking up waiters to them by releasing the queue lock. match self.state.compare_exchange_weak( state, state.mask(!QUEUE_LOCKED), @@ -501,53 +660,63 @@ impl RwLock { } } + // Since we hold the queue lock and downgrades cannot be requested if the lock is + // already read-locked, we have exclusive control over the queue here and can make + // modifications. + + let downgrade = state.addr() & DOWNGRADED != 0; let is_writer = unsafe { tail.as_ref().write }; - if is_writer && let Some(prev) = unsafe { tail.as_ref().prev.get() } { - // `tail` is a writer and there is a node before `tail`. - // Split off `tail`. + if !downgrade + && is_writer + && let Some(prev) = unsafe { tail.as_ref().prev.get() } + { + // If we are not downgrading and the next thread is a writer, only wake up that + // writing thread. - // There are no set `tail` links before the node pointed to by - // `state`, so the first non-null tail field will be current - // (invariant 2). Invariant 4 is fullfilled since `find_tail` - // was called on this node, which ensures all backlinks are set. + // Split off `tail`. + // There are no set `tail` links before the node pointed to by `state`, so the first + // non-null tail field will be current (Invariant 2). + // We also fulfill Invariant 4 since `find_tail` was called on this node, which + // ensures all backlinks are set. unsafe { to_node(state).as_ref().tail.set(Some(prev)); } - // Release the queue lock. Doing this by subtraction is more - // efficient on modern processors since it is a single instruction - // instead of an update loop, which will fail if new threads are - // added to the list. - self.state.fetch_byte_sub(QUEUE_LOCKED, Release); + // Try to release the queue lock. We need to check the state again since another + // thread might have acquired the lock and requested a downgrade. + let next = state.mask(!QUEUE_LOCKED); + if let Err(new) = self.state.compare_exchange_weak(state, next, Release, Acquire) { + // Undo the tail modification above, so that we can find the tail again above. + // As mentioned above, we have exclusive control over the queue, so no other + // thread could have noticed the change. + unsafe { + to_node(state).as_ref().tail.set(Some(tail)); + } + state = new; + continue; + } - // The tail was split off and the lock released. Mark the node as - // completed. + // The tail was split off and the lock was released. Mark the node as completed. unsafe { return Node::complete(tail); } } else { - // The next waiter is a reader or the queue only consists of one - // waiter. Just wake all threads. - - // The lock cannot be locked (checked above), so mark it as - // unlocked to reset the queue. - if let Err(new) = - self.state.compare_exchange_weak(state, UNLOCKED, Release, Acquire) - { + // We are either downgrading, the next waiter is a reader, or the queue only + // consists of one waiter. In any case, just wake all threads. + + // Clear the queue. + let next = + if downgrade { ptr::without_provenance_mut(SINGLE | LOCKED) } else { UNLOCKED }; + if let Err(new) = self.state.compare_exchange_weak(state, next, Release, Acquire) { state = new; continue; } - let mut current = tail; - loop { - let prev = unsafe { current.as_ref().prev.get() }; - unsafe { - Node::complete(current); - } - match prev { - Some(prev) => current = prev, - None => return, - } + // SAFETY: we computed `tail` above, and no new nodes can have been added since + // (otherwise the CAS above would have failed). + // Thus we have complete control over the whole queue. + unsafe { + return complete_all(tail); } } } diff --git a/std/src/sys/sync/rwlock/solid.rs b/std/src/sys/sync/rwlock/solid.rs index 7703082f95116..f664fef907404 100644 --- a/std/src/sys/sync/rwlock/solid.rs +++ b/std/src/sys/sync/rwlock/solid.rs @@ -79,6 +79,12 @@ impl RwLock { let rwl = self.raw(); expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); } + + #[inline] + pub unsafe fn downgrade(&self) { + // The SOLID platform does not support the `downgrade` operation for reader writer locks, so + // this function is simply a no-op as only 1 reader can read: the original writer. + } } impl Drop for RwLock { diff --git a/std/src/sys/sync/rwlock/teeos.rs b/std/src/sys/sync/rwlock/teeos.rs index 763430223834b..4a71a3abc2729 100644 --- a/std/src/sys/sync/rwlock/teeos.rs +++ b/std/src/sys/sync/rwlock/teeos.rs @@ -41,4 +41,10 @@ impl RwLock { pub unsafe fn write_unlock(&self) { unsafe { self.inner.unlock() }; } + + #[inline] + pub unsafe fn downgrade(&self) { + // Since there is no difference between read-locked and write-locked on this platform, this + // function is simply a no-op as only 1 reader can read: the original writer. + } } diff --git a/std/src/sys_common/wtf8.rs b/std/src/sys_common/wtf8.rs index 19d4c94f45099..666942bb8a10f 100644 --- a/std/src/sys_common/wtf8.rs +++ b/std/src/sys_common/wtf8.rs @@ -1052,8 +1052,8 @@ impl Hash for Wtf8 { unsafe impl CloneToUninit for Wtf8 { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { - // SAFETY: we're just a wrapper around [u8] - unsafe { self.bytes.clone_to_uninit(&raw mut (*dst).bytes) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around [u8] + unsafe { self.bytes.clone_to_uninit(dst) } } } diff --git a/std/src/thread/current.rs b/std/src/thread/current.rs index e6eb90c4c30a5..b9b959f98946b 100644 --- a/std/src/thread/current.rs +++ b/std/src/thread/current.rs @@ -165,6 +165,23 @@ pub(crate) fn try_current() -> Option { } } +/// Gets a handle to the thread that invokes it. If the handle stored in thread- +/// local storage was already destroyed, this creates a new unnamed temporary +/// handle to allow thread parking in nearly all situations. +pub(crate) fn current_or_unnamed() -> Thread { + let current = CURRENT.get(); + if current > DESTROYED { + unsafe { + let current = ManuallyDrop::new(Thread::from_raw(current)); + (*current).clone() + } + } else if current == DESTROYED { + Thread::new_unnamed(id::get_or_init()) + } else { + init_current(current) + } +} + /// Gets a handle to the thread that invokes it. /// /// # Examples diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 227ee9d64f375..2ff44fcd4c6b7 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -186,7 +186,12 @@ mod current; #[stable(feature = "rust1", since = "1.0.0")] pub use current::current; -pub(crate) use current::{current_id, drop_current, set_current, try_current}; +pub(crate) use current::{current_id, current_or_unnamed, drop_current, set_current, try_current}; + +mod spawnhook; + +#[unstable(feature = "thread_spawn_hook", issue = "132951")] +pub use spawnhook::add_spawn_hook; //////////////////////////////////////////////////////////////////////////////// // Thread-local storage @@ -259,6 +264,8 @@ pub struct Builder { name: Option, // The size of the stack for the spawned thread in bytes stack_size: Option, + // Skip running and inheriting the thread spawn hooks + no_hooks: bool, } impl Builder { @@ -282,7 +289,7 @@ impl Builder { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { - Builder { name: None, stack_size: None } + Builder { name: None, stack_size: None, no_hooks: false } } /// Names the thread-to-be. Currently the name is used for identification @@ -338,6 +345,16 @@ impl Builder { self } + /// Disables running and inheriting [spawn hooks](add_spawn_hook). + /// + /// Use this if the parent thread is in no way relevant for the child thread. + /// For example, when lazily spawning threads for a thread pool. + #[unstable(feature = "thread_spawn_hook", issue = "132951")] + pub fn no_hooks(mut self) -> Builder { + self.no_hooks = true; + self + } + /// Spawns a new thread by taking ownership of the `Builder`, and returns an /// [`io::Result`] to its [`JoinHandle`]. /// @@ -460,7 +477,7 @@ impl Builder { F: Send, T: Send, { - let Builder { name, stack_size } = self; + let Builder { name, stack_size, no_hooks } = self; let stack_size = stack_size.unwrap_or_else(|| { static MIN: AtomicUsize = AtomicUsize::new(0); @@ -485,6 +502,13 @@ impl Builder { Some(name) => Thread::new(id, name.into()), None => Thread::new_unnamed(id), }; + + let hooks = if no_hooks { + spawnhook::ChildSpawnHooks::default() + } else { + spawnhook::run_spawn_hooks(&my_thread) + }; + let their_thread = my_thread.clone(); let my_packet: Arc> = Arc::new(Packet { @@ -494,9 +518,6 @@ impl Builder { }); let their_packet = my_packet.clone(); - let output_capture = crate::io::set_output_capture(None); - crate::io::set_output_capture(output_capture.clone()); - // Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*. // See for more details. // To prevent leaks we use a wrapper that drops its contents. @@ -534,10 +555,9 @@ impl Builder { imp::Thread::set_name(name); } - crate::io::set_output_capture(output_capture); - let f = f.into_inner(); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { + crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.run()); crate::sys::backtrace::__rust_begin_short_backtrace(f) })); // SAFETY: `their_packet` as been built just above and moved by the @@ -1126,9 +1146,9 @@ pub fn park_timeout_ms(ms: u32) { #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { let guard = PanicGuard; - // SAFETY: park_timeout is called on the parker owned by this thread. + // SAFETY: park_timeout is called on a handle owned by this thread. unsafe { - current().0.parker().park_timeout(dur); + current().park_timeout(dur); } // No panic occurred, do not abort. forget(guard); @@ -1426,6 +1446,15 @@ impl Thread { unsafe { self.0.parker().park() } } + /// Like the public [`park_timeout`], but callable on any handle. This is + /// used to allow parking in TLS destructors. + /// + /// # Safety + /// May only be called from the thread to which this handle belongs. + pub(crate) unsafe fn park_timeout(&self, dur: Duration) { + unsafe { self.0.parker().park_timeout(dur) } + } + /// Atomically makes the handle's token available if it is not already. /// /// Every thread is equipped with some basic low-level blocking support, via diff --git a/std/src/thread/scoped.rs b/std/src/thread/scoped.rs index b2305b1eda7e1..0033fc3a73283 100644 --- a/std/src/thread/scoped.rs +++ b/std/src/thread/scoped.rs @@ -1,4 +1,4 @@ -use super::{Builder, JoinInner, Result, Thread, current, park}; +use super::{Builder, JoinInner, Result, Thread, current_or_unnamed}; use crate::marker::PhantomData; use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; use crate::sync::Arc; @@ -140,7 +140,7 @@ where let scope = Scope { data: Arc::new(ScopeData { num_running_threads: AtomicUsize::new(0), - main_thread: current(), + main_thread: current_or_unnamed(), a_thread_panicked: AtomicBool::new(false), }), env: PhantomData, @@ -152,7 +152,8 @@ where // Wait until all the threads are finished. while scope.data.num_running_threads.load(Ordering::Acquire) != 0 { - park(); + // SAFETY: this is the main thread, the handle belongs to us. + unsafe { scope.data.main_thread.park() }; } // Throw any panic from `f`, or the return value of `f` if no thread panicked. @@ -176,7 +177,7 @@ impl<'scope, 'env> Scope<'scope, 'env> { /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing /// the panic payload. /// - /// If the join handle is dropped, the spawned thread will implicitly joined at the + /// If the join handle is dropped, the spawned thread will be implicitly joined at the /// end of the scope. In that case, if the spawned thread panics, [`scope`] will /// panic after all threads are joined. /// diff --git a/std/src/thread/spawnhook.rs b/std/src/thread/spawnhook.rs new file mode 100644 index 0000000000000..99b5ad9cb9fe5 --- /dev/null +++ b/std/src/thread/spawnhook.rs @@ -0,0 +1,148 @@ +use crate::cell::Cell; +use crate::iter; +use crate::sync::Arc; +use crate::thread::Thread; + +crate::thread_local! { + /// A thread local linked list of spawn hooks. + /// + /// It is a linked list of Arcs, such that it can very cheaply be inhereted by spawned threads. + /// + /// (That technically makes it a set of linked lists with shared tails, so a linked tree.) + static SPAWN_HOOKS: Cell = const { Cell::new(SpawnHooks { first: None }) }; +} + +#[derive(Default, Clone)] +struct SpawnHooks { + first: Option>, +} + +// Manually implement drop to prevent deep recursion when dropping linked Arc list. +impl Drop for SpawnHooks { + fn drop(&mut self) { + let mut next = self.first.take(); + while let Some(SpawnHook { hook, next: n }) = next.and_then(|n| Arc::into_inner(n)) { + drop(hook); + next = n; + } + } +} + +struct SpawnHook { + hook: Box Box>, + next: Option>, +} + +/// Registers a function to run for every newly thread spawned. +/// +/// The hook is executed in the parent thread, and returns a function +/// that will be executed in the new thread. +/// +/// The hook is called with the `Thread` handle for the new thread. +/// +/// The hook will only be added for the current thread and is inherited by the threads it spawns. +/// In other words, adding a hook has no effect on already running threads (other than the current +/// thread) and the threads they might spawn in the future. +/// +/// Hooks can only be added, not removed. +/// +/// The hooks will run in reverse order, starting with the most recently added. +/// +/// # Usage +/// +/// ``` +/// #![feature(thread_spawn_hook)] +/// +/// std::thread::add_spawn_hook(|_| { +/// ..; // This will run in the parent (spawning) thread. +/// move || { +/// ..; // This will run it the child (spawned) thread. +/// } +/// }); +/// ``` +/// +/// # Example +/// +/// A spawn hook can be used to "inherit" a thread local from the parent thread: +/// +/// ``` +/// #![feature(thread_spawn_hook)] +/// +/// use std::cell::Cell; +/// +/// thread_local! { +/// static X: Cell = Cell::new(0); +/// } +/// +/// // This needs to be done once in the main thread before spawning any threads. +/// std::thread::add_spawn_hook(|_| { +/// // Get the value of X in the spawning thread. +/// let value = X.get(); +/// // Set the value of X in the newly spawned thread. +/// move || X.set(value) +/// }); +/// +/// X.set(123); +/// +/// std::thread::spawn(|| { +/// assert_eq!(X.get(), 123); +/// }).join().unwrap(); +/// ``` +#[unstable(feature = "thread_spawn_hook", issue = "132951")] +pub fn add_spawn_hook(hook: F) +where + F: 'static + Send + Sync + Fn(&Thread) -> G, + G: 'static + Send + FnOnce(), +{ + SPAWN_HOOKS.with(|h| { + let mut hooks = h.take(); + let next = hooks.first.take(); + hooks.first = Some(Arc::new(SpawnHook { + hook: Box::new(move |thread| Box::new(hook(thread))), + next, + })); + h.set(hooks); + }); +} + +/// Runs all the spawn hooks. +/// +/// Called on the parent thread. +/// +/// Returns the functions to be called on the newly spawned thread. +pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks { + // Get a snapshot of the spawn hooks. + // (Increments the refcount to the first node.) + let hooks = SPAWN_HOOKS.with(|hooks| { + let snapshot = hooks.take(); + hooks.set(snapshot.clone()); + snapshot + }); + // Iterate over the hooks, run them, and collect the results in a vector. + let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref()) + .map(|hook| (hook.hook)(thread)) + .collect(); + // Pass on the snapshot of the hooks and the results to the new thread, + // which will then run SpawnHookResults::run(). + ChildSpawnHooks { hooks, to_run } +} + +/// The results of running the spawn hooks. +/// +/// This struct is sent to the new thread. +/// It contains the inherited hooks and the closures to be run. +#[derive(Default)] +pub(super) struct ChildSpawnHooks { + hooks: SpawnHooks, + to_run: Vec>, +} + +impl ChildSpawnHooks { + // This is run on the newly spawned thread, directly at the start. + pub(super) fn run(self) { + SPAWN_HOOKS.set(self.hooks); + for run in self.to_run { + run(); + } + } +} diff --git a/stdarch b/stdarch index ff9a4445038ea..e5e00aab0a8c8 160000 --- a/stdarch +++ b/stdarch @@ -1 +1 @@ -Subproject commit ff9a4445038eae46fd095188740946808581bc0e +Subproject commit e5e00aab0a8c8fa35fb7865e88fa82366f615c53 diff --git a/test/src/lib.rs b/test/src/lib.rs index 30ccfe2af8dbd..47407df909bdf 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -24,6 +24,7 @@ #![feature(process_exitcode_internals)] #![feature(panic_can_unwind)] #![feature(test)] +#![feature(thread_spawn_hook)] #![allow(internal_features)] #![warn(rustdoc::unescaped_backticks)] @@ -134,6 +135,16 @@ pub fn test_main(args: &[String], tests: Vec, options: Option Date: Sun, 1 Dec 2024 12:59:07 -0800 Subject: [PATCH 06/13] Harness for `CStr::is_empty` (#194) Towards #150 ### Changes * Added a harness for `is_empty` * Added a small optimization for `arbitray_cstr` ### Verification Result ``` SUMMARY: ** 0 of 193 failed (5 unreachable) VERIFICATION:- SUCCESSFUL Verification Time: 51.462265s Complete - 1 successfully verified harnesses, 0 failures, 1 total. ``` --- library/core/src/ffi/c_str.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 328c7276a22e8..fe97ed3e5f2fb 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -860,8 +860,11 @@ mod verify { // Helper function fn arbitrary_cstr(slice: &[u8]) -> &CStr { + // At a minimum, the slice has a null terminator to form a valid CStr. + kani::assume(slice.len() > 0 && slice[slice.len() - 1] == 0); let result = CStr::from_bytes_until_nul(&slice); - kani::assume(result.is_ok()); + // Given the assumption, from_bytes_until_nul should never fail + assert!(result.is_ok()); let c_str = result.unwrap(); assert!(c_str.is_safe()); c_str @@ -939,4 +942,18 @@ mod verify { assert_eq!(bytes, &slice[..end_idx]); assert!(c_str.is_safe()); } + + #[kani::proof] + #[kani::unwind(33)] + fn check_is_empty() { + const MAX_SIZE: usize = 32; + let string: [u8; MAX_SIZE] = kani::any(); + let slice = kani::slice::any_slice_of_array(&string); + let c_str = arbitrary_cstr(slice); + + let bytes = c_str.to_bytes(); // does not include null terminator + let expected_is_empty = bytes.len() == 0; + assert_eq!(expected_is_empty, c_str.is_empty()); + assert!(c_str.is_safe()); + } } \ No newline at end of file From db71987dd43e7826e7cdad856ac84a26e47afbc2 Mon Sep 17 00:00:00 2001 From: JY <53210261+Jimmycreative@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:07:27 -0800 Subject: [PATCH 07/13] Contracts & Harnesses for write_volatile (#167) Contracts & Harnesses for `core::ptr::NonNull::write_volatile`. --- library/core/src/ptr/non_null.rs | 47 +++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 41e667752e305..715e70b98ea1d 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1132,6 +1132,8 @@ impl NonNull { #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] + #[cfg_attr(kani, kani::modifies(self.as_ptr()))] + #[requires(ub_checks::can_write(self.as_ptr()))] pub unsafe fn write_volatile(self, val: T) where T: Sized, @@ -1775,7 +1777,7 @@ mod verify { let maybe_null_ptr = if kani::any() { xptr as *mut i32 } else { null_mut() }; let _ = NonNull::new(maybe_null_ptr); } - + // pub const unsafe fn read(self) -> T where T: Sized #[kani::proof_for_contract(NonNull::read)] pub fn non_null_check_read() { @@ -2300,4 +2302,47 @@ mod verify { let distance = ptr_nonnull.offset_from(origin_nonnull); } } + + macro_rules! generate_write_volatile_harness { + ($type:ty, $byte_size:expr, $harness_name:ident) => { + #[kani::proof_for_contract(NonNull::write_volatile)] + pub fn $harness_name() { + // Create a pointer generator for the given type with appropriate byte size + let mut generator = kani::PointerGenerator::<$byte_size>::new(); + + // Get a raw pointer from the generator + let raw_ptr: *mut $type = generator.any_in_bounds().ptr; + + // Create a non-null pointer from the raw pointer + let ptr = NonNull::new(raw_ptr).unwrap(); + + // Create a non-deterministic value to write + let new_value: $type = kani::any(); + + unsafe { + // Perform the volatile write operation + ptr.write_volatile(new_value); + + // Read back the value and assert it's correct + assert_eq!(ptr.as_ptr().read_volatile(), new_value); + } + } + }; + } + + // Generate proof harnesses for multiple types with appropriate byte sizes + generate_write_volatile_harness!(i8, 1, non_null_check_write_volatile_i8); + generate_write_volatile_harness!(i16, 2, non_null_check_write_volatile_i16); + generate_write_volatile_harness!(i32, 4, non_null_check_write_volatile_i32); + generate_write_volatile_harness!(i64, 8, non_null_check_write_volatile_i64); + generate_write_volatile_harness!(i128, 16, non_null_check_write_volatile_i128); + generate_write_volatile_harness!(isize, {core::mem::size_of::()}, non_null_check_write_volatile_isize); + generate_write_volatile_harness!(u8, 1, non_null_check_write_volatile_u8); + generate_write_volatile_harness!(u16, 2, non_null_check_write_volatile_u16); + generate_write_volatile_harness!(u32, 4, non_null_check_write_volatile_u32); + generate_write_volatile_harness!(u64, 8, non_null_check_write_volatile_u64); + generate_write_volatile_harness!(u128, 16, non_null_check_write_volatile_u128); + generate_write_volatile_harness!(usize, {core::mem::size_of::()}, non_null_check_write_volatile_usize); + generate_write_volatile_harness!((), 1, non_null_check_write_volatile_unit); + } From ca85f7fcaa97901ba93138bf0abbc7b42130239d Mon Sep 17 00:00:00 2001 From: Rajath Kotyal <53811196+rajathkotyal@users.noreply.github.com> Date: Tue, 3 Dec 2024 00:54:05 -0800 Subject: [PATCH 08/13] Cstr - add proof from_bytes_with_null (#198) Towards #150 Verifies that the CStr safety invariant holds after calling : from_bytes_with_nul --> core::ffi::c_str module --- library/core/src/ffi/c_str.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index fe97ed3e5f2fb..22dcbdd834746 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -885,7 +885,20 @@ mod verify { assert!(c_str.is_safe()); } } - + + #[kani::proof] + #[kani::unwind(17)] + fn check_from_bytes_with_nul() { + const MAX_SIZE: usize = 16; + let string: [u8; MAX_SIZE] = kani::any(); + let slice = kani::slice::any_slice_of_array(&string); + + let result = CStr::from_bytes_with_nul(slice); + if let Ok(c_str) = result { + assert!(c_str.is_safe()); + } + } + // pub const fn count_bytes(&self) -> usize #[kani::proof] #[kani::unwind(32)] @@ -956,4 +969,4 @@ mod verify { assert_eq!(expected_is_empty, c_str.is_empty()); assert!(c_str.is_safe()); } -} \ No newline at end of file +} From 892ee59fa710697c5740cb239b5db15d16369ed0 Mon Sep 17 00:00:00 2001 From: Daniel Tu <135958699+danielhumanmod@users.noreply.github.com> Date: Tue, 3 Dec 2024 06:07:28 -0800 Subject: [PATCH 09/13] Contracts & Harnesses for `byte_add`, `byte_offset`, and `byte_offset_from` (#103) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description: This PR introduces function contracts and proof harness for the NonNull pointer in the Rust core library. Specifically, it verifies three new APIs—`byte_offset`, `byte_add`, and `byte_offset_from` with Kani. These changes enhance the functionality of pointer arithmetic and verification for NonNull pointers. # Changes Overview: **Covered APIs:** 1. `NonNull::byte_add`: Adds a specified byte offset to a pointer. 2. `NonNull::byte_offset`: Allows calculating an offset from a pointer in bytes. 4. `NonNull::byte_offset_from`: Calculates the distance between two pointers in bytes. **Proof harness:** 1. `non_null_byte_add_proof` 2. `non_null_byte_offset_proof` 3. `non_null_byte_offset_from_proof` Towards #53 --- library/core/src/ptr/non_null.rs | 86 ++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 715e70b98ea1d..c347d8b82c4ac 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -526,6 +526,11 @@ impl NonNull { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] + #[requires( + (self.as_ptr().addr() as isize).checked_add(count).is_some() && + kani::mem::same_allocation(self.as_ptr(), self.as_ptr().wrapping_byte_offset(count)) + )] + #[ensures(|result: &Self| result.as_ptr() == self.as_ptr().wrapping_byte_offset(count))] pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset` and `byte_offset` has // the same safety contract. @@ -607,6 +612,10 @@ impl NonNull { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] + #[requires( + count <= (isize::MAX as usize) - self.as_ptr().addr() && // Ensure the offset doesn't overflow + (count == 0 || kani::mem::same_allocation(self.as_ptr(), self.as_ptr().wrapping_byte_add(count))) // Ensure the offset is within the same allocation + )] pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add` and `byte_add` has the same // safety contract. @@ -820,6 +829,14 @@ impl NonNull { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] + #[requires( + self.as_ptr().addr() == origin.as_ptr().addr() || + kani::mem::same_allocation(self.as_ptr() as *const(), origin.as_ptr() as *const()) + )] + #[ensures( + |result: &isize| + *result == (self.as_ptr() as *const u8).offset_from(origin.as_ptr() as *const u8) + )] pub const unsafe fn byte_offset_from(self, origin: NonNull) -> isize { // SAFETY: the caller must uphold the safety contract for `byte_offset_from`. unsafe { self.pointer.byte_offset_from(origin.pointer) } @@ -1736,6 +1753,7 @@ impl From<&T> for NonNull { mod verify { use super::*; use crate::ptr::null_mut; + use crate::mem; use kani::PointerGenerator; trait SampleTrait { @@ -2345,4 +2363,72 @@ mod verify { generate_write_volatile_harness!(usize, {core::mem::size_of::()}, non_null_check_write_volatile_usize); generate_write_volatile_harness!((), 1, non_null_check_write_volatile_unit); + #[kani::proof_for_contract(NonNull::byte_add)] + pub fn non_null_byte_add_proof() { + // Make size as 1000 to ensure the array is large enough to cover various senarios + // while maintaining a reasonable proof runtime + const ARR_SIZE: usize = mem::size_of::() * 1000; + let mut generator = PointerGenerator::::new(); + + let count: usize = kani::any(); + let raw_ptr: *mut i32 = generator.any_in_bounds().ptr as *mut i32; + + unsafe { + let ptr = NonNull::new(raw_ptr).unwrap(); + let result = ptr.byte_add(count); + } + } + + #[kani::proof_for_contract(NonNull::byte_add)] + pub fn non_null_byte_add_dangling_proof() { + let ptr = NonNull::::dangling(); + unsafe { + let _ = ptr.byte_add(0); + } + } + + #[kani::proof_for_contract(NonNull::byte_offset)] + pub fn non_null_byte_offset_proof() { + const ARR_SIZE: usize = mem::size_of::() * 1000; + let mut generator = PointerGenerator::::new(); + + let count: isize = kani::any(); + let raw_ptr: *mut i32 = generator.any_in_bounds().ptr as *mut i32; + + unsafe { + let ptr = NonNull::new(raw_ptr).unwrap(); + let result = ptr.byte_offset(count); + } + } + + #[kani::proof_for_contract(NonNull::byte_offset_from)] + pub fn non_null_byte_offset_from_proof() { + const SIZE: usize = mem::size_of::() * 1000; + let mut generator1 = PointerGenerator::::new(); + let mut generator2 = PointerGenerator::::new(); + + let ptr: *mut i32 = generator1.any_in_bounds().ptr as *mut i32; + + let origin: *mut i32 = if kani::any() { + generator1.any_in_bounds().ptr as *mut i32 + } else { + generator2.any_in_bounds().ptr as *mut i32 + }; + + let ptr_nonnull = unsafe { NonNull::new(ptr).unwrap() }; + let origin_nonnull = unsafe { NonNull::new(origin).unwrap() }; + + unsafe { + let result = ptr_nonnull.byte_offset_from(origin_nonnull); + } + } + + #[kani::proof_for_contract(NonNull::byte_offset_from)] + pub fn non_null_byte_offset_from_dangling_proof() { + let origin = NonNull::::dangling(); + let ptr = origin; + unsafe { + let _ = ptr.byte_offset_from(origin); + } + } } From d0d9de25c44d829f52c837636284cbfa776f544e Mon Sep 17 00:00:00 2001 From: Yifei Wang <40480373+xsxszab@users.noreply.github.com> Date: Tue, 3 Dec 2024 07:36:24 -0800 Subject: [PATCH 10/13] Contracts and Harnesses for `<*const T>::add`, `sub` and `offset` (#166) Towards #76 **Summary** * Adds contracts for <*const T>::add, sub and offset. * Adds proof for contracts for above methods, verifying following pointee types: * All integer types * Tuples (representing composite types) * Slices * Unit type --- library/core/src/ptr/const_ptr.rs | 369 ++++++++++++++++++++++++++++-- 1 file changed, 356 insertions(+), 13 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index b2cecbf053c81..ec67d891686fd 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -406,6 +406,21 @@ impl *const T { #[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 + #[requires( + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize`. + // Precondition 2: adding the computed offset to `self` does not cause overflow. + // These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani. + count.checked_mul(core::mem::size_of::() as isize) + .map_or(false, |computed_offset| (self as isize).checked_add(computed_offset).is_some()) && + // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. + // Otherwise, for non-unit types, `self` and `self.wrapping_offset(count)` should point to the same allocated object, + // restricting `count` to prevent crossing allocation boundaries. + ((core::mem::size_of::() == 0) || (core::ub_checks::same_allocation(self, self.wrapping_offset(count)))) + )] + // Postcondition: If `T` is a unit type (`size_of::() == 0`), no allocation check is needed. + // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object, + // verifying that the result remains within the same allocation as `self`. + #[ensures(|result| (core::mem::size_of::() == 0) || core::ub_checks::same_allocation(self, *result as *const T))] pub const unsafe fn offset(self, count: isize) -> *const T where T: Sized, @@ -673,7 +688,7 @@ impl *const T { // Ensure the distance between `self` and `origin` is aligned to `T` (self as isize - origin as isize) % (mem::size_of::() as isize) == 0 && // Ensure both pointers are in the same allocation or are pointing to the same address - (self as isize == origin as isize || kani::mem::same_allocation(self, origin)) + (self as isize == origin as isize || core::ub_checks::same_allocation(self, origin)) )] // The result should equal the distance in terms of elements of type `T` as per the documentation above #[ensures(|result| *result == (self as isize - origin as isize) / (mem::size_of::() as isize))] @@ -928,6 +943,23 @@ impl *const T { #[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 + #[requires( + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize`. + // Precondition 2: adding the computed offset to `self` does not cause overflow. + // These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani. + count.checked_mul(core::mem::size_of::()) + .map_or(false, |computed_offset| { + computed_offset <= isize::MAX as usize && (self as isize).checked_add(computed_offset as isize).is_some() + }) && + // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. + // Otherwise, for non-unit types, `self` and `self.wrapping_add(count)` should point to the same allocated object, + // restricting `count` to prevent crossing allocation boundaries. + ((core::mem::size_of::() == 0) || (core::ub_checks::same_allocation(self, self.wrapping_add(count)))) + )] + // Postcondition: If `T` is a unit type (`size_of::() == 0`), no allocation check is needed. + // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object, + // verifying that the result remains within the same allocation as `self`. + #[ensures(|result| (core::mem::size_of::() == 0) || core::ub_checks::same_allocation(self, *result as *const T))] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -1035,6 +1067,23 @@ impl *const T { #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_neg))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[requires( + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize`. + // Precondition 2: substracting the computed offset from `self` does not cause overflow. + // These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani. + count.checked_mul(core::mem::size_of::()) + .map_or(false, |computed_offset| { + computed_offset <= isize::MAX as usize && (self as isize).checked_sub(computed_offset as isize).is_some() + }) && + // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. + // Otherwise, for non-unit types, `self` and `self.wrapping_sub(count)` should point to the same allocated object, + // restricting `count` to prevent crossing allocation boundaries. + ((core::mem::size_of::() == 0) || (core::ub_checks::same_allocation(self, self.wrapping_sub(count)))) + )] + // Postcondition: If `T` is a unit type (`size_of::() == 0`), no allocation check is needed. + // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object, + // verifying that the result remains within the same allocation as `self`. + #[ensures(|result| (core::mem::size_of::() == 0) || core::ub_checks::same_allocation(self, *result as *const T))] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -1726,19 +1775,300 @@ mod verify { use core::mem; use kani::PointerGenerator; - // Proof for unit size will panic as offset_from needs the pointee size to be greater then 0 - #[kani::proof_for_contract(<*const ()>::offset_from)] - #[kani::should_panic] - pub fn check_const_offset_from_unit() { - let val: () = (); - let src_ptr: *const () = &val; - let dest_ptr: *const () = &val; - unsafe { - dest_ptr.offset_from(src_ptr); - } + /// This macro generates a single verification harness for the `offset`, `add`, or `sub` + /// pointer operations, supporting integer, composite, or unit types. + /// - `$ty`: The type of the slice's elements (e.g., `i32`, `u32`, tuples). + /// - `$fn_name`: The name of the function being checked (`add`, `sub`, or `offset`). + /// - `$proof_name`: The name assigned to the generated proof for the contract. + /// - `$count_ty:ty`: The type of the input variable passed to the method being invoked. + /// + /// Note: This macro is intended for internal use only and should be invoked exclusively + /// by the `generate_arithmetic_harnesses` macro. Its purpose is to reduce code duplication, + /// and it is not meant to be used directly elsewhere in the codebase. + macro_rules! generate_single_arithmetic_harness { + ($ty:ty, $proof_name:ident, $fn_name:ident, $count_ty:ty) => { + #[kani::proof_for_contract(<*const $ty>::$fn_name)] + pub fn $proof_name() { + // 200 bytes are large enough to cover all pointee types used for testing + const BUF_SIZE: usize = 200; + let mut generator = kani::PointerGenerator::::new(); + let test_ptr: *const $ty = generator.any_in_bounds().ptr; + let count: $count_ty = kani::any(); + unsafe { + test_ptr.$fn_name(count); + } + } + }; + } + + /// This macro generates verification harnesses for the `offset`, `add`, and `sub` + /// pointer operations, supporting integer, composite, or unit types. + /// - `$ty`: The pointee type (e.g., i32, u32, tuples). + /// - `$offset_fn_name`: The name for the `offset` proof for contract. + /// - `$add_fn_name`: The name for the `add` proof for contract. + /// - `$sub_fn_name`: The name for the `sub` proof for contract. + macro_rules! generate_arithmetic_harnesses { + ($ty:ty, $add_fn_name:ident, $sub_fn_name:ident, $offset_fn_name:ident) => { + generate_single_arithmetic_harness!($ty, $add_fn_name, add, usize); + generate_single_arithmetic_harness!($ty, $sub_fn_name, sub, usize); + generate_single_arithmetic_harness!($ty, $offset_fn_name, offset, isize); + }; } - // Array size bound for kani::any_array + // Generate harnesses for unit type (add, sub, offset) + generate_arithmetic_harnesses!( + (), + check_const_add_unit, + check_const_sub_unit, + check_const_offset_unit + ); + + // Generate harnesses for integer types (add, sub, offset) + generate_arithmetic_harnesses!( + i8, + check_const_add_i8, + check_const_sub_i8, + check_const_offset_i8 + ); + generate_arithmetic_harnesses!( + i16, + check_const_add_i16, + check_const_sub_i16, + check_const_offset_i16 + ); + generate_arithmetic_harnesses!( + i32, + check_const_add_i32, + check_const_sub_i32, + check_const_offset_i32 + ); + generate_arithmetic_harnesses!( + i64, + check_const_add_i64, + check_const_sub_i64, + check_const_offset_i64 + ); + generate_arithmetic_harnesses!( + i128, + check_const_add_i128, + check_const_sub_i128, + check_const_offset_i128 + ); + generate_arithmetic_harnesses!( + isize, + check_const_add_isize, + check_const_sub_isize, + check_const_offset_isize + ); + generate_arithmetic_harnesses!( + u8, + check_const_add_u8, + check_const_sub_u8, + check_const_offset_u8 + ); + generate_arithmetic_harnesses!( + u16, + check_const_add_u16, + check_const_sub_u16, + check_const_offset_u16 + ); + generate_arithmetic_harnesses!( + u32, + check_const_add_u32, + check_const_sub_u32, + check_const_offset_u32 + ); + generate_arithmetic_harnesses!( + u64, + check_const_add_u64, + check_const_sub_u64, + check_const_offset_u64 + ); + generate_arithmetic_harnesses!( + u128, + check_const_add_u128, + check_const_sub_u128, + check_const_offset_u128 + ); + generate_arithmetic_harnesses!( + usize, + check_const_add_usize, + check_const_sub_usize, + check_const_offset_usize + ); + + // Generte harnesses for composite types (add, sub, offset) + generate_arithmetic_harnesses!( + (i8, i8), + check_const_add_tuple_1, + check_const_sub_tuple_1, + check_const_offset_tuple_1 + ); + generate_arithmetic_harnesses!( + (f64, bool), + check_const_add_tuple_2, + check_const_sub_tuple_2, + check_const_offset_tuple_2 + ); + generate_arithmetic_harnesses!( + (i32, f64, bool), + check_const_add_tuple_3, + check_const_sub_tuple_3, + check_const_offset_tuple_3 + ); + generate_arithmetic_harnesses!( + (i8, u16, i32, u64, isize), + check_const_add_tuple_4, + check_const_sub_tuple_4, + check_const_offset_tuple_4 + ); + + // Constant for array size used in all tests + const ARRAY_SIZE: usize = 5; + + /// This macro generates a single verification harness for the `offset`, `add`, or `sub` + /// pointer operations for a slice type. + /// - `$ty`: The type of the array's elements (e.g., `i32`, `u32`, tuples). + /// - `$fn_name`: The name of the function being checked (`add`, `sub`, or `offset`). + /// - `$proof_name`: The name assigned to the generated proof for the contract. + /// - `$count_ty:ty`: The type of the input variable passed to the method being invoked. + /// + /// Note: This macro is intended for internal use only and should be invoked exclusively + /// by the `generate_slice_harnesses` macro. Its purpose is to reduce code duplication, + /// and it is not meant to be used directly elsewhere in the codebase. + macro_rules! generate_single_slice_harness { + ($ty:ty, $proof_name:ident, $fn_name:ident, $count_ty:ty) => { + #[kani::proof_for_contract(<*const $ty>::$fn_name)] + fn $proof_name() { + let arr: [$ty; ARRAY_SIZE] = kani::Arbitrary::any_array(); + let test_ptr: *const $ty = arr.as_ptr(); + let offset: usize = kani::any(); + kani::assume(offset <= ARRAY_SIZE * mem::size_of::<$ty>()); + let ptr_with_offset: *const $ty = test_ptr.wrapping_byte_add(offset); + + let count: $count_ty = kani::any(); + unsafe { + ptr_with_offset.$fn_name(count); + } + } + }; + } + + /// This macro generates verification harnesses for the `offset`, `add`, and `sub` + /// pointer operations for a slice type. + /// - `$ty`: The type of the array (e.g., i32, u32, tuples). + /// - `$offset_fn_name`: The name for the `offset` proof for contract. + /// - `$add_fn_name`: The name for the `add` proof for contract. + /// - `$sub_fn_name`: The name for the `sub` proof for contract. + macro_rules! generate_slice_harnesses { + ($ty:ty, $add_fn_name:ident, $sub_fn_name:ident, $offset_fn_name:ident) => { + generate_single_slice_harness!($ty, $add_fn_name, add, usize); + generate_single_slice_harness!($ty, $sub_fn_name, sub, usize); + generate_single_slice_harness!($ty, $offset_fn_name, offset, isize); + }; + } + + // Generate slice harnesses for various types (add, sub, offset) + generate_slice_harnesses!( + i8, + check_const_add_slice_i8, + check_const_sub_slice_i8, + check_const_offset_slice_i8 + ); + generate_slice_harnesses!( + i16, + check_const_add_slice_i16, + check_const_sub_slice_i16, + check_const_offset_slice_i16 + ); + generate_slice_harnesses!( + i32, + check_const_add_slice_i32, + check_const_sub_slice_i32, + check_const_offset_slice_i32 + ); + generate_slice_harnesses!( + i64, + check_const_add_slice_i64, + check_const_sub_slice_i64, + check_const_offset_slice_i64 + ); + generate_slice_harnesses!( + i128, + check_const_add_slice_i128, + check_const_sub_slice_i128, + check_const_offset_slice_i128 + ); + generate_slice_harnesses!( + isize, + check_const_add_slice_isize, + check_const_sub_slice_isize, + check_const_offset_slice_isize + ); + generate_slice_harnesses!( + u8, + check_const_add_slice_u8, + check_const_sub_slice_u8, + check_const_offset_slice_u8 + ); + generate_slice_harnesses!( + u16, + check_const_add_slice_u16, + check_const_sub_slice_u16, + check_const_offset_slice_u16 + ); + generate_slice_harnesses!( + u32, + check_const_add_slice_u32, + check_const_sub_slice_u32, + check_const_offset_slice_u32 + ); + generate_slice_harnesses!( + u64, + check_const_add_slice_u64, + check_const_sub_slice_u64, + check_const_offset_slice_u64 + ); + generate_slice_harnesses!( + u128, + check_const_add_slice_u128, + check_const_sub_slice_u128, + check_const_offset_slice_u128 + ); + generate_slice_harnesses!( + usize, + check_const_add_slice_usize, + check_const_sub_slice_usize, + check_const_offset_slice_usize + ); + + // Generate slice harnesses for tuples (add, sub, offset) + generate_slice_harnesses!( + (i8, i8), + check_const_add_slice_tuple_1, + check_const_sub_slice_tuple_1, + check_const_offset_slice_tuple_1 + ); + generate_slice_harnesses!( + (f64, bool), + check_const_add_slice_tuple_2, + check_const_sub_slice_tuple_2, + check_const_offset_slice_tuple_2 + ); + generate_slice_harnesses!( + (i32, f64, bool), + check_const_add_slice_tuple_3, + check_const_sub_slice_tuple_3, + check_const_offset_slice_tuple_3 + ); + generate_slice_harnesses!( + (i8, u16, i32, u64, isize), + check_const_add_slice_tuple_4, + check_const_sub_slice_tuple_4, + check_const_offset_slice_tuple_4 + ); + + // Array size bound for kani::any_array for `offset_from` verification const ARRAY_LEN: usize = 40; macro_rules! generate_offset_from_harness { @@ -1781,6 +2111,19 @@ mod verify { }; } + // Proof for unit size will panic as offset_from needs the pointee size to be greater then 0 + #[kani::proof_for_contract(<*const ()>::offset_from)] + #[kani::should_panic] + pub fn check_const_offset_from_unit() { + let val: () = (); + let src_ptr: *const () = &val; + let dest_ptr: *const () = &val; + unsafe { + dest_ptr.offset_from(src_ptr); + } + } + + // fn <*const T>::offset_from() integer and integer slice types verification generate_offset_from_harness!( u8, check_const_offset_from_u8, @@ -1811,7 +2154,6 @@ mod verify { check_const_offset_from_usize, check_const_offset_from_usize_arr ); - generate_offset_from_harness!( i8, check_const_offset_from_i8, @@ -1843,6 +2185,7 @@ mod verify { check_const_offset_from_isize_arr ); + // fn <*const T>::offset_from() tuple and tuple slice types verification generate_offset_from_harness!( (i8, i8), check_const_offset_from_tuple_1, From d9780d64c83719312991c6d7d9ab358cb0748ccd Mon Sep 17 00:00:00 2001 From: Rajath Kotyal <53811196+rajathkotyal@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:51:06 -0800 Subject: [PATCH 11/13] CStr Invariant proofs for bytes, as_ptr, to_str (#192) Towards #150 Verifies that the CStr safety invariant holds after calling : `bytes core::ffi::c_str` `to_str core::ffi::c_str` `as_ptr core::ffi::c_str` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Co-authored-by: Yenyun035 Co-authored-by: Yenyun035 <57857379+Yenyun035@users.noreply.github.com> --- library/core/src/ffi/c_str.rs | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 22dcbdd834746..6c038e927e408 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -886,6 +886,68 @@ mod verify { } } + // pub fn bytes(&self) -> Bytes<'_> + #[kani::proof] + #[kani::unwind(32)] + fn check_bytes() { + const MAX_SIZE: usize = 32; + let string: [u8; MAX_SIZE] = kani::any(); + let slice = kani::slice::any_slice_of_array(&string); + let c_str = arbitrary_cstr(slice); + + let bytes_iterator = c_str.bytes(); + let bytes_expected = c_str.to_bytes(); + + // Compare the bytes obtained from the iterator and the slice + // bytes_expected.iter().copied() converts the slice into an iterator over u8 + assert!(bytes_iterator.eq(bytes_expected.iter().copied())); + assert!(c_str.is_safe()); + } + + // pub const fn to_str(&self) -> Result<&str, str::Utf8Error> + #[kani::proof] + #[kani::unwind(32)] + fn check_to_str() { + const MAX_SIZE: usize = 32; + let string: [u8; MAX_SIZE] = kani::any(); + let slice = kani::slice::any_slice_of_array(&string); + let c_str = arbitrary_cstr(slice); + + // a double conversion here and assertion, if the bytes are still the same, function is valid + let str_result = c_str.to_str(); + if let Ok(s) = str_result { + assert_eq!(s.as_bytes(), c_str.to_bytes()); + } + assert!(c_str.is_safe()); + } + + // pub const fn as_ptr(&self) -> *const c_char + #[kani::proof] + #[kani::unwind(33)] + fn check_as_ptr() { + const MAX_SIZE: usize = 32; + let string: [u8; MAX_SIZE] = kani::any(); + let slice = kani::slice::any_slice_of_array(&string); + let c_str = arbitrary_cstr(slice); + + let ptr = c_str.as_ptr(); + let bytes_with_nul = c_str.to_bytes_with_nul(); + let len = bytes_with_nul.len(); + + // We ensure that `ptr` is valid for reads of `len` bytes + unsafe { + for i in 0..len { + // Iterate and get each byte in the C string from our raw ptr + let byte_at_ptr = *ptr.add(i); + // Get the byte at every pos + let byte_in_cstr = bytes_with_nul[i]; + // Compare the two bytes to ensure they are equal + assert_eq!(byte_at_ptr as u8, byte_in_cstr); + } + } + assert!(c_str.is_safe()); + } + #[kani::proof] #[kani::unwind(17)] fn check_from_bytes_with_nul() { From 72323e497d4b4cd9e64f6d5cf204b4345eca5835 Mon Sep 17 00:00:00 2001 From: Yenyun035 <57857379+Yenyun035@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:21:17 -0800 Subject: [PATCH 12/13] Contracts & Harnesses for `f{32,64}::to_int_unchecked` (#134) Towards / Resolves #59 (Resolved) Depends on [this Kani Issue](https://github.com/model-checking/kani/issues/3629) and [this PR](https://github.com/model-checking/kani/pull/3660), as discussed in [this thread](https://github.com/model-checking/verify-rust-std/issues/59#issuecomment-2428184293) in #59 (Resolved) Depends on [this Kani Issue](https://github.com/model-checking/kani/issues/3711) and [this PR](https://github.com/model-checking/kani/pull/3742) (Resolved) Waiting for Kani PR#3742 merged into `feature/verify-rust-std` f16 and f128 are in #163 ### Changes * Added contracts for `f{32,64}::to_int_unchecked` (located in `library/core/src/num/f{32,64}.rs`) * Added a macro for generating `to_int_unchecked` harnesses * Added harnesses for `f{32,64}to_int_unchecked` of each integer type * `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `u8`, `u16`, `u32`, `u64`, `u128`, `usize` --- 12 harnesses in total. ### Verification Results To compile, we need to add the `-Z float-lib` flag. ``` Checking harness num::verify::checked_f32_to_int_unchecked_usize... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.424911s Checking harness num::verify::checked_f64_to_int_unchecked_u128... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.8557353s Checking harness num::verify::checked_f32_to_int_unchecked_u16... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.195041s Checking harness num::verify::checked_f32_to_int_unchecked_i8... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.2361426s Checking harness num::verify::checked_f64_to_int_unchecked_i32... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.3952055s Checking harness num::verify::checked_f64_to_int_unchecked_i128... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 7.5295496s Checking harness num::verify::checked_f64_to_int_unchecked_u16... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.2897367s Checking harness num::verify::checked_f32_to_int_unchecked_i64... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.58576s Checking harness num::verify::checked_f64_to_int_unchecked_i16... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.2046432s Checking harness num::verify::checked_f32_to_int_unchecked_i128... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.8473463s Checking harness num::verify::checked_f32_to_int_unchecked_u8... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.131122s Checking harness num::verify::checked_f32_to_int_unchecked_i16... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.436728s Checking harness num::verify::checked_f32_to_int_unchecked_u128... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.666422s Checking harness num::verify::checked_f64_to_int_unchecked_u8... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.17829s Checking harness num::verify::checked_f32_to_int_unchecked_i32... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.6507607s Checking harness num::verify::checked_f64_to_int_unchecked_i64... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 7.3081775s Checking harness num::verify::checked_f64_to_int_unchecked_u64... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 7.0912967s Checking harness num::verify::checked_f64_to_int_unchecked_i8... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.4602604s Checking harness num::verify::checked_f64_to_int_unchecked_usize... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.9098988s Checking harness num::verify::checked_f64_to_int_unchecked_u32... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.557031s Checking harness num::verify::checked_f64_to_int_unchecked_isize... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 7.1193557s Checking harness num::verify::checked_f32_to_int_unchecked_u64... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.7919626s Checking harness num::verify::checked_f32_to_int_unchecked_u32... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.557074s Checking harness num::verify::checked_f32_to_int_unchecked_isize... VERIFICATION RESULT: ** 0 of 136 failed VERIFICATION:- SUCCESSFUL Verification Time: 6.710118s Complete - 24 successfully verified harnesses, 0 failures, 24 total. ``` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Co-authored-by: rajathmCMU Co-authored-by: MWDZ Co-authored-by: Zyad Hassan --- library/core/src/num/f32.rs | 10 ++++++ library/core/src/num/f64.rs | 9 ++++++ library/core/src/num/mod.rs | 57 +++++++++++++++++++++++++++++++++++ library/core/src/ub_checks.rs | 10 ++++++ scripts/run-kani.sh | 4 +-- 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 47dfce7530fb7..fffc403470508 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -18,6 +18,14 @@ use crate::mem; use crate::num::FpCategory; use crate::panic::const_assert; +use safety::requires; + +#[cfg(kani)] +use crate::kani; + +#[allow(unused_imports)] +use crate::ub_checks::float_to_int_in_range; + /// The radix or base of the internal representation of `f32`. /// Use [`f32::RADIX`] instead. /// @@ -1054,6 +1062,8 @@ impl f32 { without modifying the original"] #[stable(feature = "float_approx_unchecked_to", since = "1.44.0")] #[inline] + // is_finite() checks if the given float is neither infinite nor NaN. + #[requires(self.is_finite() && float_to_int_in_range::(self))] pub unsafe fn to_int_unchecked(self) -> Int where Self: FloatToInt, diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index c89023c1ae490..166fb2d329a5a 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -17,6 +17,13 @@ use crate::intrinsics; use crate::mem; use crate::num::FpCategory; use crate::panic::const_assert; +use safety::requires; + +#[cfg(kani)] +use crate::kani; + +#[allow(unused_imports)] +use crate::ub_checks::float_to_int_in_range; /// The radix or base of the internal representation of `f64`. /// Use [`f64::RADIX`] instead. @@ -1055,6 +1062,8 @@ impl f64 { without modifying the original"] #[stable(feature = "float_approx_unchecked_to", since = "1.44.0")] #[inline] + // is_finite() checks if the given float is neither infinite nor NaN. + #[requires(self.is_finite() && float_to_int_in_range::(self))] pub unsafe fn to_int_unchecked(self) -> Int where Self: FloatToInt, diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 761ae7ab06ff0..15452a7a508fc 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1831,6 +1831,21 @@ mod verify { } } + // Part 3: Float to Integer Conversion function Harness Generation Macro + macro_rules! generate_to_int_unchecked_harness { + ($floatType:ty, $($intType:ty, $harness_name:ident),+) => { + $( + #[kani::proof_for_contract($floatType::to_int_unchecked)] + pub fn $harness_name() { + let num1: $floatType = kani::any::<$floatType>(); + let result = unsafe { num1.to_int_unchecked::<$intType>() }; + + assert_eq!(result, num1 as $intType); + } + )+ + } + } + // `unchecked_add` proofs // // Target types: @@ -2128,4 +2143,46 @@ mod verify { generate_wrapping_shift_harness!(u128, wrapping_shr, checked_wrapping_shr_u128); generate_wrapping_shift_harness!(usize, wrapping_shr, checked_wrapping_shr_usize); + // `f{16,32,64,128}::to_int_unchecked` proofs + // + // Target integer types: + // i{8,16,32,64,128,size} and u{8,16,32,64,128,size} -- 12 types in total + // + // Target contracts: + // 1. Float is not `NaN` and infinite + // 2. Float is representable in the return type `Int`, after truncating + // off its fractional part + // [requires(self.is_finite() && kani::float::float_to_int_in_range::(self))] + // + // Target function: + // pub unsafe fn to_int_unchecked(self) -> Int where Self: FloatToInt + generate_to_int_unchecked_harness!(f32, + i8, checked_f32_to_int_unchecked_i8, + i16, checked_f32_to_int_unchecked_i16, + i32, checked_f32_to_int_unchecked_i32, + i64, checked_f32_to_int_unchecked_i64, + i128, checked_f32_to_int_unchecked_i128, + isize, checked_f32_to_int_unchecked_isize, + u8, checked_f32_to_int_unchecked_u8, + u16, checked_f32_to_int_unchecked_u16, + u32, checked_f32_to_int_unchecked_u32, + u64, checked_f32_to_int_unchecked_u64, + u128, checked_f32_to_int_unchecked_u128, + usize, checked_f32_to_int_unchecked_usize + ); + + generate_to_int_unchecked_harness!(f64, + i8, checked_f64_to_int_unchecked_i8, + i16, checked_f64_to_int_unchecked_i16, + i32, checked_f64_to_int_unchecked_i32, + i64, checked_f64_to_int_unchecked_i64, + i128, checked_f64_to_int_unchecked_i128, + isize, checked_f64_to_int_unchecked_isize, + u8, checked_f64_to_int_unchecked_u8, + u16, checked_f64_to_int_unchecked_u16, + u32, checked_f64_to_int_unchecked_u32, + u64, checked_f64_to_int_unchecked_u64, + u128, checked_f64_to_int_unchecked_u128, + usize, checked_f64_to_int_unchecked_usize + ); } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 5598c7bb41d38..9b7a64a43000e 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -219,12 +219,22 @@ mod predicates { let _ = (src, dst); true } + + /// Check if a float is representable in the given integer type + pub fn float_to_int_in_range(value: Float) -> bool + where + Float: core::convert::FloatToInt + { + let _ = value; + true + } } #[cfg(kani)] mod predicates { pub use crate::kani::mem::{can_dereference, can_write, can_read_unaligned, can_write_unaligned, same_allocation}; + pub use crate::kani::float::float_to_int_in_range; } /// This trait should be used to specify and check type safety invariants for a diff --git a/scripts/run-kani.sh b/scripts/run-kani.sh index e32bb22c23f56..a576717849aca 100755 --- a/scripts/run-kani.sh +++ b/scripts/run-kani.sh @@ -214,15 +214,15 @@ main() { -Z function-contracts \ -Z mem-predicates \ -Z loop-contracts \ + -Z float-lib \ --output-format=terse \ $command_args \ --enable-unstable \ --cbmc-args --object-bits 12 elif [[ "$run_command" == "list" ]]; then echo "Running Kani list command..." - "$kani_path" list -Z list -Z function-contracts -Z mem-predicates ./library --std > $path/kani_list.txt + "$kani_path" list -Z list -Z function-contracts -Z mem-predicates -Z float-lib ./library --std > $path/kani_list.txt fi } main - From 2338dadbde79a640da09e87d5349273959f0b4b0 Mon Sep 17 00:00:00 2001 From: Yifei Wang <40480373+xsxszab@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:17:24 -0800 Subject: [PATCH 13/13] Refactor Contracts and Harnesses for `<*mut T>::add`, `sub` and `offset` (#203) **Summary** This PR synchronizes updates from PR #166 and applies them to `mut` function contracts and proof for contracts. --- library/core/src/ptr/mut_ptr.rs | 264 ++++++++++++++++++-------------- 1 file changed, 146 insertions(+), 118 deletions(-) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 5dfc12220b215..2bfa76a29ab05 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -405,10 +405,11 @@ impl *mut T { // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned. // These conditions are not verified as part of the preconditions. #[requires( - // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize` - count.checked_mul(core::mem::size_of::() as isize).is_some() && - // Precondition 2: adding the computed offset to `self` does not cause overflow - (self as isize).checked_add((count * core::mem::size_of::() as isize)).is_some() && + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize`. + // Precondition 2: adding the computed offset to `self` does not cause overflow. + // These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani. + count.checked_mul(core::mem::size_of::() as isize) + .map_or(false, |computed_offset| (self as isize).checked_add(computed_offset).is_some()) && // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. // Otherwise, for non-unit types, `self` and `self.wrapping_offset(count)` should point to the same allocated object, // restricting `count` to prevent crossing allocation boundaries. @@ -1016,11 +1017,13 @@ impl *mut T { // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned. // These conditions are not verified as part of the preconditions. #[requires( - // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize` - count.checked_mul(core::mem::size_of::()).is_some() && - count * core::mem::size_of::() <= isize::MAX as usize && - // Precondition 2: adding the computed offset to `self` does not cause overflow - (self as isize).checked_add((count * core::mem::size_of::()) as isize).is_some() && + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize`. + // Precondition 2: adding the computed offset to `self` does not cause overflow. + // These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani. + count.checked_mul(core::mem::size_of::()) + .map_or(false, |computed_offset| { + computed_offset <= isize::MAX as usize && (self as isize).checked_add(computed_offset as isize).is_some() + }) && // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. // Otherwise, for non-unit types, `self` and `self.wrapping_add(count)` should point to the same allocated object, // restricting `count` to prevent crossing allocation boundaries. @@ -1140,11 +1143,13 @@ impl *mut T { // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned. // These conditions are not verified as part of the preconditions. #[requires( - // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize` - count.checked_mul(core::mem::size_of::()).is_some() && - count * core::mem::size_of::() <= isize::MAX as usize && - // Precondition 2: subtracting the computed offset from `self` does not cause overflow - (self as isize).checked_sub((count * core::mem::size_of::()) as isize).is_some() && + // Precondition 1: the computed offset `count * size_of::()` does not overflow `isize`. + // Precondition 2: substracting the computed offset from `self` does not cause overflow. + // These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani. + count.checked_mul(core::mem::size_of::()) + .map_or(false, |computed_offset| { + computed_offset <= isize::MAX as usize && (self as isize).checked_sub(computed_offset as isize).is_some() + }) && // Precondition 3: If `T` is a unit type (`size_of::() == 0`), this check is unnecessary as it has no allocated memory. // Otherwise, for non-unit types, `self` and `self.wrapping_sub(count)` should point to the same allocated object, // restricting `count` to prevent crossing allocation boundaries. @@ -2173,120 +2178,143 @@ impl PartialOrd for *mut T { mod verify { use crate::kani; - /// This macro generates proofs for contracts on `add`, `sub`, and `offset` - /// operations for pointers to integer, composite, and unit types. - /// - `$type`: Specifies the pointee type. - /// - `$proof_name`: Specifies the name of the generated proof for contract. - macro_rules! generate_mut_arithmetic_harness { - ($type:ty, $proof_name:ident, add) => { - #[kani::proof_for_contract(<*mut $type>::add)] + /// This macro generates a single verification harness for the `offset`, `add`, or `sub` + /// pointer operations, supporting integer, composite, or unit types. + /// - `$ty`: The type of the slice's elements (e.g., `i32`, `u32`, tuples). + /// - `$fn_name`: The name of the function being checked (`add`, `sub`, or `offset`). + /// - `$proof_name`: The name assigned to the generated proof for the contract. + /// - `$count_ty:ty`: The type of the input variable passed to the method being invoked. + /// + /// Note: This macro is intended for internal use only and should be invoked exclusively + /// by the `generate_arithmetic_harnesses` macro. Its purpose is to reduce code duplication, + /// and it is not meant to be used directly elsewhere in the codebase. + macro_rules! generate_single_arithmetic_harness { + ($ty:ty, $proof_name:ident, $fn_name:ident, $count_ty:ty) => { + #[kani::proof_for_contract(<*mut $ty>::$fn_name)] pub fn $proof_name() { // 200 bytes are large enough to cover all pointee types used for testing const BUF_SIZE: usize = 200; let mut generator = kani::PointerGenerator::::new(); - let test_ptr: *mut $type = generator.any_in_bounds().ptr; - let count: usize = kani::any(); + let test_ptr: *mut $ty = generator.any_in_bounds().ptr; + let count: $count_ty = kani::any(); unsafe { - test_ptr.add(count); + test_ptr.$fn_name(count); } } }; - ($type:ty, $proof_name:ident, sub) => { - #[kani::proof_for_contract(<*mut $type>::sub)] - pub fn $proof_name() { - // 200 bytes are large enough to cover all pointee types used for testing - const BUF_SIZE: usize = 200; - let mut generator = kani::PointerGenerator::::new(); - let test_ptr: *mut $type = generator.any_in_bounds().ptr; - let count: usize = kani::any(); - unsafe { - test_ptr.sub(count); - } - } - }; - ($type:ty, $proof_name:ident, offset) => { - #[kani::proof_for_contract(<*mut $type>::offset)] - pub fn $proof_name() { - // 200 bytes are large enough to cover all pointee types used for testing - const BUF_SIZE: usize = 200; - let mut generator = kani::PointerGenerator::::new(); - let test_ptr: *mut $type = generator.any_in_bounds().ptr; - let count: isize = kani::any(); - unsafe { - test_ptr.offset(count); - } - } + } + + /// This macro generates verification harnesses for the `offset`, `add`, and `sub` + /// pointer operations, supporting integer, composite, and unit types. + /// - `$ty`: The pointee type (e.g., i32, u32, tuples). + /// - `$offset_fn_name`: The name for the `offset` proof for contract. + /// - `$add_fn_name`: The name for the `add` proof for contract. + /// - `$sub_fn_name`: The name for the `sub` proof for contract. + macro_rules! generate_arithmetic_harnesses { + ($ty:ty, $add_fn_name:ident, $sub_fn_name:ident, $offset_fn_name:ident) => { + generate_single_arithmetic_harness!($ty, $add_fn_name, add, usize); + generate_single_arithmetic_harness!($ty, $sub_fn_name, sub, usize); + generate_single_arithmetic_harness!($ty, $offset_fn_name, offset, isize); }; } - // <*mut T>:: add() integer types verification - generate_mut_arithmetic_harness!(i8, check_mut_add_i8, add); - generate_mut_arithmetic_harness!(i16, check_mut_add_i16, add); - generate_mut_arithmetic_harness!(i32, check_mut_add_i32, add); - generate_mut_arithmetic_harness!(i64, check_mut_add_i64, add); - generate_mut_arithmetic_harness!(i128, check_mut_add_i128, add); - generate_mut_arithmetic_harness!(isize, check_mut_add_isize, add); - // Due to a bug of kani this test case is malfunctioning for now. + // Generate harnesses for unit type (add, sub, offset) + generate_arithmetic_harnesses!( + (), + check_mut_add_unit, + check_mut_sub_unit, + check_mut_offset_unit + ); + + // Generate harnesses for integer types (add, sub, offset) + generate_arithmetic_harnesses!(i8, check_mut_add_i8, check_mut_sub_i8, check_mut_offset_i8); + generate_arithmetic_harnesses!( + i16, + check_mut_add_i16, + check_mut_sub_i16, + check_mut_offset_i16 + ); + generate_arithmetic_harnesses!( + i32, + check_mut_add_i32, + check_mut_sub_i32, + check_mut_offset_i32 + ); + generate_arithmetic_harnesses!( + i64, + check_mut_add_i64, + check_mut_sub_i64, + check_mut_offset_i64 + ); + generate_arithmetic_harnesses!( + i128, + check_mut_add_i128, + check_mut_sub_i128, + check_mut_offset_i128 + ); + generate_arithmetic_harnesses!( + isize, + check_mut_add_isize, + check_mut_sub_isize, + check_mut_offset_isize + ); + // Due to a bug of kani the test `check_mut_add_u8` is malfunctioning for now. // Tracking issue: https://github.com/model-checking/kani/issues/3743 - // generate_mut_arithmetic_harness!(u8, check_mut_add_u8, add); - generate_mut_arithmetic_harness!(u16, check_mut_add_u16, add); - generate_mut_arithmetic_harness!(u32, check_mut_add_u32, add); - generate_mut_arithmetic_harness!(u64, check_mut_add_u64, add); - generate_mut_arithmetic_harness!(u128, check_mut_add_u128, add); - generate_mut_arithmetic_harness!(usize, check_mut_add_usize, add); - - // <*mut T>:: add() unit type verification - generate_mut_arithmetic_harness!((), check_mut_add_unit, add); - - // <*mut T>:: add() composite types verification - generate_mut_arithmetic_harness!((i8, i8), check_mut_add_tuple_1, add); - generate_mut_arithmetic_harness!((f64, bool), check_mut_add_tuple_2, add); - generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_add_tuple_3, add); - generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_add_tuple_4, add); - - // <*mut T>:: sub() integer types verification - generate_mut_arithmetic_harness!(i8, check_mut_sub_i8, sub); - generate_mut_arithmetic_harness!(i16, check_mut_sub_i16, sub); - generate_mut_arithmetic_harness!(i32, check_mut_sub_i32, sub); - generate_mut_arithmetic_harness!(i64, check_mut_sub_i64, sub); - generate_mut_arithmetic_harness!(i128, check_mut_sub_i128, sub); - generate_mut_arithmetic_harness!(isize, check_mut_sub_isize, sub); - generate_mut_arithmetic_harness!(u8, check_mut_sub_u8, sub); - generate_mut_arithmetic_harness!(u16, check_mut_sub_u16, sub); - generate_mut_arithmetic_harness!(u32, check_mut_sub_u32, sub); - generate_mut_arithmetic_harness!(u64, check_mut_sub_u64, sub); - generate_mut_arithmetic_harness!(u128, check_mut_sub_u128, sub); - generate_mut_arithmetic_harness!(usize, check_mut_sub_usize, sub); - - // <*mut T>:: sub() unit type verification - generate_mut_arithmetic_harness!((), check_mut_sub_unit, sub); - - // <*mut T>:: sub() composite types verification - generate_mut_arithmetic_harness!((i8, i8), check_mut_sub_tuple_1, sub); - generate_mut_arithmetic_harness!((f64, bool), check_mut_sub_tuple_2, sub); - generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_sub_tuple_3, sub); - generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_sub_tuple_4, sub); - - // fn <*mut T>::offset() integer types verification - generate_mut_arithmetic_harness!(i8, check_mut_offset_i8, offset); - generate_mut_arithmetic_harness!(i16, check_mut_offset_i16, offset); - generate_mut_arithmetic_harness!(i32, check_mut_offset_i32, offset); - generate_mut_arithmetic_harness!(i64, check_mut_offset_i64, offset); - generate_mut_arithmetic_harness!(i128, check_mut_offset_i128, offset); - generate_mut_arithmetic_harness!(isize, check_mut_offset_isize, offset); - generate_mut_arithmetic_harness!(u8, check_mut_offset_u8, offset); - generate_mut_arithmetic_harness!(u16, check_mut_offset_u16, offset); - generate_mut_arithmetic_harness!(u32, check_mut_offset_u32, offset); - generate_mut_arithmetic_harness!(u64, check_mut_offset_u64, offset); - generate_mut_arithmetic_harness!(u128, check_mut_offset_u128, offset); - generate_mut_arithmetic_harness!(usize, check_mut_offset_usize, offset); - - // fn <*mut T>::offset() unit type verification - generate_mut_arithmetic_harness!((), check_mut_offset_unit, offset); - - // fn <*mut T>::offset() composite type verification - generate_mut_arithmetic_harness!((i8, i8), check_mut_offset_tuple_1, offset); - generate_mut_arithmetic_harness!((f64, bool), check_mut_offset_tuple_2, offset); - generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_offset_tuple_3, offset); - generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_offset_tuple_4, offset); + // generate_arithmetic_harnesses!(u8, check_mut_add_u8, check_mut_sub_u8, check_mut_offset_u8); + generate_arithmetic_harnesses!( + u16, + check_mut_add_u16, + check_mut_sub_u16, + check_mut_offset_u16 + ); + generate_arithmetic_harnesses!( + u32, + check_mut_add_u32, + check_mut_sub_u32, + check_mut_offset_u32 + ); + generate_arithmetic_harnesses!( + u64, + check_mut_add_u64, + check_mut_sub_u64, + check_mut_offset_u64 + ); + generate_arithmetic_harnesses!( + u128, + check_mut_add_u128, + check_mut_sub_u128, + check_mut_offset_u128 + ); + generate_arithmetic_harnesses!( + usize, + check_mut_add_usize, + check_mut_sub_usize, + check_mut_offset_usize + ); + + // Generte harnesses for composite types (add, sub, offset) + generate_arithmetic_harnesses!( + (i8, i8), + check_mut_add_tuple_1, + check_mut_sub_tuple_1, + check_mut_offset_tuple_1 + ); + generate_arithmetic_harnesses!( + (f64, bool), + check_mut_add_tuple_2, + check_mut_sub_tuple_2, + check_mut_offset_tuple_2 + ); + generate_arithmetic_harnesses!( + (i32, f64, bool), + check_mut_add_tuple_3, + check_mut_sub_tuple_3, + check_mut_offset_tuple_3 + ); + generate_arithmetic_harnesses!( + (i8, u16, i32, u64, isize), + check_mut_add_tuple_4, + check_mut_sub_tuple_4, + check_mut_offset_tuple_4 + ); }