diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
commit | c23a457e72abe608715ac76f076f47dc42af07a5 (patch) | |
tree | 2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /library/core | |
parent | Releasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip |
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core')
68 files changed, 1710 insertions, 457 deletions
diff --git a/library/core/primitive_docs/box_into_raw.md b/library/core/primitive_docs/box_into_raw.md deleted file mode 100644 index 9dd0344c7..000000000 --- a/library/core/primitive_docs/box_into_raw.md +++ /dev/null @@ -1 +0,0 @@ -../std/boxed/struct.Box.html#method.into_raw diff --git a/library/core/primitive_docs/fs_file.md b/library/core/primitive_docs/fs_file.md deleted file mode 100644 index 4023e340a..000000000 --- a/library/core/primitive_docs/fs_file.md +++ /dev/null @@ -1 +0,0 @@ -../std/fs/struct.File.html diff --git a/library/core/primitive_docs/io_bufread.md b/library/core/primitive_docs/io_bufread.md deleted file mode 100644 index 7beda2cd3..000000000 --- a/library/core/primitive_docs/io_bufread.md +++ /dev/null @@ -1 +0,0 @@ -../std/io/trait.BufRead.html diff --git a/library/core/primitive_docs/io_read.md b/library/core/primitive_docs/io_read.md deleted file mode 100644 index b7ecf5e27..000000000 --- a/library/core/primitive_docs/io_read.md +++ /dev/null @@ -1 +0,0 @@ -../std/io/trait.Read.html diff --git a/library/core/primitive_docs/io_seek.md b/library/core/primitive_docs/io_seek.md deleted file mode 100644 index db0274d29..000000000 --- a/library/core/primitive_docs/io_seek.md +++ /dev/null @@ -1 +0,0 @@ -../std/io/trait.Seek.html diff --git a/library/core/primitive_docs/io_write.md b/library/core/primitive_docs/io_write.md deleted file mode 100644 index 92a3b88a7..000000000 --- a/library/core/primitive_docs/io_write.md +++ /dev/null @@ -1 +0,0 @@ -../std/io/trait.Write.html diff --git a/library/core/primitive_docs/net_tosocketaddrs.md b/library/core/primitive_docs/net_tosocketaddrs.md deleted file mode 100644 index 4daa10ddb..000000000 --- a/library/core/primitive_docs/net_tosocketaddrs.md +++ /dev/null @@ -1 +0,0 @@ -../std/net/trait.ToSocketAddrs.html diff --git a/library/core/primitive_docs/process_exit.md b/library/core/primitive_docs/process_exit.md deleted file mode 100644 index cae34d12d..000000000 --- a/library/core/primitive_docs/process_exit.md +++ /dev/null @@ -1 +0,0 @@ -../std/process/fn.exit.html diff --git a/library/core/primitive_docs/string_string.md b/library/core/primitive_docs/string_string.md deleted file mode 100644 index 303dc07b1..000000000 --- a/library/core/primitive_docs/string_string.md +++ /dev/null @@ -1 +0,0 @@ -../std/string/struct.String.html diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 5378b210e..cc872a534 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -3,7 +3,7 @@ //! suggestions from rustc if you get anything slightly wrong in here, and overall //! helps with clarity as we're also referring to `char` intentionally in here. -use crate::fmt; +use crate::fmt::{self, Write}; use crate::mem::transmute; /// One of the 128 Unicode characters from U+0000 through U+007F, @@ -54,7 +54,7 @@ use crate::mem::transmute; /// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf /// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf /// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[unstable(feature = "ascii_char", issue = "110998")] #[repr(u8)] pub enum AsciiChar { @@ -563,3 +563,40 @@ impl fmt::Display for AsciiChar { <str as fmt::Display>::fmt(self.as_str(), f) } } + +#[unstable(feature = "ascii_char", issue = "110998")] +impl fmt::Debug for AsciiChar { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + #[inline] + fn backslash(a: AsciiChar) -> ([AsciiChar; 4], u8) { + ([AsciiChar::ReverseSolidus, a, AsciiChar::Null, AsciiChar::Null], 2) + } + + let (buf, len) = match self { + AsciiChar::Null => backslash(AsciiChar::Digit0), + AsciiChar::CharacterTabulation => backslash(AsciiChar::SmallT), + AsciiChar::CarriageReturn => backslash(AsciiChar::SmallR), + AsciiChar::LineFeed => backslash(AsciiChar::SmallN), + AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus), + AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe), + _ => { + let byte = self.to_u8(); + if !byte.is_ascii_control() { + ([*self, AsciiChar::Null, AsciiChar::Null, AsciiChar::Null], 1) + } else { + const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap(); + + let hi = HEX_DIGITS[usize::from(byte >> 4)]; + let lo = HEX_DIGITS[usize::from(byte & 0xf)]; + ([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4) + } + } + }; + + f.write_char('\'')?; + for byte in &buf[..len as usize] { + f.write_str(byte.as_str())?; + } + f.write_char('\'') + } +} diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index bf4c682d3..3b4d99221 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -237,6 +237,7 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; +use crate::intrinsics::is_nonoverlapping; use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn}; @@ -415,6 +416,12 @@ impl<T> Cell<T> { /// Swaps the values of two `Cell`s. /// Difference with `std::mem::swap` is that this function doesn't require `&mut` reference. /// + /// # Panics + /// + /// This function will panic if `self` and `other` are different `Cell`s that partially overlap. + /// (Using just standard library methods, it is impossible to create such partially overlapping `Cell`s. + /// However, unsafe code is allowed to e.g. create two `&Cell<[i32; 2]>` that partially overlap.) + /// /// # Examples /// /// ``` @@ -430,14 +437,20 @@ impl<T> Cell<T> { #[stable(feature = "move_cell", since = "1.17.0")] pub fn swap(&self, other: &Self) { if ptr::eq(self, other) { + // Swapping wouldn't change anything. return; } + if !is_nonoverlapping(self, other, 1) { + // See <https://github.com/rust-lang/rust/issues/80778> for why we need to stop here. + panic!("`Cell::swap` on overlapping non-identical `Cell`s"); + } // SAFETY: This can be risky if called from separate threads, but `Cell` // is `!Sync` so this won't happen. This also won't invalidate any // pointers since `Cell` makes sure nothing else will be pointing into - // either of these `Cell`s. + // either of these `Cell`s. We also excluded shenanigans like partially overlapping `Cell`s, + // so `swap` will just properly copy two full values of type `T` back and forth. unsafe { - ptr::swap(self.value.get(), other.value.get()); + mem::swap(&mut *self.value.get(), &mut *other.value.get()); } } @@ -543,6 +556,7 @@ impl<T: ?Sized> Cell<T> { #[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_never_returns_null_ptr)] pub const fn as_ptr(&self) -> *mut T { self.value.get() } @@ -740,6 +754,22 @@ impl Display for BorrowMutError { } } +// This ensures the panicking code is outlined from `borrow_mut` for `RefCell`. +#[inline(never)] +#[track_caller] +#[cold] +fn panic_already_borrowed(err: BorrowMutError) -> ! { + panic!("already borrowed: {:?}", err) +} + +// This ensures the panicking code is outlined from `borrow` for `RefCell`. +#[inline(never)] +#[track_caller] +#[cold] +fn panic_already_mutably_borrowed(err: BorrowError) -> ! { + panic!("already mutably borrowed: {:?}", err) +} + // Positive values represent the number of `Ref` active. Negative values // represent the number of `RefMut` active. Multiple `RefMut`s can only be // active at a time if they refer to distinct, nonoverlapping components of a @@ -921,7 +951,10 @@ impl<T: ?Sized> RefCell<T> { #[inline] #[track_caller] pub fn borrow(&self) -> Ref<'_, T> { - self.try_borrow().expect("already mutably borrowed") + match self.try_borrow() { + Ok(b) => b, + Err(err) => panic_already_mutably_borrowed(err), + } } /// Immutably borrows the wrapped value, returning an error if the value is currently mutably @@ -1014,7 +1047,10 @@ impl<T: ?Sized> RefCell<T> { #[inline] #[track_caller] pub fn borrow_mut(&self) -> RefMut<'_, T> { - self.try_borrow_mut().expect("already borrowed") + match self.try_borrow_mut() { + Ok(b) => b, + Err(err) => panic_already_borrowed(err), + } } /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed. @@ -1076,6 +1112,7 @@ impl<T: ?Sized> RefCell<T> { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub fn as_ptr(&self) -> *mut T { self.value.get() } @@ -1893,8 +1930,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> { /// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the /// same memory layout, the following is not allowed and undefined behavior: /// -#[cfg_attr(bootstrap, doc = "```rust,no_run")] -#[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")] +/// ```rust,compile_fail /// # use std::cell::UnsafeCell; /// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T { /// let t = ptr as *const UnsafeCell<T> as *mut T; @@ -2071,6 +2107,7 @@ impl<T: ?Sized> UnsafeCell<T> { #[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_never_returns_null_ptr)] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell<T>` to `T` because of // #[repr(transparent)]. This exploits std's special status, there is @@ -2131,6 +2168,7 @@ impl<T: ?Sized> UnsafeCell<T> { #[inline(always)] #[stable(feature = "unsafe_cell_raw_get", since = "1.56.0")] #[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")] + #[rustc_diagnostic_item = "unsafe_cell_raw_get"] pub const fn raw_get(this: *const Self) -> *mut T { // We can just cast the pointer from `UnsafeCell<T>` to `T` because of // #[repr(transparent)]. This exploits std's special status, there is @@ -2213,6 +2251,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> { /// 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_never_returns_null_ptr)] pub const fn get(&self) -> *mut T { self.value.get() } diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index b84e4b35b..453de9754 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -87,20 +87,54 @@ impl From<char> for u128 { } } -/// Map `char` with code point in U+0000..=U+00FF to byte in 0x00..=0xFF with same value, failing -/// if the code point is greater than U+00FF. +/// Maps a `char` with code point in U+0000..=U+00FF to a byte in 0x00..=0xFF with same value, +/// failing if the code point is greater than U+00FF. /// /// See [`impl From<u8> for char`](char#impl-From<u8>-for-char) for details on the encoding. #[stable(feature = "u8_from_char", since = "1.59.0")] impl TryFrom<char> for u8 { type Error = TryFromCharError; + /// Tries to convert a [`char`] into a [`u8`]. + /// + /// # Examples + /// + /// ``` + /// let a = 'ÿ'; // U+00FF + /// let b = 'Ā'; // U+0100 + /// assert_eq!(u8::try_from(a), Ok(0xFF_u8)); + /// assert!(u8::try_from(b).is_err()); + /// ``` #[inline] fn try_from(c: char) -> Result<u8, Self::Error> { u8::try_from(u32::from(c)).map_err(|_| TryFromCharError(())) } } +/// Maps a `char` with code point in U+0000..=U+FFFF to a `u16` in 0x0000..=0xFFFF with same value, +/// failing if the code point is greater than U+FFFF. +/// +/// This corresponds to the UCS-2 encoding, as specified in ISO/IEC 10646:2003. +#[stable(feature = "u16_from_char", since = "1.74.0")] +impl TryFrom<char> for u16 { + type Error = TryFromCharError; + + /// Tries to convert a [`char`] into a [`u16`]. + /// + /// # Examples + /// + /// ``` + /// let trans_rights = '⚧'; // U+26A7 + /// let ninjas = '🥷'; // U+1F977 + /// assert_eq!(u16::try_from(trans_rights), Ok(0x26A7_u16)); + /// assert!(u16::try_from(ninjas).is_err()); + /// ``` + #[inline] + fn try_from(c: char) -> Result<u16, Self::Error> { + u16::try_from(u32::from(c)).map_err(|_| TryFromCharError(())) + } +} + /// Maps a byte in 0x00..=0xFF to a `char` whose code point has the same value, in U+0000..=U+00FF. /// /// Unicode is designed such that this effectively decodes bytes diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 515b8d20e..4ac956e7b 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -9,8 +9,58 @@ use crate::unicode::{self, conversions}; use super::*; impl char { + /// The lowest valid code point a `char` can have, `'\0'`. + /// + /// Unlike integer types, `char` actually has a gap in the middle, + /// meaning that the range of possible `char`s is smaller than you + /// might expect. Ranges of `char` will automatically hop this gap + /// for you: + /// + /// ``` + /// #![feature(char_min)] + /// let dist = u32::from(char::MAX) - u32::from(char::MIN); + /// let size = (char::MIN..=char::MAX).count() as u32; + /// assert!(size < dist); + /// ``` + /// + /// Despite this gap, the `MIN` and [`MAX`] values can be used as bounds for + /// all `char` values. + /// + /// [`MAX`]: char::MAX + /// + /// # Examples + /// + /// ``` + /// #![feature(char_min)] + /// # fn something_which_returns_char() -> char { 'a' } + /// let c: char = something_which_returns_char(); + /// assert!(char::MIN <= c); + /// + /// let value_at_min = u32::from(char::MIN); + /// assert_eq!(char::from_u32(value_at_min), Some('\0')); + /// ``` + #[unstable(feature = "char_min", issue = "114298")] + pub const MIN: char = '\0'; + /// The highest valid code point a `char` can have, `'\u{10FFFF}'`. /// + /// Unlike integer types, `char` actually has a gap in the middle, + /// meaning that the range of possible `char`s is smaller than you + /// might expect. Ranges of `char` will automatically hop this gap + /// for you: + /// + /// ``` + /// #![feature(char_min)] + /// let dist = u32::from(char::MAX) - u32::from(char::MIN); + /// let size = (char::MIN..=char::MAX).count() as u32; + /// assert!(size < dist); + /// ``` + /// + /// Despite this gap, the [`MIN`] and `MAX` values can be used as bounds for + /// all `char` values. + /// + /// [`MIN`]: char::MIN + /// /// # Examples /// /// ``` @@ -18,7 +68,7 @@ impl char { /// let c: char = something_which_returns_char(); /// assert!(c <= char::MAX); /// - /// let value_at_max = char::MAX as u32; + /// let value_at_max = u32::from(char::MAX); /// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}')); /// assert_eq!(char::from_u32(value_at_max + 1), None); /// ``` diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3c127efb3..360806167 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -63,6 +63,11 @@ use self::Ordering::*; /// (transitive) impls are not forced to exist, but these requirements apply /// whenever they do exist. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d on structs, two @@ -250,6 +255,11 @@ pub macro PartialEq($item:item) { /// This property cannot be checked by the compiler, and therefore `Eq` implies /// [`PartialEq`], and has no extra methods. /// +/// Violating this property is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has @@ -281,15 +291,16 @@ pub macro PartialEq($item:item) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Eq"] pub trait Eq: PartialEq<Self> { - // this method is used solely by #[deriving] to assert - // that every component of a type implements #[deriving] - // itself, the current deriving infrastructure means doing this + // this method is used solely by #[derive(Eq)] to assert + // that every component of a type implements `Eq` + // itself. The current deriving infrastructure means doing this // assertion without using a method on this trait is nearly // impossible. // // This should never be implemented by hand. #[doc(hidden)] - #[no_coverage] // rust-lang/rust#84605 + #[cfg_attr(bootstrap, no_coverage)] // rust-lang/rust#84605 + #[cfg_attr(not(bootstrap), coverage(off))] // #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn assert_receiver_is_total_eq(&self) {} @@ -298,7 +309,9 @@ pub trait Eq: PartialEq<Self> { /// Derive macro generating an impl of the trait [`Eq`]. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match, no_coverage)] +#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)] +#[cfg_attr(bootstrap, allow_internal_unstable(no_coverage))] +#[cfg_attr(not(bootstrap), allow_internal_unstable(coverage_attribute))] pub macro Eq($item:item) { /* compiler built-in */ } @@ -656,6 +669,11 @@ impl<T: Clone> Clone for Reverse<T> { /// It's easy to accidentally make `cmp` and `partial_cmp` disagree by /// deriving some of the traits and manually implementing others. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Corollaries /// /// From the above and the requirements of `PartialOrd`, it follows that `<` defines a strict total order. @@ -889,6 +907,11 @@ pub macro Ord($item:item) { /// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T: /// PartialOrd<V>`. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Corollaries /// /// The following corollaries follow from the above requirements: @@ -1266,6 +1289,91 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) } +/// Compares and sorts two values, returning minimum and maximum. +/// +/// Returns `[v1, v2]` if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_minmax)] +/// use std::cmp; +/// +/// assert_eq!(cmp::minmax(1, 2), [1, 2]); +/// assert_eq!(cmp::minmax(2, 2), [2, 2]); +/// +/// // You can destructure the result using array patterns +/// let [min, max] = cmp::minmax(42, 17); +/// assert_eq!(min, 17); +/// assert_eq!(max, 42); +/// ``` +#[inline] +#[must_use] +#[unstable(feature = "cmp_minmax", issue = "115939")] +pub fn minmax<T>(v1: T, v2: T) -> [T; 2] +where + T: Ord, +{ + if v1 <= v2 { [v1, v2] } else { [v2, v1] } +} + +/// Returns minimum and maximum values with respect to the specified comparison function. +/// +/// Returns `[v1, v2]` if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_minmax)] +/// use std::cmp; +/// +/// assert_eq!(cmp::minmax_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [1, -2]); +/// assert_eq!(cmp::minmax_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [-2, 2]); +/// +/// // You can destructure the result using array patterns +/// let [min, max] = cmp::minmax_by(-42, 17, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// assert_eq!(min, 17); +/// assert_eq!(max, -42); +/// ``` +#[inline] +#[must_use] +#[unstable(feature = "cmp_minmax", issue = "115939")] +pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2] +where + F: FnOnce(&T, &T) -> Ordering, +{ + if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] } +} + +/// Returns minimum and maximum values with respect to the specified key function. +/// +/// Returns `[v1, v2]` if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_minmax)] +/// use std::cmp; +/// +/// assert_eq!(cmp::minmax_by_key(-2, 1, |x: &i32| x.abs()), [1, -2]); +/// assert_eq!(cmp::minmax_by_key(-2, 2, |x: &i32| x.abs()), [-2, 2]); +/// +/// // You can destructure the result using array patterns +/// let [min, max] = cmp::minmax_by_key(-42, 17, |x: &i32| x.abs()); +/// assert_eq!(min, 17); +/// assert_eq!(max, -42); +/// ``` +#[inline] +#[must_use] +#[unstable(feature = "cmp_minmax", issue = "115939")] +pub fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2] +where + F: FnMut(&T) -> K, + K: Ord, +{ + minmax_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) +} + // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types mod impls { use crate::cmp::Ordering::{self, Equal, Greater, Less}; diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 56ab63be2..b048b5135 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -142,9 +142,9 @@ impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.2 // RISC-V defines the possibility of a 128-bit address space (RV128). -// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize. +// CHERI proposes 128-bit “capabilities”. Unclear if this would be relevant to usize/isize. // https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf -// https://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf +// https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-951.pdf // Note: integers can only be represented with full precision in a float if // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. diff --git a/library/core/src/error.md b/library/core/src/error.md index 7771b8adc..a5deb71e6 100644 --- a/library/core/src/error.md +++ b/library/core/src/error.md @@ -37,7 +37,7 @@ responsibilities they cover: The panic and error systems are not entirely distinct. Often times errors that are anticipated runtime failures in an API might instead represent bugs to a caller. For these situations the standard library provides APIs for -constructing panics with an `Error` as it's source. +constructing panics with an `Error` as its source. * [`Result::unwrap`] * [`Result::expect`] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 163a65c90..93a6716d7 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -214,6 +214,8 @@ impl CStr { /// * The memory referenced by the returned `CStr` must not be mutated for /// the duration of lifetime `'a`. /// + /// * The nul terminator must be within `isize::MAX` from `ptr` + /// /// > **Note**: This operation is intended to be a 0-cost cast but it is /// > currently implemented with an up-front calculation of the length of /// > the string. This is not guaranteed to always be the case. @@ -259,42 +261,16 @@ impl CStr { #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { // SAFETY: The caller has provided a pointer that points to a valid C - // string with a NUL terminator of size less than `isize::MAX`, whose - // content remain valid and doesn't change for the lifetime of the - // returned `CStr`. - // - // Thus computing the length is fine (a NUL byte exists), the call to - // from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning - // the call to `from_bytes_with_nul_unchecked` is correct. + // string with a NUL terminator less than `isize::MAX` from `ptr`. + let len = unsafe { const_strlen(ptr) }; + + // SAFETY: The caller has provided a valid pointer with length less than + // `isize::MAX`, so `from_raw_parts` is safe. The content remains valid + // and doesn't change for the lifetime of the returned `CStr`. This + // means the call to `from_bytes_with_nul_unchecked` is correct. // // The cast from c_char to u8 is ok because a c_char is always one byte. - unsafe { - 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; - } - - len - } - - // `inline` is necessary for codegen to see strlen. - #[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) } - } - - let len = intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt); - Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1)) - } + unsafe { Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1)) } } /// Creates a C string wrapper from a byte slice with any number of nuls. @@ -511,10 +487,39 @@ 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_never_returns_null_ptr)] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() } + /// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator. + /// + /// > **Note**: This method is currently implemented as a constant-time + /// > cast, but it is planned to alter its definition in the future to + /// > perform the length calculation whenever this method is called. + /// + /// # Examples + /// + /// ``` + /// #![feature(cstr_count_bytes)] + /// + /// use std::ffi::CStr; + /// + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); + /// assert_eq!(cstr.count_bytes(), 3); + /// + /// let cstr = CStr::from_bytes_with_nul(b"\0").unwrap(); + /// assert_eq!(cstr.count_bytes(), 0); + /// ``` + #[inline] + #[must_use] + #[doc(alias("len", "strlen"))] + #[unstable(feature = "cstr_count_bytes", issue = "114441")] + #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] + pub const fn count_bytes(&self) -> usize { + self.inner.len() - 1 + } + /// Returns `true` if `self.to_bytes()` has a length of 0. /// /// # Examples @@ -681,3 +686,37 @@ impl AsRef<CStr> for CStr { self } } + +/// Calculate the length of a nul-terminated string. Defers to C's `strlen` when possible. +/// +/// # Safety +/// +/// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be +/// located within `isize::MAX` from `ptr`. +#[inline] +const unsafe fn const_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; + } + + len + } + + #[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: the two functions always provide equivalent functionality + unsafe { intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) } +} diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index d2c9f9800..922724804 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -40,6 +40,14 @@ impl fmt::Write for PadAdapter<'_, '_> { Ok(()) } + + fn write_char(&mut self, c: char) -> fmt::Result { + if self.state.on_newline { + self.buf.write_str(" ")?; + } + self.state.on_newline = c == '\n'; + self.buf.write_char(c) + } } /// A struct to help with [`fmt::Debug`](Debug) implementations. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 9ce6093f1..fc91d1afc 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -112,9 +112,9 @@ pub trait Write { /// /// # Errors /// - /// This function will return an instance of [`Error`] on error. + /// This function will return an instance of [`std::fmt::Error`][Error] on error. /// - /// The purpose of std::fmt::Error is to abort the formatting operation when the underlying + /// The purpose of that error is to abort the formatting operation when the underlying /// destination encounters some error preventing it from accepting more text; it should /// generally be propagated rather than handled, at least when implementing formatting traits. /// @@ -188,8 +188,28 @@ pub trait Write { /// assert_eq!(&buf, "world"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn write_fmt(mut self: &mut Self, args: Arguments<'_>) -> Result { - write(&mut self, args) + fn write_fmt(&mut self, args: Arguments<'_>) -> Result { + // We use a specialization for `Sized` types to avoid an indirection + // through `&mut self` + trait SpecWriteFmt { + fn spec_write_fmt(self, args: Arguments<'_>) -> Result; + } + + impl<W: Write + ?Sized> SpecWriteFmt for &mut W { + #[inline] + default fn spec_write_fmt(mut self, args: Arguments<'_>) -> Result { + write(&mut self, args) + } + } + + impl<W: Write> SpecWriteFmt for &mut W { + #[inline] + fn spec_write_fmt(self, args: Arguments<'_>) -> Result { + write(self, args) + } + } + + self.spec_write_fmt(args) } } diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 794a57f09..35b757dc1 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -153,6 +153,11 @@ mod sip; /// Thankfully, you won't need to worry about upholding this property when /// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`. /// +/// Violating this property is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Prefix collisions /// /// Implementations of `hash` should ensure that the data they diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 75c104ce2..4bf3da073 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -175,34 +175,27 @@ pub fn spin_loop() { unsafe { crate::arch::x86_64::_mm_pause() }; } - // RISC-V platform spin loop hint implementation + #[cfg(target_arch = "riscv32")] { - // RISC-V RV32 and RV64 share the same PAUSE instruction, but they are located in different - // modules in `core::arch`. - // In this case, here we call `pause` function in each core arch module. - #[cfg(target_arch = "riscv32")] - { - crate::arch::riscv32::pause(); - } - #[cfg(target_arch = "riscv64")] - { - crate::arch::riscv64::pause(); - } + crate::arch::riscv32::pause(); } - #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))] + #[cfg(target_arch = "riscv64")] { - #[cfg(target_arch = "aarch64")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. - unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) }; - } - #[cfg(target_arch = "arm")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on arm targets - // with support for the v6 feature. - unsafe { crate::arch::arm::__yield() }; - } + crate::arch::riscv64::pause(); + } + + #[cfg(target_arch = "aarch64")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. + unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) }; + } + + #[cfg(all(target_arch = "arm", target_feature = "v6"))] + { + // SAFETY: the `cfg` attr ensures that we only execute this on arm targets + // with support for the v6 feature. + unsafe { crate::arch::arm::__yield() }; } } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 676d4f2f3..4c76662ac 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1130,7 +1130,10 @@ extern "rust-intrinsic" { /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly /// unsafe**. `transmute` should be the absolute last resort. /// - /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub]. + /// 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 [`invalid`][crate::ptr::invalid], + /// 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.) @@ -2399,7 +2402,6 @@ extern "rust-intrinsic" { /// that differs. That allows optimizations that can read in large chunks. /// /// [valid]: crate::ptr#safety - #[cfg(not(bootstrap))] #[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; @@ -2568,7 +2570,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) - let size = mem::size_of::<T>() .checked_mul(count) .expect("is_nonoverlapping: `size_of::<T>() * count` overflows a usize"); - let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_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 @@ -2705,9 +2707,13 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. +/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes, and must remain valid even +/// when `dst` is written for `count * size_of::<T>()` 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::<T>()` bytes. +/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even +/// when `src` is read for `count * size_of::<T>()` bytes. /// /// * Both `src` and `dst` must be properly aligned. /// @@ -2844,18 +2850,3 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { write_bytes(dst, val, count) } } - -/// Backfill for bootstrap -#[cfg(bootstrap)] -pub unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32 { - extern "C" { - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> crate::ffi::c_int; - } - - if bytes != 0 { - // SAFETY: Since bytes is non-zero, the caller has met `memcmp`'s requirements. - unsafe { memcmp(left, right, bytes).into() } - } else { - 0 - } -} diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index ef0a2fd4e..cab195dad 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -12,9 +12,10 @@ //! //! Typical usage will look like this: //! -//! ```rust +#![cfg_attr(bootstrap, doc = "```rust,ignore")] +#![cfg_attr(not(bootstrap), doc = "```rust")] //! #![feature(core_intrinsics, custom_mir)] -#![cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")] +//! #![allow(internal_features)] //! //! use core::intrinsics::mir::*; //! @@ -62,9 +63,10 @@ //! //! # Examples //! -//! ```rust +#![cfg_attr(bootstrap, doc = "```rust,ignore")] +#![cfg_attr(not(bootstrap), doc = "```rust")] //! #![feature(core_intrinsics, custom_mir)] -#![cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")] +//! #![allow(internal_features)] //! //! use core::intrinsics::mir::*; //! @@ -317,8 +319,9 @@ define!( /// /// # Examples /// - /// ```rust - #[cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")] + #[cfg_attr(bootstrap, doc = "```rust,ignore")] + #[cfg_attr(not(bootstrap), doc = "```rust")] + /// #![allow(internal_features)] /// #![feature(custom_mir, core_intrinsics)] /// /// use core::intrinsics::mir::*; @@ -361,6 +364,11 @@ define!( #[doc(hidden)] fn __internal_make_place<T>(place: T) -> *mut T ); +define!( + "mir_debuginfo", + #[doc(hidden)] + fn __debuginfo<T>(name: &'static str, s: T) +); /// Macro for generating custom MIR. /// @@ -371,6 +379,7 @@ pub macro mir { ( $(type RET = $ret_ty:ty ;)? $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)* + $(debug $dbg_name:ident => $dbg_data:expr ;)* { $($entry:tt)* @@ -394,26 +403,32 @@ pub macro mir { $( let $local_decl $(: $local_decl_ty)? ; )* - ::core::intrinsics::mir::__internal_extract_let!($($entry)*); $( ::core::intrinsics::mir::__internal_extract_let!($($block)*); )* { - // Finally, the contents of the basic blocks - ::core::intrinsics::mir::__internal_remove_let!({ - {} - { $($entry)* } - }); + // Now debuginfo $( + __debuginfo(stringify!($dbg_name), $dbg_data); + )* + + { + // Finally, the contents of the basic blocks ::core::intrinsics::mir::__internal_remove_let!({ {} - { $($block)* } + { $($entry)* } }); - )* + $( + ::core::intrinsics::mir::__internal_remove_let!({ + {} + { $($block)* } + }); + )* - RET + RET + } } } }} diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index ce18bffe7..c1d8cc4ff 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -1,5 +1,7 @@ use crate::cmp; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::iter::{ + adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess, +}; use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; @@ -98,26 +100,18 @@ where } } - impl_fold_via_try_fold! { fold -> try_fold } - #[inline] - fn for_each<F: FnMut(Self::Item)>(mut self, f: F) { - // The default implementation would use a unit accumulator, so we can - // avoid a stateful closure by folding over the remaining number - // of items we wish to return instead. - fn check<'a, Item>( - mut action: impl FnMut(Item) + 'a, - ) -> impl FnMut(usize, Item) -> Option<usize> + 'a { - move |more, x| { - action(x); - more.checked_sub(1) - } - } + fn fold<B, F>(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + Self::spec_fold(self, init, f) + } - let remaining = self.n; - if remaining > 0 { - self.iter.try_fold(remaining - 1, check(f)); - } + #[inline] + fn for_each<F: FnMut(Self::Item)>(self, f: F) { + Self::spec_for_each(self, f) } #[inline] @@ -249,3 +243,72 @@ impl<I> FusedIterator for Take<I> where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<I: TrustedLen> TrustedLen for Take<I> {} + +trait SpecTake: Iterator { + fn spec_fold<B, F>(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B; + + fn spec_for_each<F: FnMut(Self::Item)>(self, f: F); +} + +impl<I: Iterator> SpecTake for Take<I> { + #[inline] + default fn spec_fold<B, F>(mut self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + use crate::ops::NeverShortCircuit; + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + default fn spec_for_each<F: FnMut(Self::Item)>(mut self, f: F) { + // The default implementation would use a unit accumulator, so we can + // avoid a stateful closure by folding over the remaining number + // of items we wish to return instead. + fn check<'a, Item>( + mut action: impl FnMut(Item) + 'a, + ) -> impl FnMut(usize, Item) -> Option<usize> + 'a { + move |more, x| { + action(x); + more.checked_sub(1) + } + } + + let remaining = self.n; + if remaining > 0 { + self.iter.try_fold(remaining - 1, check(f)); + } + } +} + +impl<I: Iterator + TrustedRandomAccess> SpecTake for Take<I> { + #[inline] + fn spec_fold<B, F>(mut self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + let mut acc = init; + let end = self.n.min(self.iter.size()); + for i in 0..end { + // SAFETY: i < end <= self.iter.size() and we discard the iterator at the end + let val = unsafe { self.iter.__iterator_get_unchecked(i) }; + acc = f(acc, val); + } + acc + } + + #[inline] + fn spec_for_each<F: FnMut(Self::Item)>(mut self, mut f: F) { + let end = self.n.min(self.iter.size()); + for i in 0..end { + // SAFETY: i < end <= self.iter.size() and we discard the iterator at the end + let val = unsafe { self.iter.__iterator_get_unchecked(i) }; + f(val); + } + } +} diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 462f7170a..0e03d0c2d 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,5 +1,7 @@ +use crate::ascii::Char as AsciiChar; use crate::convert::TryFrom; use crate::mem; +use crate::net::{Ipv4Addr, Ipv6Addr}; use crate::num::NonZeroUsize; use crate::ops::{self, Try}; @@ -14,7 +16,7 @@ macro_rules! unsafe_impl_trusted_step { unsafe impl TrustedStep for $type {} )*}; } -unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; +unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize Ipv4Addr Ipv6Addr]; /// Objects that have a notion of *successor* and *predecessor* operations. /// @@ -484,6 +486,112 @@ 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<usize> { + Step::steps_between(&start.to_u8(), &end.to_u8()) + } + + #[inline] + fn forward_checked(start: AsciiChar, count: usize) -> Option<AsciiChar> { + let end = Step::forward_checked(start.to_u8(), count)?; + AsciiChar::from_u8(end) + } + + #[inline] + fn backward_checked(start: AsciiChar, count: usize) -> Option<AsciiChar> { + let end = Step::backward_checked(start.to_u8(), count)?; + + // SAFETY: Values below that of a valid ASCII character are also valid ASCII + Some(unsafe { AsciiChar::from_u8_unchecked(end) }) + } + + #[inline] + unsafe fn forward_unchecked(start: AsciiChar, count: usize) -> AsciiChar { + // SAFETY: Caller asserts that result is a valid ASCII character, + // and therefore it is a valid u8. + let end = unsafe { Step::forward_unchecked(start.to_u8(), count) }; + + // SAFETY: Caller asserts that result is a valid ASCII character. + unsafe { AsciiChar::from_u8_unchecked(end) } + } + + #[inline] + unsafe fn backward_unchecked(start: AsciiChar, count: usize) -> AsciiChar { + // SAFETY: Caller asserts that result is a valid ASCII character, + // and therefore it is a valid u8. + let end = unsafe { Step::backward_unchecked(start.to_u8(), count) }; + + // SAFETY: Caller asserts that result is a valid ASCII character. + unsafe { AsciiChar::from_u8_unchecked(end) } + } +} + +#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +impl Step for Ipv4Addr { + #[inline] + fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> Option<usize> { + u32::steps_between(&start.to_bits(), &end.to_bits()) + } + + #[inline] + fn forward_checked(start: Ipv4Addr, count: usize) -> Option<Ipv4Addr> { + u32::forward_checked(start.to_bits(), count).map(Ipv4Addr::from_bits) + } + + #[inline] + fn backward_checked(start: Ipv4Addr, count: usize) -> Option<Ipv4Addr> { + u32::backward_checked(start.to_bits(), count).map(Ipv4Addr::from_bits) + } + + #[inline] + unsafe fn forward_unchecked(start: Ipv4Addr, count: usize) -> Ipv4Addr { + // SAFETY: Since u32 and Ipv4Addr are losslessly convertible, + // this is as safe as the u32 version. + Ipv4Addr::from_bits(unsafe { u32::forward_unchecked(start.to_bits(), count) }) + } + + #[inline] + unsafe fn backward_unchecked(start: Ipv4Addr, count: usize) -> Ipv4Addr { + // SAFETY: Since u32 and Ipv4Addr are losslessly convertible, + // this is as safe as the u32 version. + Ipv4Addr::from_bits(unsafe { u32::backward_unchecked(start.to_bits(), count) }) + } +} + +#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +impl Step for Ipv6Addr { + #[inline] + fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> Option<usize> { + u128::steps_between(&start.to_bits(), &end.to_bits()) + } + + #[inline] + fn forward_checked(start: Ipv6Addr, count: usize) -> Option<Ipv6Addr> { + u128::forward_checked(start.to_bits(), count).map(Ipv6Addr::from_bits) + } + + #[inline] + fn backward_checked(start: Ipv6Addr, count: usize) -> Option<Ipv6Addr> { + u128::backward_checked(start.to_bits(), count).map(Ipv6Addr::from_bits) + } + + #[inline] + unsafe fn forward_unchecked(start: Ipv6Addr, count: usize) -> Ipv6Addr { + // SAFETY: Since u128 and Ipv6Addr are losslessly convertible, + // this is as safe as the u128 version. + Ipv6Addr::from_bits(unsafe { u128::forward_unchecked(start.to_bits(), count) }) + } + + #[inline] + unsafe fn backward_unchecked(start: Ipv6Addr, count: usize) -> Ipv6Addr { + // SAFETY: Since u128 and Ipv6Addr are losslessly convertible, + // this is as safe as the u128 version. + Ipv6Addr::from_bits(unsafe { u128::backward_unchecked(start.to_bits(), count) }) + } +} + macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] @@ -723,6 +831,15 @@ impl<A: Step> Iterator for ops::Range<A> { } #[inline] + fn count(self) -> usize { + if self.start < self.end { + Step::steps_between(&self.start, &self.end).expect("count overflowed usize") + } else { + 0 + } + } + + #[inline] fn nth(&mut self, n: usize) -> Option<A> { self.spec_nth(n) } @@ -1120,6 +1237,17 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { } #[inline] + fn count(self) -> usize { + if self.is_empty() { + return 0; + } + + Step::steps_between(&self.start, &self.end) + .and_then(|steps| steps.checked_add(1)) + .expect("count overflowed usize") + } + + #[inline] fn nth(&mut self, n: usize) -> Option<A> { if self.is_empty() { return None; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a2729b374..8b15e8269 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -20,11 +20,19 @@ // FIXME: Fill me in with more detail when the interface settles //! This library is built on the assumption of a few existing symbols: //! -//! * `memcpy`, `memcmp`, `memset`, `strlen` - These are core memory routines which are -//! often generated by LLVM. Additionally, this library can make explicit -//! calls to these functions. Their signatures are the same as found in C. -//! These functions are often provided by the system libc, but can also be -//! provided by the [compiler-builtins crate](https://crates.io/crates/compiler_builtins). +//! * `memcpy`, `memmove`, `memset`, `memcmp`, `bcmp`, `strlen` - These are core memory routines +//! which are generated by Rust codegen backends. Additionally, this library can make explicit +//! calls to `strlen`. Their signatures are the same as found in C, but there are extra +//! assumptions about their semantics: For `memcpy`, `memmove`, `memset`, `memcmp`, and `bcmp`, if +//! the `n` parameter is 0, the function is assumed to not be UB. Furthermore, for `memcpy`, if +//! source and target pointer are equal, the function is assumed to not be UB. +//! (Note that these are [standard assumptions](https://reviews.llvm.org/D86993) among compilers.) +//! These functions are often provided by the system libc, but can also be provided by the +//! [compiler-builtins crate](https://crates.io/crates/compiler_builtins). +//! Note that the library does not guarantee that it will always make these assumptions, so Rust +//! user code directly calling the C functions should follow the C specification! The advice for +//! Rust user code is to call the functions provided by this library instead (such as +//! `ptr::copy`). //! //! * `rust_begin_panic` - This function takes four arguments, a //! `fmt::Arguments`, a `&'static str`, and two `u32`'s. These four arguments @@ -96,12 +104,14 @@ #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] #![warn(multiple_supertrait_upcastable)] -#![cfg_attr(not(bootstrap), allow(internal_features))] +#![allow(internal_features)] // Do not check link redundancy on bootstraping phase -#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))] +#![allow(rustdoc::redundant_explicit_links)] // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(no_coverage))] // rust-lang/rust#84605 +#![cfg_attr(not(bootstrap), feature(coverage_attribute))] // rust-lang/rust#84605 #![feature(char_indices_offset)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] @@ -152,12 +162,10 @@ #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_from_ref)] #![feature(const_slice_index)] -#![feature(const_slice_is_ascii)] #![feature(const_slice_ptr_len)] #![feature(const_slice_split_at_mut)] #![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_swap)] -#![feature(const_transmute_copy)] #![feature(const_try)] #![feature(const_type_id)] #![feature(const_type_name)] @@ -170,6 +178,7 @@ #![feature(ip)] #![feature(ip_bits)] #![feature(is_ascii_octdigit)] +#![feature(isqrt)] #![feature(maybe_uninit_uninit_array)] #![feature(ptr_alignment_type)] #![feature(ptr_metadata)] @@ -228,7 +237,6 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(no_core)] -#![feature(no_coverage)] // rust-lang/rust#84605 #![feature(platform_intrinsics)] #![feature(prelude_import)] #![feature(repr_simd)] @@ -282,6 +290,9 @@ pub mod assert_matches { pub use crate::macros::{assert_matches, debug_assert_matches}; } +#[unstable(feature = "cfg_match", issue = "115585")] +pub use crate::macros::cfg_match; + #[macro_use] mod internal_macros; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 14cc523b0..123661b35 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -168,6 +168,94 @@ pub macro assert_matches { }, } +/// A macro for defining `#[cfg]` match-like statements. +/// +/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of +/// `#[cfg]` cases, emitting the implementation which matches first. +/// +/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code +/// without having to rewrite each clause multiple times. +/// +/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when +/// all previous declarations do not evaluate to true. +/// +/// # Example +/// +/// ``` +/// #![feature(cfg_match)] +/// +/// cfg_match! { +/// cfg(unix) => { +/// fn foo() { /* unix specific functionality */ } +/// } +/// cfg(target_pointer_width = "32") => { +/// fn foo() { /* non-unix, 32-bit functionality */ } +/// } +/// _ => { +/// fn foo() { /* fallback implementation */ } +/// } +/// } +/// ``` +#[unstable(feature = "cfg_match", issue = "115585")] +#[rustc_diagnostic_item = "cfg_match"] +pub macro cfg_match { + // with a final wildcard + ( + $(cfg($initial_meta:meta) => { $($initial_tokens:item)* })+ + _ => { $($extra_tokens:item)* } + ) => { + cfg_match! { + @__items (); + $((($initial_meta) ($($initial_tokens)*)),)+ + (() ($($extra_tokens)*)), + } + }, + + // without a final wildcard + ( + $(cfg($extra_meta:meta) => { $($extra_tokens:item)* })* + ) => { + cfg_match! { + @__items (); + $((($extra_meta) ($($extra_tokens)*)),)* + } + }, + + // Internal and recursive macro to emit all the items + // + // Collects all the previous cfgs in a list at the beginning, so they can be + // negated. After the semicolon is all the remaining items. + (@__items ($($_:meta,)*);) => {}, + ( + @__items ($($no:meta,)*); + (($($yes:meta)?) ($($tokens:item)*)), + $($rest:tt,)* + ) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$yes` matchers specified and must also negate + // all previous matchers. + #[cfg(all( + $($yes,)? + not(any($($no),*)) + ))] + cfg_match! { @__identity $($tokens)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$yes` matchers to the list of `$no` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_match! { + @__items ($($no,)* $($yes,)?); + $($rest,)* + } + }, + + // Internal macro to make __apply work out right for different match types, + // because of how macros match/expand stuff. + (@__identity $($tokens:item)*) => { + $($tokens)* + } +} + /// Asserts that a boolean expression is `true` at runtime. /// /// This will invoke the [`panic!`] macro if the provided expression cannot be @@ -849,7 +937,8 @@ pub(crate) mod builtin { /// assert_eq!(display, debug); /// ``` /// - /// For more information, see the documentation in [`std::fmt`]. + /// See [the formatting documentation in `std::fmt`](../std/fmt/index.html) + /// for details of the macro argument syntax, and further information. /// /// [`Display`]: crate::fmt::Display /// [`Debug`]: crate::fmt::Debug @@ -1043,7 +1132,7 @@ pub(crate) mod builtin { /// expression of type `&'static str` which represents all of the literals /// concatenated left-to-right. /// - /// Integer and floating point literals are stringified in order to be + /// Integer and floating point literals are [stringified](core::stringify) in order to be /// concatenated. /// /// # Examples diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md index 8b549e187..60100c265 100644 --- a/library/core/src/macros/panic.md +++ b/library/core/src/macros/panic.md @@ -8,8 +8,8 @@ tests. `panic!` is closely tied with the `unwrap` method of both [`Option`][ounwrap] and [`Result`][runwrap] enums. Both implementations call `panic!` when they are set to [`None`] or [`Err`] variants. -When using `panic!()` you can specify a string payload, that is built using -the [`format!`] syntax. That payload is used when injecting the panic into +When using `panic!()` you can specify a string payload that is built using +[formatting syntax]. That payload is used when injecting the panic into the calling Rust thread, causing the thread to panic entirely. The behavior of the default `std` hook, i.e. the code that runs directly @@ -18,6 +18,7 @@ after the panic is invoked, is to print the message payload to call. You can override the panic hook using [`std::panic::set_hook()`]. Inside the hook a panic can be accessed as a `&dyn Any + Send`, which contains either a `&str` or `String` for regular `panic!()` invocations. +(Whether a particular invocation contains the payload at type `&str` or `String` is unspecified and can change.) To panic with a value of another other type, [`panic_any`] can be used. See also the macro [`compile_error!`], for raising errors during compilation. @@ -55,7 +56,7 @@ For more detailed information about error handling check out the [book] or the [`panic_any`]: ../std/panic/fn.panic_any.html [`Box`]: ../std/boxed/struct.Box.html [`Any`]: crate::any::Any -[`format!`]: ../std/macro.format.html +[`format!` syntax]: ../std/fmt/index.html [book]: ../book/ch09-00-error-handling.html [`std::result`]: ../std/result/index.html @@ -64,6 +65,29 @@ For more detailed information about error handling check out the [book] or the If the main thread panics it will terminate all your threads and end your program with code `101`. +# Editions + +Behavior of the panic macros changed over editions. + +## 2021 and later + +In Rust 2021 and later, `panic!` always requires a format string and +the applicable format arguments, and is the same in `core` and `std`. +Use [`std::panic::panic_any(x)`](../std/panic/fn.panic_any.html) to +panic with an arbitrary payload. + +## 2018 and 2015 + +In Rust Editions prior to 2021, `std::panic!(x)` with a single +argument directly uses that argument as a payload. +This is true even if the argument is a string literal. +For example, `panic!("problem: {reason}")` panics with a +payload of literally `"problem: {reason}"` (a `&'static str`). + +`core::panic!(x)` with a single argument requires that `x` be `&str`, +but otherwise behaves like `std::panic!`. In particular, the string +need not be a literal, and is not interpreted as a format string. + # Examples ```should_panic diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 5ec751e51..5ed82e26a 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -986,11 +986,16 @@ pub trait Tuple {} pub trait PointerLike {} /// 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 +/// derived (`StructuralPartialEq`). There's a hard-coded check in the compiler ensuring +/// that all fields are also `ConstParamTy`, which implies that recursively, all fields +/// are `StructuralPartialEq`. #[lang = "const_param_ty"] #[unstable(feature = "adt_const_params", issue = "95174")] #[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] #[allow(multiple_supertrait_upcastable)] -pub trait ConstParamTy: StructuralEq + StructuralPartialEq {} +pub trait ConstParamTy: StructuralEq + StructuralPartialEq + Eq {} /// Derive macro generating an impl of the trait `ConstParamTy`. #[rustc_builtin_macro] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 2fff3f0ef..e478b217f 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -413,7 +413,7 @@ pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(note = "use `align_of` instead", since = "1.2.0")] +#[deprecated(note = "use `align_of` instead", since = "1.2.0", suggestion = "align_of")] pub fn min_align_of<T>() -> usize { intrinsics::min_align_of::<T>() } @@ -436,7 +436,7 @@ pub fn min_align_of<T>() -> usize { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(note = "use `align_of_val` instead", since = "1.2.0")] +#[deprecated(note = "use `align_of_val` instead", since = "1.2.0", suggestion = "align_of_val")] pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer unsafe { intrinsics::min_align_of_val(val) } @@ -1051,7 +1051,7 @@ pub const fn copy<T: Copy>(x: &T) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] +#[rustc_const_stable(feature = "const_transmute_copy", since = "1.74.0")] pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst { assert!( size_of::<Src>() >= size_of::<Dst>(), @@ -1126,6 +1126,13 @@ impl<T> fmt::Debug for Discriminant<T> { /// /// [Reference]: ../../reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations /// +/// The value of a [`Discriminant<T>`] is independent of any *free lifetimes* in `T`. As such, +/// reading or writing a `Discriminant<Foo<'a>>` as a `Discriminant<Foo<'b>>` (whether via +/// [`transmute`] or otherwise) is always sound. Note that this is **not** true for other kinds +/// of generic parameters and for higher-ranked lifetimes; `Discriminant<Foo<A>>` and +/// `Discriminant<Foo<B>>` as well as `Discriminant<Bar<dyn for<'a> Trait<'a>>>` and +/// `Discriminant<Bar<dyn Trait<'static>>>` may be incompatible. +/// /// # Examples /// /// This can be used to compare enums that carry data, while disregarding diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 56460c75e..6a36dfec0 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1856,13 +1856,7 @@ impl fmt::Display for Ipv6Addr { if f.precision().is_none() && f.width().is_none() { let segments = self.segments(); - // Special case for :: and ::1; otherwise they get written with the - // IPv4 formatter - if self.is_unspecified() { - f.write_str("::") - } else if self.is_loopback() { - f.write_str("::1") - } else if let Some(ipv4) = self.to_ipv4_mapped() { + if let Some(ipv4) = self.to_ipv4_mapped() { write!(f, "::ffff:{}", ipv4) } else { #[derive(Copy, Clone, Default)] diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/dec2flt/fpu.rs index 3806977f7..8d62684f8 100644 --- a/library/core/src/num/dec2flt/fpu.rs +++ b/library/core/src/num/dec2flt/fpu.rs @@ -8,6 +8,17 @@ pub use fpu_precision::set_precision; // round to 80 bits causing double rounding to happen when values are eventually represented as // 32/64 bit float values. To overcome this, the FPU control word can be set so that the // computations are performed in the desired precision. +// +// Note that normally, it is Undefined Behavior to alter the FPU control word while Rust code runs. +// The compiler assumes that the control word is always in its default state. However, in this +// particular case the semantics with the altered control word are actually *more faithful* +// to Rust semantics than the default -- arguably it is all the code that runs *outside* of the scope +// of a `set_precision` guard that is wrong. +// In other words, we are only using this to work around <https://github.com/rust-lang/rust/issues/114479>. +// Sometimes killing UB with UB actually works... +// (If this is used to set 32bit precision, there is still a risk that the compiler moves some 64bit +// operation into the scope of the `set_precision` guard. So it's not like this is totally sound. +// But it's not really any less sound than the default state of 80bit precision...) #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] mod fpu_precision { use core::arch::asm; diff --git a/library/core/src/num/dec2flt/number.rs b/library/core/src/num/dec2flt/number.rs index 8589e2bbd..253899156 100644 --- a/library/core/src/num/dec2flt/number.rs +++ b/library/core/src/num/dec2flt/number.rs @@ -51,6 +51,7 @@ impl Number { /// There is an exception: disguised fast-path cases, where we can shift /// powers-of-10 from the exponent to the significant digits. pub fn try_fast_path<F: RawFloat>(&self) -> Option<F> { + // Here we need to work around <https://github.com/rust-lang/rust/issues/114479>. // The fast path crucially depends on arithmetic being rounded to the correct number of bits // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index d050d21c8..290f649f9 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -277,6 +277,14 @@ pub mod consts { #[stable(feature = "tau_constant", since = "1.47.0")] pub const TAU: f32 = 6.28318530717958647692528676655900577_f32; + /// The golden ratio (φ) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const PHI: f32 = 1.618033988749894848204586834365638118_f32; + + /// The Euler-Mascheroni constant (γ) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const EGAMMA: f32 = 0.577215664901532860606512090082402431_f32; + /// π/2 #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_PI_2: f32 = 1.57079632679489661923132169163975144_f32; @@ -301,6 +309,10 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_1_PI: f32 = 0.318309886183790671537767526745028724_f32; + /// 1/sqrt(π) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_PI: f32 = 0.564189583547756286948079451560772586_f32; + /// 2/π #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_2_PI: f32 = 0.636619772367581343075535053490057448_f32; @@ -317,6 +329,14 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_1_SQRT_2: f32 = 0.707106781186547524400844362104849039_f32; + /// sqrt(3) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const SQRT_3: f32 = 1.732050807568877293527446341505872367_f32; + + /// 1/sqrt(3) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_3: f32 = 0.577350269189625764509148780501957456_f32; + /// Euler's number (e) #[stable(feature = "rust1", since = "1.0.0")] pub const E: f32 = 2.71828182845904523536028747135266250_f32; @@ -937,6 +957,7 @@ impl f32 { } else if self == other { if self.is_sign_negative() && other.is_sign_positive() { self } else { other } } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. self + other } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index d9a738191..7569d2cd6 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -277,6 +277,14 @@ pub mod consts { #[stable(feature = "tau_constant", since = "1.47.0")] pub const TAU: f64 = 6.28318530717958647692528676655900577_f64; + /// The golden ratio (φ) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const PHI: f64 = 1.618033988749894848204586834365638118_f64; + + /// The Euler-Mascheroni constant (γ) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const EGAMMA: f64 = 0.577215664901532860606512090082402431_f64; + /// π/2 #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_PI_2: f64 = 1.57079632679489661923132169163975144_f64; @@ -301,6 +309,10 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_1_PI: f64 = 0.318309886183790671537767526745028724_f64; + /// 1/sqrt(π) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_PI: f64 = 0.564189583547756286948079451560772586_f64; + /// 2/π #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_2_PI: f64 = 0.636619772367581343075535053490057448_f64; @@ -317,6 +329,14 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64; + /// sqrt(3) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const SQRT_3: f64 = 1.732050807568877293527446341505872367_f64; + + /// 1/sqrt(3) + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_3: f64 = 0.577350269189625764509148780501957456_f64; + /// Euler's number (e) #[stable(feature = "rust1", since = "1.0.0")] pub const E: f64 = 2.71828182845904523536028747135266250_f64; @@ -948,6 +968,7 @@ impl f64 { } else if self == other { if self.is_sign_negative() && other.is_sign_positive() { self } else { other } } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. self + other } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 1f43520e1..3cbb55af3 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -898,6 +898,30 @@ macro_rules! int_impl { acc.checked_mul(base) } + /// Returns the square root of the number, rounded down. + /// + /// Returns `None` if `self` is negative. + /// + /// # Examples + /// + /// Basic usage: + /// ``` + /// #![feature(isqrt)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_isqrt(), Some(3));")] + /// ``` + #[unstable(feature = "isqrt", issue = "116226")] + #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_isqrt(self) -> Option<Self> { + if self < 0 { + None + } else { + Some((self as $UnsignedT).isqrt() as Self) + } + } + /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric /// bounds instead of overflowing. /// @@ -2061,6 +2085,36 @@ macro_rules! int_impl { acc * base } + /// Returns the square root of the number, rounded down. + /// + /// # Panics + /// + /// This function will panic if `self` is negative. + /// + /// # Examples + /// + /// Basic usage: + /// ``` + /// #![feature(isqrt)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] + /// ``` + #[unstable(feature = "isqrt", issue = "116226")] + #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn isqrt(self) -> Self { + // I would like to implement it as + // ``` + // self.checked_isqrt().expect("argument of integer square root must be non-negative") + // ``` + // but `expect` is not yet stable as a `const fn`. + match self.checked_isqrt() { + Some(sqrt) => sqrt, + None => panic!("argument of integer square root must be non-negative"), + } + } + /// Calculates the quotient of Euclidean division of `self` by `rhs`. /// /// This computes the integer `q` such that `self = q * rhs + r`, with diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 95dcaf5dd..8b127132c 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -44,11 +44,10 @@ mod uint_macros; // import uint_impl! mod error; mod int_log10; mod nonzero; -#[unstable(feature = "saturating_int_impl", issue = "87920")] mod saturating; mod wrapping; -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] pub use saturating::Saturating; #[stable(feature = "rust1", since = "1.0.0")] pub use wrapping::Wrapping; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5939dedbd..7f8d673c1 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -41,6 +41,20 @@ macro_rules! nonzero_integers { /// with the exception that `0` is not a valid instance. #[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be compatible with `", stringify!($Int), "`,")] /// including in FFI. + /// + /// Thanks to the [null pointer optimization], + #[doc = concat!("`", stringify!($Ty), "` and `Option<", stringify!($Ty), ">`")] + /// are guaranteed to have the same size and alignment: + /// + /// ``` + /// # use std::mem::{size_of, align_of}; + #[doc = concat!("use std::num::", stringify!($Ty), ";")] + /// + #[doc = concat!("assert_eq!(size_of::<", stringify!($Ty), ">(), size_of::<Option<", stringify!($Ty), ">>());")] + #[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::<Option<", stringify!($Ty), ">>());")] + /// ``` + /// + /// [null pointer optimization]: crate::option#representation #[$stability] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs index 8982473b2..d9ccc73c4 100644 --- a/library/core/src/num/saturating.rs +++ b/library/core/src/num/saturating.rs @@ -4,7 +4,7 @@ use crate::fmt; use crate::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign}; use crate::ops::{BitXor, BitXorAssign, Div, DivAssign}; use crate::ops::{Mul, MulAssign, Neg, Not, Rem, RemAssign}; -use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; +use crate::ops::{Sub, SubAssign}; /// Provides intentionally-saturating arithmetic on `T`. /// @@ -24,7 +24,6 @@ use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; /// # Examples /// /// ``` -/// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let max = Saturating(u32::MAX); @@ -32,180 +31,186 @@ use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; /// /// assert_eq!(u32::MAX, (max + one).0); /// ``` -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] #[repr(transparent)] -pub struct Saturating<T>(#[unstable(feature = "saturating_int_impl", issue = "87920")] pub T); +#[rustc_diagnostic_item = "Saturating"] +pub struct Saturating<T>( + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub T, +); -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::Debug> fmt::Debug for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::Display> fmt::Display for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::Binary> fmt::Binary for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::Octal> fmt::Octal for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::LowerHex> fmt::LowerHex for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[allow(unused_macros)] -macro_rules! sh_impl_signed { - ($t:ident, $f:ident) => { - // FIXME what is the correct implementation here? see discussion https://github.com/rust-lang/rust/pull/87921#discussion_r695870065 - // - // #[unstable(feature = "saturating_int_impl", issue = "87920")] - // impl Shl<$f> for Saturating<$t> { - // type Output = Saturating<$t>; - // - // #[inline] - // fn shl(self, other: $f) -> Saturating<$t> { - // if other < 0 { - // Saturating(self.0.shr((-other & self::shift_max::$t as $f) as u32)) - // } else { - // Saturating(self.0.shl((other & self::shift_max::$t as $f) as u32)) - // } - // } - // } - // forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f, - // #[unstable(feature = "saturating_int_impl", issue = "87920")] } - // - // #[unstable(feature = "saturating_int_impl", issue = "87920")] - // impl ShlAssign<$f> for Saturating<$t> { - // #[inline] - // fn shl_assign(&mut self, other: $f) { - // *self = *self << other; - // } - // } - // forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f } - - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl Shr<$f> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn shr(self, other: $f) -> Saturating<$t> { - if other < 0 { - Saturating(self.0.shl((-other & self::shift_max::$t as $f) as u32)) - } else { - Saturating(self.0.shr((other & self::shift_max::$t as $f) as u32)) - } - } - } - forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } - - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl ShrAssign<$f> for Saturating<$t> { - #[inline] - fn shr_assign(&mut self, other: $f) { - *self = *self >> other; - } - } - forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f } - }; -} - -macro_rules! sh_impl_unsigned { - ($t:ident, $f:ident) => { - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl Shl<$f> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn shl(self, other: $f) -> Saturating<$t> { - Saturating(self.0.wrapping_shl(other as u32)) - } - } - forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } - - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl ShlAssign<$f> for Saturating<$t> { - #[inline] - fn shl_assign(&mut self, other: $f) { - *self = *self << other; - } - } - forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f } - - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl Shr<$f> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn shr(self, other: $f) -> Saturating<$t> { - Saturating(self.0.wrapping_shr(other as u32)) - } - } - forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl ShrAssign<$f> for Saturating<$t> { - #[inline] - fn shr_assign(&mut self, other: $f) { - *self = *self >> other; - } - } - forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f } - }; -} - -// FIXME (#23545): uncomment the remaining impls -macro_rules! sh_impl_all { - ($($t:ident)*) => ($( - //sh_impl_unsigned! { $t, u8 } - //sh_impl_unsigned! { $t, u16 } - //sh_impl_unsigned! { $t, u32 } - //sh_impl_unsigned! { $t, u64 } - //sh_impl_unsigned! { $t, u128 } - sh_impl_unsigned! { $t, usize } - - //sh_impl_signed! { $t, i8 } - //sh_impl_signed! { $t, i16 } - //sh_impl_signed! { $t, i32 } - //sh_impl_signed! { $t, i64 } - //sh_impl_signed! { $t, i128 } - //sh_impl_signed! { $t, isize } - )*) -} - -sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } +// FIXME the correct implementation is not clear. Waiting for a real world use case at https://github.com/rust-lang/libs-team/issues/230 +// +// #[allow(unused_macros)] +// macro_rules! sh_impl_signed { +// ($t:ident, $f:ident) => { +// // FIXME what is the correct implementation here? see discussion https://github.com/rust-lang/rust/pull/87921#discussion_r695870065 +// // +// // #[unstable(feature = "saturating_int_impl", issue = "87920")] +// // impl Shl<$f> for Saturating<$t> { +// // type Output = Saturating<$t>; +// // +// // #[inline] +// // fn shl(self, other: $f) -> Saturating<$t> { +// // if other < 0 { +// // Saturating(self.0.shr((-other & self::shift_max::$t as $f) as u32)) +// // } else { +// // Saturating(self.0.shl((other & self::shift_max::$t as $f) as u32)) +// // } +// // } +// // } +// // forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f, +// // #[unstable(feature = "saturating_int_impl", issue = "87920")] } +// // +// // #[unstable(feature = "saturating_int_impl", issue = "87920")] +// // impl ShlAssign<$f> for Saturating<$t> { +// // #[inline] +// // fn shl_assign(&mut self, other: $f) { +// // *self = *self << other; +// // } +// // } +// // forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl Shr<$f> for Saturating<$t> { +// type Output = Saturating<$t>; +// +// #[inline] +// fn shr(self, other: $f) -> Saturating<$t> { +// if other < 0 { +// Saturating(self.0.shl((-other & self::shift_max::$t as $f) as u32)) +// } else { +// Saturating(self.0.shr((other & self::shift_max::$t as $f) as u32)) +// } +// } +// } +// forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f, +// #[unstable(feature = "saturating_int_impl", issue = "87920")] } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl ShrAssign<$f> for Saturating<$t> { +// #[inline] +// fn shr_assign(&mut self, other: $f) { +// *self = *self >> other; +// } +// } +// forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f } +// }; +// } +// +// macro_rules! sh_impl_unsigned { +// ($t:ident, $f:ident) => { +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl Shl<$f> for Saturating<$t> { +// type Output = Saturating<$t>; +// +// #[inline] +// fn shl(self, other: $f) -> Saturating<$t> { +// Saturating(self.0.wrapping_shl(other as u32)) +// } +// } +// forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f, +// #[unstable(feature = "saturating_int_impl", issue = "87920")] } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl ShlAssign<$f> for Saturating<$t> { +// #[inline] +// fn shl_assign(&mut self, other: $f) { +// *self = *self << other; +// } +// } +// forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl Shr<$f> for Saturating<$t> { +// type Output = Saturating<$t>; +// +// #[inline] +// fn shr(self, other: $f) -> Saturating<$t> { +// Saturating(self.0.wrapping_shr(other as u32)) +// } +// } +// forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f, +// #[unstable(feature = "saturating_int_impl", issue = "87920")] } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl ShrAssign<$f> for Saturating<$t> { +// #[inline] +// fn shr_assign(&mut self, other: $f) { +// *self = *self >> other; +// } +// } +// forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f } +// }; +// } +// +// // FIXME (#23545): uncomment the remaining impls +// macro_rules! sh_impl_all { +// ($($t:ident)*) => ($( +// //sh_impl_unsigned! { $t, u8 } +// //sh_impl_unsigned! { $t, u16 } +// //sh_impl_unsigned! { $t, u32 } +// //sh_impl_unsigned! { $t, u64 } +// //sh_impl_unsigned! { $t, u128 } +// sh_impl_unsigned! { $t, usize } +// +// //sh_impl_signed! { $t, i8 } +// //sh_impl_signed! { $t, i16 } +// //sh_impl_signed! { $t, i32 } +// //sh_impl_signed! { $t, i64 } +// //sh_impl_signed! { $t, i128 } +// //sh_impl_signed! { $t, isize } +// )*) +// } +// +// sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } // FIXME(30524): impl Op<T> for Saturating<T>, impl OpAssign<T> for Saturating<T> macro_rules! saturating_impl { ($($t:ty)*) => ($( - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Add for Saturating<$t> { type Output = Saturating<$t>; @@ -215,9 +220,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl AddAssign for Saturating<$t> { #[inline] fn add_assign(&mut self, other: Saturating<$t>) { @@ -226,7 +231,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl AddAssign<$t> for Saturating<$t> { #[inline] fn add_assign(&mut self, other: $t) { @@ -235,7 +240,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Sub for Saturating<$t> { type Output = Saturating<$t>; @@ -245,9 +250,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl SubAssign for Saturating<$t> { #[inline] fn sub_assign(&mut self, other: Saturating<$t>) { @@ -256,7 +261,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl SubAssign<$t> for Saturating<$t> { #[inline] fn sub_assign(&mut self, other: $t) { @@ -265,7 +270,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Mul for Saturating<$t> { type Output = Saturating<$t>; @@ -275,9 +280,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl MulAssign for Saturating<$t> { #[inline] fn mul_assign(&mut self, other: Saturating<$t>) { @@ -286,7 +291,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl MulAssign<$t> for Saturating<$t> { #[inline] fn mul_assign(&mut self, other: $t) { @@ -300,7 +305,6 @@ macro_rules! saturating_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / Saturating(2));")] @@ -309,12 +313,11 @@ macro_rules! saturating_impl { /// ``` /// /// ```should_panic - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / Saturating(0);")] /// ``` - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Div for Saturating<$t> { type Output = Saturating<$t>; @@ -324,10 +327,10 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl DivAssign for Saturating<$t> { #[inline] fn div_assign(&mut self, other: Saturating<$t>) { @@ -336,7 +339,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl DivAssign<$t> for Saturating<$t> { #[inline] fn div_assign(&mut self, other: $t) { @@ -345,7 +348,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Rem for Saturating<$t> { type Output = Saturating<$t>; @@ -355,9 +358,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl RemAssign for Saturating<$t> { #[inline] fn rem_assign(&mut self, other: Saturating<$t>) { @@ -366,7 +369,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl RemAssign<$t> for Saturating<$t> { #[inline] fn rem_assign(&mut self, other: $t) { @@ -375,7 +378,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Not for Saturating<$t> { type Output = Saturating<$t>; @@ -385,9 +388,9 @@ macro_rules! saturating_impl { } } forward_ref_unop! { impl Not, not for Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitXor for Saturating<$t> { type Output = Saturating<$t>; @@ -397,9 +400,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitXorAssign for Saturating<$t> { #[inline] fn bitxor_assign(&mut self, other: Saturating<$t>) { @@ -408,7 +411,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl BitXorAssign<$t> for Saturating<$t> { #[inline] fn bitxor_assign(&mut self, other: $t) { @@ -417,7 +420,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitOr for Saturating<$t> { type Output = Saturating<$t>; @@ -427,9 +430,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitOrAssign for Saturating<$t> { #[inline] fn bitor_assign(&mut self, other: Saturating<$t>) { @@ -438,7 +441,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl BitOrAssign<$t> for Saturating<$t> { #[inline] fn bitor_assign(&mut self, other: $t) { @@ -447,7 +450,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitAnd for Saturating<$t> { type Output = Saturating<$t>; @@ -457,9 +460,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitAndAssign for Saturating<$t> { #[inline] fn bitand_assign(&mut self, other: Saturating<$t>) { @@ -468,7 +471,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl BitAndAssign<$t> for Saturating<$t> { #[inline] fn bitand_assign(&mut self, other: $t) { @@ -492,12 +495,11 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::MIN, Saturating(", stringify!($t), "::MIN));")] /// ``` - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const MIN: Self = Self(<$t>::MIN); /// Returns the largest value that can be represented by this integer type. @@ -507,12 +509,11 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::MAX, Saturating(", stringify!($t), "::MAX));")] /// ``` - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const MAX: Self = Self(<$t>::MAX); /// Returns the size of this integer type in bits. @@ -522,12 +523,11 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::BITS, ", stringify!($t), "::BITS);")] /// ``` - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const BITS: u32 = <$t>::BITS; /// Returns the number of ones in the binary representation of `self`. @@ -537,7 +537,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0b01001100", stringify!($t), ");")] @@ -549,7 +548,8 @@ macro_rules! saturating_int_impl { #[doc(alias = "popcnt")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn count_ones(self) -> u32 { self.0.count_ones() } @@ -561,7 +561,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(!0", stringify!($t), ").count_zeros(), 0);")] @@ -569,7 +568,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn count_zeros(self) -> u32 { self.0.count_zeros() } @@ -581,7 +581,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0b0101000", stringify!($t), ");")] @@ -591,7 +590,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn trailing_zeros(self) -> u32 { self.0.trailing_zeros() } @@ -608,7 +608,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let n: Saturating<i64> = Saturating(0x0123456789ABCDEF); @@ -619,7 +618,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn rotate_left(self, n: u32) -> Self { Saturating(self.0.rotate_left(n)) } @@ -636,7 +636,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let n: Saturating<i64> = Saturating(0x0123456789ABCDEF); @@ -647,7 +646,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn rotate_right(self, n: u32) -> Self { Saturating(self.0.rotate_right(n)) } @@ -659,7 +659,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let n: Saturating<i16> = Saturating(0b0000000_01010101); @@ -673,7 +672,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn swap_bytes(self) -> Self { Saturating(self.0.swap_bytes()) } @@ -688,7 +688,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let n = Saturating(0b0000000_01010101i16); @@ -700,8 +699,8 @@ macro_rules! saturating_int_impl { /// assert_eq!(m, Saturating(-22016)); /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] - #[rustc_const_unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn reverse_bits(self) -> Self { @@ -718,7 +717,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")] @@ -731,7 +729,8 @@ macro_rules! saturating_int_impl { /// ``` #[inline] #[must_use] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn from_be(x: Self) -> Self { Saturating(<$t>::from_be(x.0)) } @@ -746,7 +745,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")] @@ -759,7 +757,8 @@ macro_rules! saturating_int_impl { /// ``` #[inline] #[must_use] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn from_le(x: Self) -> Self { Saturating(<$t>::from_le(x.0)) } @@ -774,7 +773,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")] @@ -786,7 +784,8 @@ macro_rules! saturating_int_impl { /// } /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn to_be(self) -> Self { @@ -803,7 +802,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")] @@ -815,7 +813,8 @@ macro_rules! saturating_int_impl { /// } /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn to_le(self) -> Self { @@ -829,7 +828,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(3", stringify!($t), ").pow(4), Saturating(81));")] @@ -838,17 +836,17 @@ macro_rules! saturating_int_impl { /// Results that are too large are saturated: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// assert_eq!(Saturating(3i8).pow(5), Saturating(127)); /// assert_eq!(Saturating(3i8).pow(6), Saturating(127)); /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn pow(self, exp: u32) -> Self { + pub const fn pow(self, exp: u32) -> Self { Saturating(self.0.saturating_pow(exp)) } } @@ -867,7 +865,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(", stringify!($t), "::MAX >> 2);")] @@ -875,7 +872,8 @@ macro_rules! saturating_int_impl_signed { /// assert_eq!(n.leading_zeros(), 3); /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn leading_zeros(self) -> u32 { @@ -890,7 +888,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(100", stringify!($t), ").abs(), Saturating(100));")] @@ -900,10 +897,11 @@ macro_rules! saturating_int_impl_signed { #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MIN).abs(), Saturating(", stringify!($t), "::MAX));")] /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn abs(self) -> Saturating<$t> { + pub const fn abs(self) -> Saturating<$t> { Saturating(self.0.saturating_abs()) } @@ -918,7 +916,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(10", stringify!($t), ").signum(), Saturating(1));")] @@ -926,10 +923,11 @@ macro_rules! saturating_int_impl_signed { #[doc = concat!("assert_eq!(Saturating(-10", stringify!($t), ").signum(), Saturating(-1));")] /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn signum(self) -> Saturating<$t> { + pub const fn signum(self) -> Saturating<$t> { Saturating(self.0.signum()) } @@ -941,7 +939,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert!(Saturating(10", stringify!($t), ").is_positive());")] @@ -949,7 +946,8 @@ macro_rules! saturating_int_impl_signed { /// ``` #[must_use] #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn is_positive(self) -> bool { self.0.is_positive() } @@ -962,7 +960,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert!(Saturating(-10", stringify!($t), ").is_negative());")] @@ -970,13 +967,14 @@ macro_rules! saturating_int_impl_signed { /// ``` #[must_use] #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn is_negative(self) -> bool { self.0.is_negative() } } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Neg for Saturating<$t> { type Output = Self; #[inline] @@ -985,7 +983,7 @@ macro_rules! saturating_int_impl_signed { } } forward_ref_unop! { impl Neg, neg for Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } )*) } @@ -1001,7 +999,6 @@ macro_rules! saturating_int_impl_unsigned { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(", stringify!($t), "::MAX >> 2);")] @@ -1009,7 +1006,8 @@ macro_rules! saturating_int_impl_unsigned { /// assert_eq!(n.leading_zeros(), 2); /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn leading_zeros(self) -> u32 { @@ -1023,7 +1021,6 @@ macro_rules! saturating_int_impl_unsigned { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert!(Saturating(16", stringify!($t), ").is_power_of_two());")] @@ -1031,8 +1028,9 @@ macro_rules! saturating_int_impl_unsigned { /// ``` #[must_use] #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] - pub fn is_power_of_two(self) -> bool { + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] + pub const fn is_power_of_two(self) -> bool { self.0.is_power_of_two() } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 23ca37817..a9c5312a1 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1259,6 +1259,10 @@ macro_rules! uint_impl { /// This function exists, so that all operations /// are accounted for in the wrapping operations. /// + /// # Panics + /// + /// This function will panic if `rhs` is 0. + /// /// # Examples /// /// Basic usage: @@ -1284,6 +1288,10 @@ macro_rules! uint_impl { /// definitions of division are equal, this /// is exactly equal to `self.wrapping_div(rhs)`. /// + /// # Panics + /// + /// This function will panic if `rhs` is 0. + /// /// # Examples /// /// Basic usage: @@ -1307,6 +1315,10 @@ macro_rules! uint_impl { /// This function exists, so that all operations /// are accounted for in the wrapping operations. /// + /// # Panics + /// + /// This function will panic if `rhs` is 0. + /// /// # Examples /// /// Basic usage: @@ -1333,6 +1345,10 @@ macro_rules! uint_impl { /// definitions of division are equal, this /// is exactly equal to `self.wrapping_rem(rhs)`. /// + /// # Panics + /// + /// This function will panic if `rhs` is 0. + /// /// # Examples /// /// Basic usage: @@ -1979,6 +1995,54 @@ macro_rules! uint_impl { acc * base } + /// Returns the square root of the number, rounded down. + /// + /// # Examples + /// + /// Basic usage: + /// ``` + /// #![feature(isqrt)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] + /// ``` + #[unstable(feature = "isqrt", issue = "116226")] + #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn isqrt(self) -> Self { + if self < 2 { + return self; + } + + // The algorithm is based on the one presented in + // <https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)> + // which cites as source the following C code: + // <https://web.archive.org/web/20120306040058/http://medialab.freaknet.org/martin/src/sqrt/sqrt.c>. + + let mut op = self; + let mut res = 0; + let mut one = 1 << (self.ilog2() & !1); + + while one != 0 { + if op >= res + one { + op -= res + one; + res = (res >> 1) + one; + } else { + res >>= 1; + } + one >>= 2; + } + + // SAFETY: the result is positive and fits in an integer with half as many bits. + // Inform the optimizer about it. + unsafe { + intrinsics::assume(0 < res); + intrinsics::assume(res < 1 << (Self::BITS / 2)); + } + + res + } + /// Performs Euclidean division. /// /// Since, for the positive integers, all common diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index ed354a2e5..16f0b6d91 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -39,6 +39,7 @@ use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] #[repr(transparent)] +#[rustc_diagnostic_item = "Wrapping"] pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T); #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 08c35b6da..911761c6e 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -14,6 +14,11 @@ /// For similar reasons, **this trait should never fail**. Failure during /// dereferencing can be extremely confusing when `Deref` is invoked implicitly. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this +/// method. +/// /// # More on `Deref` coercion /// /// If `T` implements `Deref<Target = U>`, and `x` is a value of type `T`, then: @@ -114,6 +119,11 @@ impl<T: ?Sized> Deref for &mut T { /// dereferencing can be extremely confusing when `DerefMut` is invoked /// implicitly. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this +/// method. +/// /// # More on `Deref` coercion /// /// If `T` implements `DerefMut<Target = U>`, and `x` is a value of type `T`, diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index 9ebf426be..34dfa9e4c 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -202,7 +202,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")] -#[const_trait] +// FIXME(effects) #[const_trait] pub trait Drop { /// Executes the destructor for this type. /// @@ -217,8 +217,13 @@ pub trait Drop { /// /// # Panics /// - /// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`] - /// in a `drop` implementation will likely abort. + /// Implementations should generally avoid [`panic!`]ing, because `drop()` may itself be called + /// during unwinding due to a panic, and if the `drop()` panics in that situation (a “double + /// panic”), this will likely abort the program. It is possible to check [`panicking()`] first, + /// which may be desirable for a `Drop` implementation that is reporting a bug of the kind + /// “you didn't finish using this before it was dropped”; but most types should simply clean up + /// their owned allocations or other resources and return normally from `drop()`, regardless of + /// what state they are in. /// /// Note that even if this panics, the value is considered to be dropped; /// you must not cause `drop` to be called again. This is normally automatically @@ -227,6 +232,7 @@ pub trait Drop { /// /// [E0040]: ../../error_codes/E0040.html /// [`panic!`]: crate::panic! + /// [`panicking()`]: ../../std/thread/fn.panicking.html /// [`mem::drop`]: drop /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 67c8245f0..20f0bba4c 100644 --- a/library/core/src/ops/function.rs +++ b/library/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"] -#[const_trait] +// FIXME(effects) #[const_trait] pub trait Fn<Args: Tuple>: FnMut<Args> { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -159,7 +159,7 @@ pub trait Fn<Args: Tuple>: FnMut<Args> { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -#[const_trait] +// FIXME(effects) #[const_trait] pub trait FnMut<Args: Tuple>: FnOnce<Args> { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -238,7 +238,7 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -#[const_trait] +// FIXME(effects) #[const_trait] pub trait FnOnce<Args: Tuple> { /// The returned type after the call operator is used. #[lang = "fn_once_output"] diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index ba5e6ddc7..cc596293c 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -11,7 +11,7 @@ use crate::hash::Hash; /// The `..` syntax is a `RangeFull`: /// /// ``` -/// assert_eq!((..), std::ops::RangeFull); +/// assert_eq!(.., std::ops::RangeFull); /// ``` /// /// It does not have an [`IntoIterator`] implementation, so you can't use it in diff --git a/library/core/src/option.rs b/library/core/src/option.rs index becb63309..f2909a81d 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -119,7 +119,7 @@ //! # Representation //! //! Rust guarantees to optimize the following types `T` such that -//! [`Option<T>`] has the same size as `T`: +//! [`Option<T>`] has the same size and alignment as `T`: //! //! * [`Box<U>`] //! * `&U` diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 20be60d35..386f5fcbd 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -99,7 +99,7 @@ pub macro unreachable_2021 { /// use. #[unstable(feature = "std_internals", issue = "none")] #[doc(hidden)] -pub unsafe trait BoxMeUp { +pub unsafe trait PanicPayload { /// Take full ownership of the contents. /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in core. /// @@ -107,7 +107,7 @@ pub unsafe trait BoxMeUp { /// Calling this method twice, or calling `get` after calling this method, is an error. /// /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only - /// gets a borrowed `dyn BoxMeUp`. + /// gets a borrowed `dyn PanicPayload`. fn take_box(&mut self) -> *mut (dyn Any + Send); /// Just borrow the contents. diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index c7f04f11e..c77e9675a 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -28,6 +28,7 @@ pub struct PanicInfo<'a> { message: Option<&'a fmt::Arguments<'a>>, location: &'a Location<'a>, can_unwind: bool, + force_no_backtrace: bool, } impl<'a> PanicInfo<'a> { @@ -42,9 +43,10 @@ impl<'a> PanicInfo<'a> { message: Option<&'a fmt::Arguments<'a>>, location: &'a Location<'a>, can_unwind: bool, + force_no_backtrace: bool, ) -> Self { struct NoPayload; - PanicInfo { location, message, payload: &NoPayload, can_unwind } + PanicInfo { location, message, payload: &NoPayload, can_unwind, force_no_backtrace } } #[unstable( @@ -141,6 +143,17 @@ impl<'a> PanicInfo<'a> { pub fn can_unwind(&self) -> bool { self.can_unwind } + + #[unstable( + feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` and related macros", + issue = "none" + )] + #[doc(hidden)] + #[inline] + pub fn force_no_backtrace(&self) -> bool { + self.force_no_backtrace + } } #[stable(feature = "panic_hook_display", since = "1.26.0")] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 7b6249207..e6cdffd96 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -61,7 +61,12 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { fn panic_impl(pi: &PanicInfo<'_>) -> !; } - let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true); + let pi = PanicInfo::internal_constructor( + Some(&fmt), + Location::caller(), + /* can_unwind */ true, + /* force_no_backtrace */ false, + ); // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. unsafe { panic_impl(&pi) } @@ -77,7 +82,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, // which causes a "panic in a function that cannot unwind". #[rustc_nounwind] -pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! { +pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } @@ -90,7 +95,12 @@ pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! { } // PanicInfo with the `can_unwind` flag set to false forces an abort. - let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false); + let pi = PanicInfo::internal_constructor( + Some(&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) } @@ -123,7 +133,15 @@ pub const fn panic(expr: &'static str) -> ! { #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] pub fn panic_nounwind(expr: &'static str) -> ! { - panic_nounwind_fmt(fmt::Arguments::new_const(&[expr])); + panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false); +} + +/// Like `panic_nounwind`, but also inhibits showing a backtrace. +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[rustc_nounwind] +pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { + panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true); } #[inline] @@ -172,13 +190,18 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { super::intrinsics::abort() } - panic_nounwind_fmt(format_args!( - "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}" - )) + panic_nounwind_fmt( + format_args!( + "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}" + ), + /* force_no_backtrace */ false, + ) } /// Panic because we cannot unwind out of a function. /// +/// This is a separate function to avoid the codesize impact of each crate containing the string to +/// pass to `panic_nounwind`. /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] @@ -186,15 +209,33 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { #[lang = "panic_cannot_unwind"] // needed by codegen for panic in nounwind function #[rustc_nounwind] fn panic_cannot_unwind() -> ! { + // Keep the text in sync with `UnwindTerminateReason::as_str` in `rustc_middle`. panic_nounwind("panic in a function that cannot unwind") } +/// Panic because we are unwinding out of a destructor during cleanup. +/// +/// This is a separate function to avoid the codesize impact of each crate containing the string to +/// pass to `panic_nounwind`. +/// This function is called directly by the codegen backend, and must not have +/// any extra arguments (including those synthesized by track_caller). +#[cfg(not(bootstrap))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function +#[rustc_nounwind] +fn panic_in_cleanup() -> ! { + // Keep the text in sync with `UnwindTerminateReason::as_str` in `rustc_middle`. + panic_nounwind_nobacktrace("panic in a destructor during cleanup") +} + /// This function is used instead of panic_fmt in const eval. #[lang = "const_panic_fmt"] #[rustc_const_unstable(feature = "core_panic", issue = "none")] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { - panic_str(msg); + // The panic_display function is hooked by const eval. + panic_display(&msg); } else { // SAFETY: This is only evaluated at compile time, which reliably // handles this UB (in case this branch turns out to be reachable diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 6b319b435..94c682b61 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -572,7 +572,10 @@ impl<P: Deref> Pin<P> { /// // though we have previously pinned it! We have violated the pinning API contract. /// } /// ``` - /// A value, once pinned, must remain pinned forever (unless its type implements `Unpin`). + /// A value, once pinned, must remain pinned until it is dropped (unless its type implements + /// `Unpin`). Because `Pin<&mut T>` does not own the value, dropping the `Pin` will not drop + /// the value and will not end the pinning contract. So moving the value after dropping the + /// `Pin<&mut T>` is still a violation of the API contract. /// /// Similarly, calling `Pin::new_unchecked` on an `Rc<T>` is unsafe because there could be /// aliases to the same data that are not subject to the pinning restrictions: diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 80289ca08..fd5fe5a04 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1,6 +1,3 @@ -// `library/{std,core}/src/primitive_docs.rs` should have the same contents. -// These are different files so that relative links work properly without -// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same. #[rustc_doc_primitive = "bool"] #[doc(alias = "true")] #[doc(alias = "false")] @@ -106,7 +103,7 @@ mod prim_bool {} /// behaviour of the `!` type - expressions with type `!` will coerce into any other type. /// /// [`u32`]: prim@u32 -#[doc = concat!("[`exit`]: ", include_str!("../primitive_docs/process_exit.md"))] +/// [`exit`]: ../std/process/fn.exit.html /// /// # `!` and generics /// @@ -191,7 +188,7 @@ mod prim_bool {} /// because `!` coerces to `Result<!, ConnectionError>` automatically. /// /// [`String::from_str`]: str::FromStr::from_str -#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] +/// [`String`]: ../std/string/struct.String.html /// [`FromStr`]: str::FromStr /// /// # `!` and traits @@ -267,7 +264,7 @@ mod prim_bool {} /// `impl` for this which simply panics, but the same is true for any type (we could `impl /// Default` for (eg.) [`File`] by just making [`default()`] panic.) /// -#[doc = concat!("[`File`]: ", include_str!("../primitive_docs/fs_file.md"))] +/// [`File`]: ../std/fs/struct.File.html /// [`Debug`]: fmt::Debug /// [`default()`]: Default::default /// @@ -355,7 +352,7 @@ mod prim_never {} /// assert_eq!(5, s.len() * std::mem::size_of::<u8>()); /// ``` /// -#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] +/// [`String`]: ../std/string/struct.String.html /// /// As always, remember that a human intuition for 'character' might not map to /// Unicode's definitions. For example, despite looking similar, the 'é' @@ -572,7 +569,7 @@ impl Copy for () { /// [`null_mut`]: ptr::null_mut /// [`is_null`]: pointer::is_null /// [`offset`]: pointer::offset -#[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))] +/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw /// [`write`]: ptr::write #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} @@ -612,7 +609,7 @@ mod prim_pointer {} /// statically generated up to size 32. /// /// Arrays of sizes from 1 to 12 (inclusive) implement [`From<Tuple>`], where `Tuple` -/// is a homogenous [prim@tuple] of appropriate length. +/// is a homogeneous [prim@tuple] of appropriate length. /// /// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on /// an array. Indeed, this provides most of the API for working with arrays. @@ -676,7 +673,7 @@ mod prim_pointer {} /// move_away(roa); /// ``` /// -/// Arrays can be created from homogenous tuples of appropriate length: +/// Arrays can be created from homogeneous tuples of appropriate length: /// /// ``` /// let tuple: (u32, u32, u32) = (1, 2, 3); @@ -1065,7 +1062,7 @@ mod prim_str {} /// assert_eq!(y, 5); /// ``` /// -/// Homogenous tuples can be created from arrays of appropriate length: +/// Homogeneous tuples can be created from arrays of appropriate length: /// /// ``` /// let array: [u32; 3] = [1, 2, 3]; @@ -1361,7 +1358,7 @@ mod prim_usize {} /// /// [`std::fmt`]: fmt /// [`Hash`]: hash::Hash -#[doc = concat!("[`ToSocketAddrs`]: ", include_str!("../primitive_docs/net_tosocketaddrs.md"))] +/// [`ToSocketAddrs`]: ../std/net/trait.ToSocketAddrs.html /// /// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T` /// implements that trait: @@ -1381,10 +1378,10 @@ mod prim_usize {} /// /// [`FusedIterator`]: iter::FusedIterator /// [`TrustedLen`]: iter::TrustedLen -#[doc = concat!("[`Seek`]: ", include_str!("../primitive_docs/io_seek.md"))] -#[doc = concat!("[`BufRead`]: ", include_str!("../primitive_docs/io_bufread.md"))] -#[doc = concat!("[`Read`]: ", include_str!("../primitive_docs/io_read.md"))] -#[doc = concat!("[`io::Write`]: ", include_str!("../primitive_docs/io_write.md"))] +/// [`Seek`]: ../std/io/trait.Seek.html +/// [`BufRead`]: ../std/io/trait.BufRead.html +/// [`Read`]: ../std/io/trait.Read.html +/// [`io::Write`]: ../std/io/trait.Write.html /// /// Note that due to method call deref coercion, simply calling a trait method will act like they /// work on references as well as they do on owned values! The implementations described here are diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index ee69d89a4..9af8f1228 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -607,7 +607,16 @@ impl<T: ?Sized> *const T { /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes divided by `mem::size_of::<T>()`. /// - /// This function is the inverse of [`offset`]. + /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::<T>() as isize)`, + /// except that it has a lot more opportunities for UB, in exchange for the compiler + /// better understanding what you are doing. + /// + /// The primary motivation of this method is for computing the `len` of an array/slice + /// of `T` that you are currently representing as a "start" and "end" pointer + /// (and "end" is "one past the end" of the array). + /// In that case, `end.offset_from(start)` gets you the length of the array. + /// + /// All of the following safety requirements are trivially satisfied for this usecase. /// /// [`offset`]: #method.offset /// @@ -616,7 +625,7 @@ impl<T: ?Sized> *const T { /// If any of the following conditions are violated, the result is Undefined /// Behavior: /// - /// * Both the starting and other pointer must be either in bounds or one + /// * Both `self` and `origin` must be either in bounds or one /// byte past the end of the same [allocated object]. /// /// * Both pointers must be *derived from* a pointer to the same object. @@ -646,6 +655,14 @@ impl<T: ?Sized> *const T { /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on /// such large allocations either.) /// + /// The requirement for pointers to be derived from the same allocated object is primarily + /// needed for `const`-compatibility: the distance between pointers into *different* allocated + /// objects is not known at compile-time. However, the requirement also exists at + /// runtime and may be exploited by optimizations. If you wish to compute the difference between + /// pointers that are not guaranteed to be from the same allocation, use `(self as isize - + /// origin as isize) / mem::size_of::<T>()`. + // FIXME: recommend `addr()` instead of `as usize` once that is stable. + /// /// [`add`]: #method.add /// [allocated object]: crate::ptr#allocated-object /// @@ -703,7 +720,7 @@ impl<T: ?Sized> *const T { /// units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [offset_from][pointer::offset_from] on it. See that method for + /// using [`offset_from`][pointer::offset_from] on it. See that method for /// documentation and safety requirements. /// /// For non-`Sized` pointees this operation considers only the data pointers, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 5f094ac4e..d1286a1de 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -698,6 +698,7 @@ where #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] +#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] #[rustc_diagnostic_item = "ptr_from_ref"] pub const fn from_ref<T: ?Sized>(r: &T) -> *const T { r @@ -710,7 +711,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T { #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] -#[rustc_diagnostic_item = "ptr_from_mut"] +#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T { r } @@ -795,7 +796,9 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * Both `x` and `y` must be [valid] for both reads and writes. +/// * Both `x` and `y` must be [valid] for both reads and writes. They must remain valid even when the +/// other pointer is written. (This means if the memory ranges overlap, the two pointers must not +/// be subject to aliasing restrictions relative to each other.) /// /// * Both `x` and `y` must be properly aligned. /// @@ -1357,6 +1360,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] +#[rustc_diagnostic_item = "ptr_write"] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write<T>(dst: *mut T, src: T) { // Semantically, it would be fine for this to be implemented as a @@ -1459,6 +1463,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] +#[rustc_diagnostic_item = "ptr_write_unaligned"] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. @@ -1607,6 +1612,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] +#[rustc_diagnostic_item = "ptr_write_volatile"] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn write_volatile<T>(dst: *mut T, src: T) { // SAFETY: the caller must uphold the safety contract for `volatile_store`. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 9dbb3f9d3..109c28692 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -109,7 +109,7 @@ impl<T: ?Sized> *mut T { /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit /// coercion. /// - /// [`cast_mut`]: #method.cast_mut + /// [`cast_mut`]: pointer::cast_mut #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_diagnostic_item = "ptr_cast_const"] @@ -121,7 +121,7 @@ impl<T: ?Sized> *mut T { /// Casts a pointer to its raw bits. /// /// This is equivalent to `as usize`, but is more specific to enhance readability. - /// The inverse method is [`from_bits`](#method.from_bits-1). + /// The inverse method is [`from_bits`](pointer#method.from_bits-1). /// /// In particular, `*p as usize` and `p as usize` will both compile for /// pointers to numeric types but do very different things, so using this @@ -157,7 +157,7 @@ impl<T: ?Sized> *mut T { /// Creates a pointer from its raw bits. /// /// This is equivalent to `as *mut T`, but is more specific to enhance readability. - /// The inverse method is [`to_bits`](#method.to_bits-1). + /// The inverse method is [`to_bits`](pointer#method.to_bits-1). /// /// # Examples /// @@ -307,7 +307,7 @@ impl<T: ?Sized> *mut T { /// /// For the mutable counterpart see [`as_mut`]. /// - /// [`as_uninit_ref`]: #method.as_uninit_ref-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 /// [`as_mut`]: #method.as_mut /// /// # Safety @@ -373,7 +373,7 @@ impl<T: ?Sized> *mut T { /// /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// [`as_uninit_mut`]: #method.as_uninit_mut /// /// # Safety @@ -628,7 +628,7 @@ impl<T: ?Sized> *mut T { /// For the shared counterpart see [`as_ref`]. /// /// [`as_uninit_mut`]: #method.as_uninit_mut - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// /// # Safety /// @@ -693,7 +693,7 @@ impl<T: ?Sized> *mut T { /// For the shared counterpart see [`as_uninit_ref`]. /// /// [`as_mut`]: #method.as_mut - /// [`as_uninit_ref`]: #method.as_uninit_ref-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 /// /// # Safety /// @@ -781,16 +781,25 @@ impl<T: ?Sized> *mut T { /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes divided by `mem::size_of::<T>()`. /// - /// This function is the inverse of [`offset`]. + /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::<T>() as isize)`, + /// except that it has a lot more opportunities for UB, in exchange for the compiler + /// better understanding what you are doing. /// - /// [`offset`]: #method.offset-1 + /// The primary motivation of this method is for computing the `len` of an array/slice + /// of `T` that you are currently representing as a "start" and "end" pointer + /// (and "end" is "one past the end" of the array). + /// In that case, `end.offset_from(start)` gets you the length of the array. + /// + /// All of the following safety requirements are trivially satisfied for this usecase. + /// + /// [`offset`]: pointer#method.offset-1 /// /// # Safety /// /// If any of the following conditions are violated, the result is Undefined /// Behavior: /// - /// * Both the starting and other pointer must be either in bounds or one + /// * Both `self` and `origin` must be either in bounds or one /// byte past the end of the same [allocated object]. /// /// * Both pointers must be *derived from* a pointer to the same object. @@ -820,6 +829,14 @@ impl<T: ?Sized> *mut T { /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on /// such large allocations either.) /// + /// The requirement for pointers to be derived from the same allocated object is primarily + /// needed for `const`-compatibility: the distance between pointers into *different* allocated + /// objects is not known at compile-time. However, the requirement also exists at + /// runtime and may be exploited by optimizations. If you wish to compute the difference between + /// pointers that are not guaranteed to be from the same allocation, use `(self as isize - + /// origin as isize) / mem::size_of::<T>()`. + // FIXME: recommend `addr()` instead of `as usize` once that is stable. + /// /// [`add`]: #method.add /// [allocated object]: crate::ptr#allocated-object /// @@ -875,7 +892,7 @@ impl<T: ?Sized> *mut T { /// units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [offset_from][pointer::offset_from] on it. See that method for + /// using [`offset_from`][pointer::offset_from] on it. See that method for /// documentation and safety requirements. /// /// For non-`Sized` pointees this operation considers only the data pointers, @@ -2064,7 +2081,7 @@ impl<T> *mut [T] { /// /// For the mutable counterpart see [`as_uninit_slice_mut`]. /// - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut /// /// # Safety diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index e0fd347a0..d5bd54fd5 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -43,9 +43,27 @@ use crate::slice::{self, SliceIndex}; /// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr` /// is never used for mutation. /// +/// # Representation +/// +/// Thanks to the [null pointer optimization], +/// `NonNull<T>` and `Option<NonNull<T>>` +/// are guaranteed to have the same size and alignment: +/// +/// ``` +/// # use std::mem::{size_of, align_of}; +/// use std::ptr::NonNull; +/// +/// assert_eq!(size_of::<NonNull<i16>>(), size_of::<Option<NonNull<i16>>>()); +/// assert_eq!(align_of::<NonNull<i16>>(), align_of::<Option<NonNull<i16>>>()); +/// +/// assert_eq!(size_of::<NonNull<str>>(), size_of::<Option<NonNull<str>>>()); +/// assert_eq!(align_of::<NonNull<str>>(), align_of::<Option<NonNull<str>>>()); +/// ``` +/// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html /// [`PhantomData`]: crate::marker::PhantomData /// [`UnsafeCell<T>`]: crate::cell::UnsafeCell +/// [null pointer optimization]: crate::option#representation #[stable(feature = "nonnull", since = "1.25.0")] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] @@ -320,6 +338,7 @@ impl<T: ?Sized> NonNull<T> { /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] #[must_use] #[inline(always)] pub const fn as_ptr(self) -> *mut T { @@ -579,6 +598,7 @@ impl<T> NonNull<[T]> { #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub const fn as_mut_ptr(self) -> *mut T { self.as_non_null_ptr().as_ptr() } diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index f3311f76a..4cfccd2e3 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -10,7 +10,7 @@ use crate::ops; impl [u8] { /// Checks if all bytes in this slice are within the ASCII range. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")] + #[rustc_const_stable(feature = "const_slice_is_ascii", since = "1.74.0")] #[must_use] #[inline] pub const fn is_ascii(&self) -> bool { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d95662afd..a19fcf93c 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -730,6 +730,7 @@ impl<T> [T] { /// [`as_mut_ptr`]: slice::as_mut_ptr #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -760,6 +761,7 @@ impl<T> [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_allow_const_fn_unstable(const_mut_refs)] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] #[inline(always)] #[must_use] pub const fn as_mut_ptr(&mut self) -> *mut T { @@ -3408,7 +3410,7 @@ impl<T> [T] { /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); /// ``` /// - /// Rotate a subslice: + /// Rotating a subslice: /// /// ``` /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index e5f34952c..dfa2d4fd5 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -386,6 +386,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -401,6 +402,7 @@ impl str { /// It is your responsibility to make sure that the string slice only gets /// modified in a way that it remains valid UTF-8. #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] #[must_use] #[inline(always)] pub fn as_mut_ptr(&mut self) -> *mut u8 { @@ -997,7 +999,7 @@ impl str { /// An iterator over the lines of a string. #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.4.0", note = "use lines() instead now")] + #[deprecated(since = "1.4.0", note = "use lines() instead now", suggestion = "lines")] #[inline] #[allow(deprecated)] pub fn lines_any(&self) -> LinesAny<'_> { @@ -2322,7 +2324,7 @@ impl str { /// assert!(!non_ascii.is_ascii()); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")] + #[rustc_const_stable(feature = "const_slice_is_ascii", since = "1.74.0")] #[must_use] #[inline] pub const fn is_ascii(&self) -> bool { diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 22a1c0978..cf1fbe2d3 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1018,6 +1018,7 @@ impl AtomicBool { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub const fn as_ptr(&self) -> *mut bool { self.v.get().cast() } @@ -1953,6 +1954,7 @@ impl<T> AtomicPtr<T> { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub const fn as_ptr(&self) -> *mut *mut T { self.p.get() } @@ -2891,6 +2893,7 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub const fn as_ptr(&self) -> *mut $int_type { self.v.get() } diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index 3f3e19c55..ff538d55c 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -2,6 +2,8 @@ use core::fmt; use core::future::Future; +use core::marker::Tuple; +use core::ops::{Generator, GeneratorState}; use core::pin::Pin; use core::task::{Context, Poll}; @@ -168,10 +170,52 @@ impl<T> From<T> for Exclusive<T> { } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl<T: Future + ?Sized> Future for Exclusive<T> { +impl<F, Args> FnOnce<Args> for Exclusive<F> +where + F: FnOnce<Args>, + Args: Tuple, +{ + type Output = F::Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output { + self.into_inner().call_once(args) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl<F, Args> FnMut<Args> for Exclusive<F> +where + F: FnMut<Args>, + Args: Tuple, +{ + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { + self.get_mut().call_mut(args) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl<T> Future for Exclusive<T> +where + T: Future + ?Sized, +{ type Output = T::Output; + #[inline] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { self.get_pin_mut().poll(cx) } } + +#[unstable(feature = "generator_trait", issue = "43122")] // also #98407 +impl<R, G> Generator<R> for Exclusive<G> +where + G: Generator<R> + ?Sized, +{ + type Yield = G::Yield; + type Return = G::Return; + + #[inline] + fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> { + G::resume(self.get_pin_mut(), arg) + } +} diff --git a/library/core/src/time.rs b/library/core/src/time.rs index b08d5782a..1e8d28979 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -656,10 +656,10 @@ impl Duration { #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")] pub const fn checked_div(self, rhs: u32) -> Option<Duration> { if rhs != 0 { - let secs = self.secs / (rhs as u64); - let carry = self.secs - secs * (rhs as u64); - let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); - let nanos = self.nanos.0 / rhs + (extra_nanos as u32); + let (secs, extra_secs) = (self.secs / (rhs as u64), self.secs % (rhs as u64)); + let (mut nanos, extra_nanos) = (self.nanos.0 / rhs, self.nanos.0 % rhs); + nanos += + ((extra_secs * (NANOS_PER_SEC as u64) + extra_nanos as u64) / (rhs as u64)) as u32; debug_assert!(nanos < NANOS_PER_SEC); Some(Duration::new(secs, nanos)) } else { diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 7782ace69..ff292ff2d 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,4 +1,4 @@ -// See src/libstd/primitive_docs.rs for documentation. +// See core/src/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; use crate::marker::ConstParamTy; diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs index 0a77ecddb..5b87d6c1f 100644 --- a/library/core/tests/iter/range.rs +++ b/library/core/tests/iter/range.rs @@ -1,5 +1,6 @@ -use core::num::NonZeroUsize; use super::*; +use core::ascii::Char as AsciiChar; +use core::num::NonZeroUsize; #[test] fn test_range() { @@ -40,6 +41,21 @@ fn test_char_range() { } #[test] +fn test_ascii_char_range() { + let from = AsciiChar::Null; + let to = AsciiChar::Delete; + assert!((from..=to).eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8))); + assert!((from..=to).rev().eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8).rev())); + + assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).count(), 26); + assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).size_hint(), (26, Some(26))); + assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).count(), 26); + assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).size_hint(), (26, Some(26))); + assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).count(), 10); + assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).size_hint(), (10, Some(10))); +} + +#[test] fn test_range_exhaustion() { let mut r = 10..10; assert!(r.is_empty()); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 7a6def37a..e4003a208 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -2,6 +2,8 @@ #![feature(array_chunks)] #![feature(array_methods)] #![feature(array_windows)] +#![feature(ascii_char)] +#![feature(ascii_char_variants)] #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_align_offset)] @@ -54,6 +56,7 @@ #![feature(min_specialization)] #![feature(numfmt)] #![feature(num_midpoint)] +#![feature(isqrt)] #![feature(step_trait)] #![feature(str_internals)] #![feature(std_internals)] @@ -94,6 +97,7 @@ #![feature(const_option_ext)] #![feature(const_result)] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] +#![cfg_attr(test, feature(cfg_match))] #![feature(int_roundings)] #![feature(slice_group_by)] #![feature(split_array)] @@ -137,6 +141,7 @@ mod hash; mod intrinsics; mod iter; mod lazy; +#[cfg(test)] mod macros; mod manually_drop; mod mem; diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs index ff3632e35..eb886def1 100644 --- a/library/core/tests/macros.rs +++ b/library/core/tests/macros.rs @@ -1,3 +1,25 @@ +trait Trait { + fn blah(&self); +} + +#[allow(dead_code)] +struct Struct; + +impl Trait for Struct { + cfg_match! { + cfg(feature = "blah") => { + fn blah(&self) { + unimplemented!(); + } + } + _ => { + fn blah(&self) { + unimplemented!(); + } + } + } +} + #[test] fn assert_eq_trailing_comma() { assert_eq!(1, 1,); @@ -18,3 +40,135 @@ fn assert_ne_trailing_comma() { fn matches_leading_pipe() { matches!(1, | 1 | 2 | 3); } + +#[test] +fn cfg_match_basic() { + cfg_match! { + cfg(target_pointer_width = "64") => { fn f0_() -> bool { true }} + } + + cfg_match! { + cfg(unix) => { fn f1_() -> bool { true }} + cfg(any(target_os = "macos", target_os = "linux")) => { fn f1_() -> bool { false }} + } + + cfg_match! { + cfg(target_pointer_width = "32") => { fn f2_() -> bool { false }} + cfg(target_pointer_width = "64") => { fn f2_() -> bool { true }} + } + + cfg_match! { + cfg(target_pointer_width = "16") => { fn f3_() -> i32 { 1 }} + _ => { fn f3_() -> i32 { 2 }} + } + + #[cfg(target_pointer_width = "64")] + assert!(f0_()); + + #[cfg(unix)] + assert!(f1_()); + + #[cfg(target_pointer_width = "32")] + assert!(!f2_()); + #[cfg(target_pointer_width = "64")] + assert!(f2_()); + + #[cfg(not(target_pointer_width = "16"))] + assert_eq!(f3_(), 2); +} + +#[test] +fn cfg_match_debug_assertions() { + cfg_match! { + cfg(debug_assertions) => { + assert!(cfg!(debug_assertions)); + assert_eq!(4, 2+2); + } + _ => { + assert!(cfg!(not(debug_assertions))); + assert_eq!(10, 5+5); + } + } +} + +#[cfg(target_pointer_width = "64")] +#[test] +fn cfg_match_no_duplication_on_64() { + cfg_match! { + cfg(windows) => { + fn foo() {} + } + cfg(unix) => { + fn foo() {} + } + cfg(target_pointer_width = "64") => { + fn foo() {} + } + } + foo(); +} + +#[test] +fn cfg_match_options() { + cfg_match! { + cfg(test) => { + use core::option::Option as Option2; + fn works1() -> Option2<u32> { Some(1) } + } + _ => { fn works1() -> Option<u32> { None } } + } + + cfg_match! { + cfg(feature = "foo") => { fn works2() -> bool { false } } + cfg(test) => { fn works2() -> bool { true } } + _ => { fn works2() -> bool { false } } + } + + cfg_match! { + cfg(feature = "foo") => { fn works3() -> bool { false } } + _ => { fn works3() -> bool { true } } + } + + cfg_match! { + cfg(test) => { + use core::option::Option as Option3; + fn works4() -> Option3<u32> { Some(1) } + } + } + + cfg_match! { + cfg(feature = "foo") => { fn works5() -> bool { false } } + cfg(test) => { fn works5() -> bool { true } } + } + + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); +} + +#[test] +fn cfg_match_two_functions() { + cfg_match! { + cfg(target_pointer_width = "64") => { + fn foo1() {} + fn bar1() {} + } + _ => { + fn foo2() {} + fn bar2() {} + } + } + + #[cfg(target_pointer_width = "64")] + { + foo1(); + bar1(); + } + #[cfg(not(target_pointer_width = "64"))] + { + foo2(); + bar2(); + } +} diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 439bbe669..165d9a296 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -291,6 +291,38 @@ macro_rules! int_module { } #[test] + fn test_isqrt() { + assert_eq!($T::MIN.checked_isqrt(), None); + assert_eq!((-1 as $T).checked_isqrt(), None); + assert_eq!((0 as $T).isqrt(), 0 as $T); + assert_eq!((1 as $T).isqrt(), 1 as $T); + assert_eq!((2 as $T).isqrt(), 1 as $T); + assert_eq!((99 as $T).isqrt(), 9 as $T); + assert_eq!((100 as $T).isqrt(), 10 as $T); + } + + #[cfg(not(miri))] // Miri is too slow + #[test] + fn test_lots_of_isqrt() { + let n_max: $T = (1024 * 1024).min($T::MAX as u128) as $T; + for n in 0..=n_max { + let isqrt: $T = n.isqrt(); + + assert!(isqrt.pow(2) <= n); + let (square, overflow) = (isqrt + 1).overflowing_pow(2); + assert!(overflow || square > n); + } + + for n in ($T::MAX - 127)..=$T::MAX { + let isqrt: $T = n.isqrt(); + + assert!(isqrt.pow(2) <= n); + let (square, overflow) = (isqrt + 1).overflowing_pow(2); + assert!(overflow || square > n); + } + } + + #[test] fn test_div_floor() { let a: $T = 8; let b = 3; diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 7d6203db0..955440647 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -207,6 +207,35 @@ macro_rules! uint_module { } #[test] + fn test_isqrt() { + assert_eq!((0 as $T).isqrt(), 0 as $T); + assert_eq!((1 as $T).isqrt(), 1 as $T); + assert_eq!((2 as $T).isqrt(), 1 as $T); + assert_eq!((99 as $T).isqrt(), 9 as $T); + assert_eq!((100 as $T).isqrt(), 10 as $T); + assert_eq!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); + } + + #[cfg(not(miri))] // Miri is too slow + #[test] + fn test_lots_of_isqrt() { + let n_max: $T = (1024 * 1024).min($T::MAX as u128) as $T; + for n in 0..=n_max { + let isqrt: $T = n.isqrt(); + + assert!(isqrt.pow(2) <= n); + assert!(isqrt + 1 == (1 as $T) << ($T::BITS / 2) || (isqrt + 1).pow(2) > n); + } + + for n in ($T::MAX - 255)..=$T::MAX { + let isqrt: $T = n.isqrt(); + + assert!(isqrt.pow(2) <= n); + assert!(isqrt + 1 == (1 as $T) << ($T::BITS / 2) || (isqrt + 1).pow(2) > n); + } + } + + #[test] fn test_div_floor() { assert_eq!((8 as $T).div_floor(3), 2); } diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index 872611937..bd6e63edb 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -170,6 +170,7 @@ fn saturating_mul() { fn div() { assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); + assert_eq!(Duration::new(1, 1) / 7, Duration::new(0, 142_857_143)); assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990)); } |