diff options
| author | Ralf Jung <post@ralfj.de> | 2025-04-02 22:22:18 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-02 22:22:18 +0000 |
| commit | 5103bdeb29d7aa4d7ad4d811893c76baa8a98ab7 (patch) | |
| tree | c989d04f4bcd32bcd93ed62208af68e1dbe36b6d /library/core | |
| parent | 4858c3fe7d1a9a7484db4998199f6deb1e05185a (diff) | |
| parent | e435ba32d85057070dba3f07fa8afd96799a0cfb (diff) | |
Merge pull request #4245 from RalfJung/rustup
Rustup
Diffstat (limited to 'library/core')
24 files changed, 482 insertions, 410 deletions
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 1a320b316a4..e789601a409 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -495,7 +495,7 @@ impl<T> Cell<T> { /// ``` #[inline] #[stable(feature = "move_cell", since = "1.17.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] #[rustc_confusables("swap")] pub const fn replace(&self, val: T) -> T { // SAFETY: This can cause data races if called from a separate thread, @@ -537,7 +537,7 @@ impl<T: Copy> Cell<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] pub const fn get(&self) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. @@ -617,7 +617,7 @@ impl<T: ?Sized> Cell<T> { /// ``` #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] pub const fn get_mut(&mut self) -> &mut T { self.value.get_mut() } @@ -637,7 +637,7 @@ impl<T: ?Sized> Cell<T> { /// ``` #[inline] #[stable(feature = "as_cell", since = "1.37.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] pub const fn from_mut(t: &mut T) -> &Cell<T> { // SAFETY: `&mut` ensures unique access. unsafe { &*(t as *mut T as *const Cell<T>) } @@ -695,7 +695,7 @@ impl<T> Cell<[T]> { /// assert_eq!(slice_cell.len(), 3); /// ``` #[stable(feature = "as_cell", since = "1.37.0")] - #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] pub const fn as_slice_of_cells(&self) -> &[Cell<T>] { // SAFETY: `Cell<T>` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T]> as *const [Cell<T>]) } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 25bd17d5802..0dc2cc72e06 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -29,6 +29,7 @@ mod bytewise; pub(crate) use bytewise::BytewiseEq; use self::Ordering::*; +use crate::ops::ControlFlow; /// Trait for comparisons using the equality operator. /// @@ -1435,6 +1436,67 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { fn ge(&self, other: &Rhs) -> bool { self.partial_cmp(other).is_some_and(Ordering::is_ge) } + + /// If `self == other`, returns `ControlFlow::Continue(())`. + /// Otherwise, returns `ControlFlow::Break(self < other)`. + /// + /// This is useful for chaining together calls when implementing a lexical + /// `PartialOrd::lt`, as it allows types (like primitives) which can cheaply + /// check `==` and `<` separately to do rather than needing to calculate + /// (then optimize out) the three-way `Ordering` result. + #[inline] + #[must_use] + // Added to improve the behaviour of tuples; not necessarily stabilization-track. + #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] + #[doc(hidden)] + fn __chaining_lt(&self, other: &Rhs) -> ControlFlow<bool> { + default_chaining_impl(self, other, Ordering::is_lt) + } + + /// Same as `__chaining_lt`, but for `<=` instead of `<`. + #[inline] + #[must_use] + #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] + #[doc(hidden)] + fn __chaining_le(&self, other: &Rhs) -> ControlFlow<bool> { + default_chaining_impl(self, other, Ordering::is_le) + } + + /// Same as `__chaining_lt`, but for `>` instead of `<`. + #[inline] + #[must_use] + #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] + #[doc(hidden)] + fn __chaining_gt(&self, other: &Rhs) -> ControlFlow<bool> { + default_chaining_impl(self, other, Ordering::is_gt) + } + + /// Same as `__chaining_lt`, but for `>=` instead of `<`. + #[inline] + #[must_use] + #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] + #[doc(hidden)] + fn __chaining_ge(&self, other: &Rhs) -> ControlFlow<bool> { + default_chaining_impl(self, other, Ordering::is_ge) + } +} + +fn default_chaining_impl<T: ?Sized, U: ?Sized>( + lhs: &T, + rhs: &U, + p: impl FnOnce(Ordering) -> bool, +) -> ControlFlow<bool> +where + T: PartialOrd<U>, +{ + // It's important that this only call `partial_cmp` once, not call `eq` then + // one of the relational operators. We don't want to `bcmp`-then-`memcp` a + // `String`, for example, or similarly for other data structures (#108157). + match <T as PartialOrd<U>>::partial_cmp(lhs, rhs) { + Some(Equal) => ControlFlow::Continue(()), + Some(c) => ControlFlow::Break(p(c)), + None => ControlFlow::Break(false), + } } /// Derive macro generating an impl of the trait [`PartialOrd`]. @@ -1741,15 +1803,16 @@ where mod impls { use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::hint::unreachable_unchecked; + use crate::ops::ControlFlow::{self, Break, Continue}; macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for $t { #[inline] - fn eq(&self, other: &$t) -> bool { (*self) == (*other) } + fn eq(&self, other: &Self) -> bool { *self == *other } #[inline] - fn ne(&self, other: &$t) -> bool { (*self) != (*other) } + fn ne(&self, other: &Self) -> bool { *self != *other } } )*) } @@ -1779,12 +1842,51 @@ mod impls { eq_impl! { () bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + #[rustfmt::skip] + macro_rules! partial_ord_methods_primitive_impl { + () => { + #[inline(always)] + fn lt(&self, other: &Self) -> bool { *self < *other } + #[inline(always)] + fn le(&self, other: &Self) -> bool { *self <= *other } + #[inline(always)] + fn gt(&self, other: &Self) -> bool { *self > *other } + #[inline(always)] + fn ge(&self, other: &Self) -> bool { *self >= *other } + + // These implementations are the same for `Ord` or `PartialOrd` types + // because if either is NAN the `==` test will fail so we end up in + // the `Break` case and the comparison will correctly return `false`. + + #[inline] + fn __chaining_lt(&self, other: &Self) -> ControlFlow<bool> { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs < rhs) } + } + #[inline] + fn __chaining_le(&self, other: &Self) -> ControlFlow<bool> { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs <= rhs) } + } + #[inline] + fn __chaining_gt(&self, other: &Self) -> ControlFlow<bool> { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs > rhs) } + } + #[inline] + fn __chaining_ge(&self, other: &Self) -> ControlFlow<bool> { + let (lhs, rhs) = (*self, *other); + if lhs == rhs { Continue(()) } else { Break(lhs >= rhs) } + } + }; + } + macro_rules! partial_ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for $t { #[inline] - fn partial_cmp(&self, other: &$t) -> Option<Ordering> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { match (*self <= *other, *self >= *other) { (false, false) => None, (false, true) => Some(Greater), @@ -1792,14 +1894,8 @@ mod impls { (true, true) => Some(Equal), } } - #[inline(always)] - fn lt(&self, other: &$t) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &$t) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &$t) -> bool { (*self) > (*other) } + + partial_ord_methods_primitive_impl!(); } )*) } @@ -1818,6 +1914,8 @@ mod impls { fn partial_cmp(&self, other: &bool) -> Option<Ordering> { Some(self.cmp(other)) } + + partial_ord_methods_primitive_impl!(); } partial_ord_impl! { f16 f32 f64 f128 } @@ -1827,23 +1925,17 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for $t { #[inline] - fn partial_cmp(&self, other: &$t) -> Option<Ordering> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(crate::intrinsics::three_way_compare(*self, *other)) } - #[inline(always)] - fn lt(&self, other: &$t) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &$t) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &$t) -> bool { (*self) > (*other) } + + partial_ord_methods_primitive_impl!(); } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for $t { #[inline] - fn cmp(&self, other: &$t) -> Ordering { + fn cmp(&self, other: &Self) -> Ordering { crate::intrinsics::three_way_compare(*self, *other) } } diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs index 0a70eb4da55..351bf9f8314 100644 --- a/library/core/src/ffi/primitives.rs +++ b/library/core/src/ffi/primitives.rs @@ -35,7 +35,7 @@ type_alias! { "c_float.md", c_float = f32; } type_alias! { "c_double.md", c_double = f64; } mod c_char_definition { - cfg_if! { + crate::cfg_match! { // These are the targets on which c_char is unsigned. Usually the // signedness is the same for all target_os values on a given architecture // but there are some exceptions (see isSignedCharDefault() in clang). @@ -105,7 +105,7 @@ mod c_char_definition { // architecture defaults). As we only have a target for userspace apps so there are no // special cases for L4Re below. // https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240 - if #[cfg(all( + all( not(windows), not(target_vendor = "apple"), not(target_os = "vita"), @@ -122,24 +122,27 @@ mod c_char_definition { target_arch = "s390x", target_arch = "xtensa", ) - ))] { + ) => { pub(super) type c_char = u8; - } else { - // On every other target, c_char is signed. + } + // On every other target, c_char is signed. + _ => { pub(super) type c_char = i8; } } } mod c_long_definition { - cfg_if! { - if #[cfg(any( + crate::cfg_match! { + any( all(target_pointer_width = "64", not(windows)), // wasm32 Linux ABI uses 64-bit long - all(target_arch = "wasm32", target_os = "linux")))] { + all(target_arch = "wasm32", target_os = "linux") + ) => { pub(super) type c_long = i64; pub(super) type c_ulong = u64; - } else { + } + _ => { // The minimal size of `long` in the C standard is 32 bits pub(super) type c_long = i32; pub(super) type c_ulong = u32; @@ -169,11 +172,12 @@ pub type c_ptrdiff_t = isize; pub type c_ssize_t = isize; mod c_int_definition { - cfg_if! { - if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] { + crate::cfg_match! { + any(target_arch = "avr", target_arch = "msp430") => { pub(super) type c_int = i16; pub(super) type c_uint = u16; - } else { + } + _ => { pub(super) type c_int = i32; pub(super) type c_uint = u32; } diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 4a43c12be9a..870ad9df4fd 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -86,7 +86,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { float_to_decimal_common_exact(fmt, num, sign, precision) } else { let min_precision = 0; @@ -162,7 +162,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { // 1 integral digit + `precision` fractional digits = `precision + 1` total digits float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper) } else { @@ -180,7 +180,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { // this behavior of {:.PREC?} predates exponential formatting for {:?} float_to_decimal_common_exact(fmt, num, sign, precision) } else { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 48f36044471..30fd2d7815f 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -33,19 +33,6 @@ pub enum Alignment { Center, } -#[doc(hidden)] -#[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] -impl From<rt::Alignment> for Option<Alignment> { - fn from(value: rt::Alignment) -> Self { - match value { - rt::Alignment::Left => Some(Alignment::Left), - rt::Alignment::Right => Some(Alignment::Right), - rt::Alignment::Center => Some(Alignment::Center), - rt::Alignment::Unknown => None, - } - } -} - #[stable(feature = "debug_builders", since = "1.2.0")] pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[unstable(feature = "debug_closure_helpers", issue = "117729")] @@ -291,11 +278,52 @@ pub enum DebugAsHex { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "formatting_options", issue = "118117")] pub struct FormattingOptions { + /// Flags, with the following bit fields: + /// + /// ```text + /// 31 30 29 28 27 26 25 24 23 22 21 20 0 + /// ┌───┬───────┬───┬───┬───┬───┬───┬───┬───┬───┬──────────────────────────────────┐ + /// │ 1 │ align │ p │ w │ X?│ x?│'0'│ # │ - │ + │ fill │ + /// └───┴───────┴───┴───┴───┴───┴───┴───┴───┴───┴──────────────────────────────────┘ + /// │ │ │ │ └─┬───────────────────┘ └─┬──────────────────────────────┘ + /// │ │ │ │ │ └─ The fill character (21 bits char). + /// │ │ │ │ └─ The debug upper/lower hex, zero pad, alternate, and plus/minus flags. + /// │ │ │ └─ Whether a width is set. (The value is stored separately.) + /// │ │ └─ Whether a precision is set. (The value is stored separately.) + /// │ ├─ 0: Align left. (<) + /// │ ├─ 1: Align right. (>) + /// │ ├─ 2: Align center. (^) + /// │ └─ 3: Alignment not set. (default) + /// └─ Always set. + /// This makes it possible to distinguish formatting flags from + /// a &str size when stored in (the upper bits of) the same field. + /// (fmt::Arguments will make use of this property in the future.) + /// ``` + // Note: This could use a special niche type with range 0x8000_0000..=0xfdd0ffff. + // It's unclear if that's useful, though. flags: u32, - fill: char, - align: Option<Alignment>, - width: Option<u16>, - precision: Option<u16>, + /// Width if width flag (bit 27) above is set. Otherwise, always 0. + width: u16, + /// Precision if precision flag (bit 28) above is set. Otherwise, always 0. + precision: u16, +} + +// This needs to match with compiler/rustc_ast_lowering/src/format.rs. +mod flags { + pub(super) const SIGN_PLUS_FLAG: u32 = 1 << 21; + pub(super) const SIGN_MINUS_FLAG: u32 = 1 << 22; + pub(super) const ALTERNATE_FLAG: u32 = 1 << 23; + pub(super) const SIGN_AWARE_ZERO_PAD_FLAG: u32 = 1 << 24; + pub(super) const DEBUG_LOWER_HEX_FLAG: u32 = 1 << 25; + pub(super) const DEBUG_UPPER_HEX_FLAG: u32 = 1 << 26; + pub(super) const WIDTH_FLAG: u32 = 1 << 27; + pub(super) const PRECISION_FLAG: u32 = 1 << 28; + pub(super) const ALIGN_BITS: u32 = 0b11 << 29; + pub(super) const ALIGN_LEFT: u32 = 0 << 29; + pub(super) const ALIGN_RIGHT: u32 = 1 << 29; + pub(super) const ALIGN_CENTER: u32 = 2 << 29; + pub(super) const ALIGN_UNKNOWN: u32 = 3 << 29; + pub(super) const ALWAYS_SET: u32 = 1 << 31; } impl FormattingOptions { @@ -311,7 +339,11 @@ impl FormattingOptions { /// - no [`DebugAsHex`] output mode. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn new() -> Self { - Self { flags: 0, fill: ' ', align: None, width: None, precision: None } + Self { + flags: ' ' as u32 | flags::ALIGN_UNKNOWN | flags::ALWAYS_SET, + width: 0, + precision: 0, + } } /// Sets or removes the sign (the `+` or the `-` flag). @@ -324,13 +356,12 @@ impl FormattingOptions { /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self { - self.flags = - self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); - match sign { - None => {} - Some(Sign::Plus) => self.flags |= 1 << rt::Flag::SignPlus as u32, - Some(Sign::Minus) => self.flags |= 1 << rt::Flag::SignMinus as u32, - } + let sign = match sign { + None => 0, + Some(Sign::Plus) => flags::SIGN_PLUS_FLAG, + Some(Sign::Minus) => flags::SIGN_MINUS_FLAG, + }; + self.flags = self.flags & !(flags::SIGN_PLUS_FLAG | flags::SIGN_MINUS_FLAG) | sign; self } /// Sets or unsets the `0` flag. @@ -339,9 +370,9 @@ impl FormattingOptions { #[unstable(feature = "formatting_options", issue = "118117")] pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { if sign_aware_zero_pad { - self.flags |= 1 << rt::Flag::SignAwareZeroPad as u32 + self.flags |= flags::SIGN_AWARE_ZERO_PAD_FLAG; } else { - self.flags &= !(1 << rt::Flag::SignAwareZeroPad as u32) + self.flags &= !flags::SIGN_AWARE_ZERO_PAD_FLAG; } self } @@ -356,9 +387,9 @@ impl FormattingOptions { #[unstable(feature = "formatting_options", issue = "118117")] pub fn alternate(&mut self, alternate: bool) -> &mut Self { if alternate { - self.flags |= 1 << rt::Flag::Alternate as u32 + self.flags |= flags::ALTERNATE_FLAG; } else { - self.flags &= !(1 << rt::Flag::Alternate as u32) + self.flags &= !flags::ALTERNATE_FLAG; } self } @@ -370,7 +401,7 @@ impl FormattingOptions { /// printed around it. #[unstable(feature = "formatting_options", issue = "118117")] pub fn fill(&mut self, fill: char) -> &mut Self { - self.fill = fill; + self.flags = self.flags & (u32::MAX << 21) | fill as u32; self } /// Sets or removes the alignment. @@ -379,7 +410,13 @@ impl FormattingOptions { /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] pub fn align(&mut self, align: Option<Alignment>) -> &mut Self { - self.align = align; + let align: u32 = match align { + Some(Alignment::Left) => flags::ALIGN_LEFT, + Some(Alignment::Right) => flags::ALIGN_RIGHT, + Some(Alignment::Center) => flags::ALIGN_CENTER, + None => flags::ALIGN_UNKNOWN, + }; + self.flags = self.flags & !flags::ALIGN_BITS | align; self } /// Sets or removes the width. @@ -390,7 +427,13 @@ impl FormattingOptions { /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] pub fn width(&mut self, width: Option<u16>) -> &mut Self { - self.width = width; + if let Some(width) = width { + self.flags |= flags::WIDTH_FLAG; + self.width = width; + } else { + self.flags &= !flags::WIDTH_FLAG; + self.width = 0; + } self } /// Sets or removes the precision. @@ -404,77 +447,85 @@ impl FormattingOptions { /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] pub fn precision(&mut self, precision: Option<u16>) -> &mut Self { - self.precision = precision; + if let Some(precision) = precision { + self.flags |= flags::PRECISION_FLAG; + self.precision = precision; + } else { + self.flags &= !flags::PRECISION_FLAG; + self.precision = 0; + } self } /// Specifies whether the [`Debug`] trait should use lower-/upper-case /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self { - self.flags = self.flags - & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); - match debug_as_hex { - None => {} - Some(DebugAsHex::Upper) => self.flags |= 1 << rt::Flag::DebugUpperHex as u32, - Some(DebugAsHex::Lower) => self.flags |= 1 << rt::Flag::DebugLowerHex as u32, - } + let debug_as_hex = match debug_as_hex { + None => 0, + Some(DebugAsHex::Lower) => flags::DEBUG_LOWER_HEX_FLAG, + Some(DebugAsHex::Upper) => flags::DEBUG_UPPER_HEX_FLAG, + }; + self.flags = self.flags & !(flags::DEBUG_LOWER_HEX_FLAG | flags::DEBUG_UPPER_HEX_FLAG) + | debug_as_hex; self } /// Returns the current sign (the `+` or the `-` flag). #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign(&self) -> Option<Sign> { - const SIGN_PLUS_BITFIELD: u32 = 1 << rt::Flag::SignPlus as u32; - const SIGN_MINUS_BITFIELD: u32 = 1 << rt::Flag::SignMinus as u32; - match self.flags & ((1 << rt::Flag::SignPlus as u32) | (1 << rt::Flag::SignMinus as u32)) { - SIGN_PLUS_BITFIELD => Some(Sign::Plus), - SIGN_MINUS_BITFIELD => Some(Sign::Minus), - 0 => None, - _ => panic!("Invalid sign bits set in flags"), + if self.flags & flags::SIGN_PLUS_FLAG != 0 { + Some(Sign::Plus) + } else if self.flags & flags::SIGN_MINUS_FLAG != 0 { + Some(Sign::Minus) + } else { + None } } /// Returns the current `0` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign_aware_zero_pad(&self) -> bool { - self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 + self.flags & flags::SIGN_AWARE_ZERO_PAD_FLAG != 0 } /// Returns the current `#` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_alternate(&self) -> bool { - self.flags & (1 << rt::Flag::Alternate as u32) != 0 + self.flags & flags::ALTERNATE_FLAG != 0 } /// Returns the current fill character. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_fill(&self) -> char { - self.fill + // SAFETY: We only ever put a valid `char` in the lower 21 bits of the flags field. + unsafe { char::from_u32_unchecked(self.flags & 0x1FFFFF) } } /// Returns the current alignment. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_align(&self) -> Option<Alignment> { - self.align + match self.flags & flags::ALIGN_BITS { + flags::ALIGN_LEFT => Some(Alignment::Left), + flags::ALIGN_RIGHT => Some(Alignment::Right), + flags::ALIGN_CENTER => Some(Alignment::Center), + _ => None, + } } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_width(&self) -> Option<u16> { - self.width + if self.flags & flags::WIDTH_FLAG != 0 { Some(self.width) } else { None } } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_precision(&self) -> Option<u16> { - self.precision + if self.flags & flags::PRECISION_FLAG != 0 { Some(self.precision) } else { None } } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_debug_as_hex(&self) -> Option<DebugAsHex> { - const DEBUG_UPPER_BITFIELD: u32 = 1 << rt::Flag::DebugUpperHex as u32; - const DEBUG_LOWER_BITFIELD: u32 = 1 << rt::Flag::DebugLowerHex as u32; - match self.flags - & ((1 << rt::Flag::DebugUpperHex as u32) | (1 << rt::Flag::DebugLowerHex as u32)) - { - DEBUG_UPPER_BITFIELD => Some(DebugAsHex::Upper), - DEBUG_LOWER_BITFIELD => Some(DebugAsHex::Lower), - 0 => None, - _ => panic!("Invalid hex debug bits set in flags"), + if self.flags & flags::DEBUG_LOWER_HEX_FLAG != 0 { + Some(DebugAsHex::Lower) + } else if self.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 { + Some(DebugAsHex::Upper) + } else { + None } } @@ -485,27 +536,6 @@ impl FormattingOptions { pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { options: self, buf: write } } - - #[doc(hidden)] - #[unstable( - feature = "fmt_internals", - reason = "internal routines only exposed for testing", - issue = "none" - )] - /// Flags for formatting - pub fn flags(&mut self, flags: u32) { - self.flags = flags - } - #[doc(hidden)] - #[unstable( - feature = "fmt_internals", - reason = "internal routines only exposed for testing", - issue = "none" - )] - /// Flags for formatting - pub fn get_flags(&self) -> u32 { - self.flags - } } #[unstable(feature = "formatting_options", issue = "118117")] @@ -1479,15 +1509,25 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { } unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { - fmt.options.fill = arg.fill; - fmt.options.align = arg.align.into(); - fmt.options.flags = arg.flags; - // SAFETY: arg and args come from the same Arguments, - // which guarantees the indexes are always within bounds. - unsafe { - fmt.options.width = getcount(args, &arg.width); - fmt.options.precision = getcount(args, &arg.precision); - } + let (width, precision) = + // SAFETY: arg and args come from the same Arguments, + // which guarantees the indexes are always within bounds. + unsafe { (getcount(args, &arg.width), getcount(args, &arg.precision)) }; + + #[cfg(bootstrap)] + let options = + *FormattingOptions { flags: flags::ALWAYS_SET | arg.flags << 21, width: 0, precision: 0 } + .align(match arg.align { + rt::Alignment::Left => Some(Alignment::Left), + rt::Alignment::Right => Some(Alignment::Right), + rt::Alignment::Center => Some(Alignment::Center), + rt::Alignment::Unknown => None, + }) + .fill(arg.fill) + .width(width) + .precision(precision); + #[cfg(not(bootstrap))] + let options = FormattingOptions { flags: arg.flags, width, precision }; // Extract the correct argument debug_assert!(arg.position < args.len()); @@ -1495,17 +1535,18 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume // which guarantees its index is always within bounds. let value = unsafe { args.get_unchecked(arg.position) }; + // Set all the formatting options. + fmt.options = options; + // Then actually do some printing // SAFETY: this is a placeholder argument. unsafe { value.fmt(fmt) } } +#[cfg(bootstrap)] unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<u16> { match *cnt { - #[cfg(bootstrap)] rt::Count::Is(n) => Some(n as u16), - #[cfg(not(bootstrap))] - rt::Count::Is(n) => Some(n), rt::Count::Implied => None, rt::Count::Param(i) => { debug_assert!(i < args.len()); @@ -1516,6 +1557,20 @@ unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<u16> { } } +#[cfg(not(bootstrap))] +unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> u16 { + match *cnt { + rt::Count::Is(n) => n, + rt::Count::Implied => 0, + rt::Count::Param(i) => { + debug_assert!(i < args.len()); + // SAFETY: cnt and args come from the same Arguments, + // which guarantees this index is always within bounds. + unsafe { args.get_unchecked(i).as_u16().unwrap_unchecked() } + } + } +} + /// Padding after the end of something. Returned by `Formatter::padding`. #[must_use = "don't forget to write the post padding"] pub(crate) struct PostPadding { @@ -1629,40 +1684,28 @@ impl<'a> Formatter<'a> { } // The `width` field is more of a `min-width` parameter at this point. - match self.options.width { - // If there's no minimum length requirements then we can just - // write the bytes. - None => { - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf) - } - // Check if we're over the minimum width, if so then we can also - // just write the bytes. - Some(min) if width >= usize::from(min) => { - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf) - } + let min = self.options.width; + if width >= usize::from(min) { + // We're over the minimum width, so then we can just write the bytes. + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf) + } else if self.sign_aware_zero_pad() { // The sign and prefix goes before the padding if the fill character // is zero - Some(min) if self.sign_aware_zero_pad() => { - let old_fill = crate::mem::replace(&mut self.options.fill, '0'); - let old_align = - crate::mem::replace(&mut self.options.align, Some(Alignment::Right)); - write_prefix(self, sign, prefix)?; - let post_padding = self.padding(min - width as u16, Alignment::Right)?; - self.buf.write_str(buf)?; - post_padding.write(self)?; - self.options.fill = old_fill; - self.options.align = old_align; - Ok(()) - } + let old_options = self.options; + self.options.fill('0').align(Some(Alignment::Right)); + write_prefix(self, sign, prefix)?; + let post_padding = self.padding(min - width as u16, Alignment::Right)?; + self.buf.write_str(buf)?; + post_padding.write(self)?; + self.options = old_options; + Ok(()) + } else { // Otherwise, the sign and prefix goes after the padding - Some(min) => { - let post_padding = self.padding(min - width as u16, Alignment::Right)?; - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf)?; - post_padding.write(self) - } + let post_padding = self.padding(min - width as u16, Alignment::Right)?; + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf)?; + post_padding.write(self) } } @@ -1698,13 +1741,13 @@ impl<'a> Formatter<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front. - if self.options.width.is_none() && self.options.precision.is_none() { + if self.options.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { return self.buf.write_str(s); } // The `precision` field can be interpreted as a maximum width for the // string being formatted. - let (s, char_count) = if let Some(max_char_count) = self.options.precision { + let (s, char_count) = if let Some(max_char_count) = self.options.get_precision() { let mut iter = s.char_indices(); let remaining = match iter.advance_by(usize::from(max_char_count)) { Ok(()) => 0, @@ -1720,12 +1763,11 @@ impl<'a> Formatter<'a> { }; // The `width` field is more of a minimum width parameter at this point. - if let Some(width) = self.options.width - && char_count < usize::from(width) - { + if char_count < usize::from(self.options.width) { // If we're under the minimum width, then fill up the minimum width // with the specified string + some alignment. - let post_padding = self.padding(width - char_count as u16, Alignment::Left)?; + let post_padding = + self.padding(self.options.width - char_count as u16, Alignment::Left)?; self.buf.write_str(s)?; post_padding.write(self) } else { @@ -1744,19 +1786,20 @@ impl<'a> Formatter<'a> { padding: u16, default: Alignment, ) -> result::Result<PostPadding, Error> { - let align = self.align().unwrap_or(default); + let align = self.options.get_align().unwrap_or(default); + let fill = self.options.get_fill(); - let (pre_pad, post_pad) = match align { - Alignment::Left => (0, padding), - Alignment::Right => (padding, 0), - Alignment::Center => (padding / 2, (padding + 1) / 2), + let padding_left = match align { + Alignment::Left => 0, + Alignment::Right => padding, + Alignment::Center => padding / 2, }; - for _ in 0..pre_pad { - self.buf.write_char(self.options.fill)?; + for _ in 0..padding_left { + self.buf.write_char(fill)?; } - Ok(PostPadding::new(self.options.fill, post_pad)) + Ok(PostPadding::new(fill, padding - padding_left)) } /// Takes the formatted parts and applies the padding. @@ -1768,12 +1811,16 @@ impl<'a> Formatter<'a> { /// /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { - if let Some(mut width) = self.options.width { + if self.options.width == 0 { + // this is the common case and we take a shortcut + // SAFETY: Per the precondition. + unsafe { self.write_formatted_parts(formatted) } + } else { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. let mut formatted = formatted.clone(); - let old_fill = self.options.fill; - let old_align = self.options.align; + let mut width = self.options.width; + let old_options = self.options; if self.sign_aware_zero_pad() { // a sign always goes first let sign = formatted.sign; @@ -1782,8 +1829,7 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; width = width.saturating_sub(sign.len() as u16); - self.options.fill = '0'; - self.options.align = Some(Alignment::Right); + self.options.fill('0').align(Some(Alignment::Right)); } // remaining parts go through the ordinary padding process. @@ -1800,13 +1846,8 @@ impl<'a> Formatter<'a> { } post_padding.write(self) }; - self.options.fill = old_fill; - self.options.align = old_align; + self.options = old_options; ret - } else { - // this is the common case and we take a shortcut - // SAFETY: Per the precondition. - unsafe { self.write_formatted_parts(formatted) } } } @@ -1927,7 +1968,9 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead" )] pub fn flags(&self) -> u32 { - self.options.flags + // Extract the debug upper/lower hex, zero pad, alternate, and plus/minus flags + // to stay compatible with older versions of Rust. + self.options.flags >> 21 & 0x3F } /// Returns the character used as 'fill' whenever there is alignment. @@ -1960,7 +2003,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { - self.options.fill + self.options.get_fill() } /// Returns a flag indicating what form of alignment was requested. @@ -1995,7 +2038,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option<Alignment> { - self.options.align + self.options.get_align() } /// Returns the optionally specified integer width that the output should be. @@ -2025,7 +2068,11 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option<usize> { - self.options.width.map(|x| x as usize) + if self.options.flags & flags::WIDTH_FLAG == 0 { + None + } else { + Some(self.options.width as usize) + } } /// Returns the optionally specified precision for numeric types. @@ -2056,7 +2103,11 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option<usize> { - self.options.precision.map(|x| x as usize) + if self.options.flags & flags::PRECISION_FLAG == 0 { + None + } else { + Some(self.options.precision as usize) + } } /// Determines if the `+` flag was specified. @@ -2088,7 +2139,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignPlus as u32) != 0 + self.options.flags & flags::SIGN_PLUS_FLAG != 0 } /// Determines if the `-` flag was specified. @@ -2117,7 +2168,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignMinus as u32) != 0 + self.options.flags & flags::SIGN_MINUS_FLAG != 0 } /// Determines if the `#` flag was specified. @@ -2145,7 +2196,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.options.flags & (1 << rt::Flag::Alternate as u32) != 0 + self.options.flags & flags::ALTERNATE_FLAG != 0 } /// Determines if the `0` flag was specified. @@ -2171,17 +2222,16 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 + self.options.flags & flags::SIGN_AWARE_ZERO_PAD_FLAG != 0 } // FIXME: Decide what public API we want for these two flags. // https://github.com/rust-lang/rust/issues/48584 fn debug_lower_hex(&self) -> bool { - self.options.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 + self.options.flags & flags::DEBUG_LOWER_HEX_FLAG != 0 } - fn debug_upper_hex(&self) -> bool { - self.options.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 + self.options.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 } /// Creates a [`DebugStruct`] builder designed to assist with creation of @@ -2761,7 +2811,7 @@ impl Debug for char { #[stable(feature = "rust1", since = "1.0.0")] impl Display for char { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - if f.options.width.is_none() && f.options.precision.is_none() { + if f.options.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; MAX_LEN_UTF8])) @@ -2792,26 +2842,24 @@ impl<T: ?Sized> Pointer for *const T { /// /// [problematic]: https://github.com/rust-lang/rust/issues/95489 pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result { - let old_width = f.options.width; - let old_flags = f.options.flags; + let old_options = f.options; // The alternate flag is already treated by LowerHex as being special- // it denotes whether to prefix with 0x. We use it to work out whether // or not to zero extend, and then unconditionally set it to get the // prefix. - if f.alternate() { - f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); + if f.options.get_alternate() { + f.options.sign_aware_zero_pad(true); - if f.options.width.is_none() { - f.options.width = Some((usize::BITS / 4) as u16 + 2); + if f.options.get_width().is_none() { + f.options.width(Some((usize::BITS / 4) as u16 + 2)); } } - f.options.flags |= 1 << (rt::Flag::Alternate as u32); + f.options.alternate(true); let ret = LowerHex::fmt(&ptr_addr, f); - f.options.width = old_width; - f.options.flags = old_flags; + f.options = old_options; ret } diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 080fc6ddfc9..0b04ebccae2 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -11,13 +11,16 @@ use crate::ptr::NonNull; #[derive(Copy, Clone)] pub struct Placeholder { pub position: usize, + #[cfg(bootstrap)] pub fill: char, + #[cfg(bootstrap)] pub align: Alignment, pub flags: u32, pub precision: Count, pub width: Count, } +#[cfg(bootstrap)] impl Placeholder { #[inline] pub const fn new( @@ -32,6 +35,7 @@ impl Placeholder { } } +#[cfg(bootstrap)] #[lang = "format_alignment"] #[derive(Copy, Clone, PartialEq, Eq)] pub enum Alignment { @@ -58,17 +62,6 @@ pub enum Count { Implied, } -// This needs to match the order of flags in compiler/rustc_ast_lowering/src/format.rs. -#[derive(Copy, Clone)] -pub(super) enum Flag { - SignPlus, - SignMinus, - Alternate, - SignAwareZeroPad, - DebugLowerHex, - DebugUpperHex, -} - #[derive(Copy, Clone)] enum ArgumentType<'a> { Placeholder { diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs index fe4fa80263c..2aaefba2468 100644 --- a/library/core/src/internal_macros.rs +++ b/library/core/src/internal_macros.rs @@ -120,80 +120,3 @@ macro_rules! impl_fn_for_zst { )+ } } - -/// A macro for defining `#[cfg]` if-else statements. -/// -/// `cfg_if` 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. -/// -/// # Example -/// -/// ```ignore(cannot-test-this-because-non-exported-macro) -/// cfg_if! { -/// if #[cfg(unix)] { -/// fn foo() { /* unix specific functionality */ } -/// } else if #[cfg(target_pointer_width = "32")] { -/// fn foo() { /* non-unix, 32-bit functionality */ } -/// } else { -/// fn foo() { /* fallback implementation */ } -/// } -/// } -/// -/// # fn main() {} -/// ``` -// This is a copy of `cfg_if!` from the `cfg_if` crate. -// The recursive invocations should use $crate if this is ever exported. -macro_rules! cfg_if { - // match if/else chains with a final `else` - ( - $( - if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* } - ) else+ - else { $( $e_tokens:tt )* } - ) => { - cfg_if! { - @__items () ; - $( - (( $i_meta ) ( $( $i_tokens )* )) , - )+ - (() ( $( $e_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:tt )* )) , - $( $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_if! { @__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_if! { - @__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:tt )* ) => { - $( $tokens )* - }; -} diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index cf03c07b6a5..81e59a1f349 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3002,6 +3002,7 @@ pub const fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discrimina /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. +/// Returns `1` if unwinding occurred and `catch_fn` was called; returns `0` otherwise. /// /// `catch_fn` must not unwind. /// diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 9b9353b800a..a820045521b 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -172,61 +172,6 @@ where } } -/// Marker trait for iterators/iterables which have a statically known upper -/// bound of the number of items they can produce. -/// -/// # Safety -/// -/// Implementations must not yield more elements than indicated by UPPER_BOUND if it is `Some`. -/// Used in specializations. Implementations must not be conditional on lifetimes or -/// user-implementable traits. -#[rustc_specialization_trait] -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe trait BoundedSize { - const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(1); -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<T> BoundedSize for Option<T> {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<T> BoundedSize for option::IntoIter<T> {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<T, U> BoundedSize for Result<T, U> {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<T> BoundedSize for result::IntoIter<T> {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<T> BoundedSize for Once<T> {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<T> BoundedSize for OnceWith<T> {} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<T, const N: usize> BoundedSize for [T; N] { - const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(N); -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<T, const N: usize> BoundedSize for array::IntoIter<T, N> { - const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(N); -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: BoundedSize, P> BoundedSize for Filter<I, P> { - const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND; -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: BoundedSize, P> BoundedSize for FilterMap<I, P> { - const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND; -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: BoundedSize, F> BoundedSize for Map<I, F> { - const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND; -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: BoundedSize> BoundedSize for Copied<I> { - const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND; -} -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: BoundedSize> BoundedSize for Cloned<I> { - const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND; -} - /// An iterator that flattens one level of nesting in an iterator of things /// that can be turned into iterators. /// diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index cc089c617c0..ada37b9af4c 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -1,7 +1,8 @@ use crate::fmt; use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator}; -use crate::mem::{self, MaybeUninit}; +use crate::mem::MaybeUninit; use crate::num::NonZero; +use crate::ops::{NeverShortCircuit, Try}; /// Creates a new iterator that repeats a single element a given number of times. /// @@ -95,10 +96,10 @@ impl<A> RepeatN<A> { fn take_element(&mut self) -> Option<A> { if self.count > 0 { self.count = 0; - let element = mem::replace(&mut self.element, MaybeUninit::uninit()); // SAFETY: We just set count to zero so it won't be dropped again, // and it used to be non-zero so it hasn't already been dropped. - unsafe { Some(element.assume_init()) } + let element = unsafe { self.element.assume_init_read() }; + Some(element) } else { None } @@ -169,6 +170,39 @@ impl<A: Clone> Iterator for RepeatN<A> { } } + fn try_fold<B, F, R>(&mut self, mut acc: B, mut f: F) -> R + where + F: FnMut(B, A) -> R, + R: Try<Output = B>, + { + if self.count > 0 { + while self.count > 1 { + self.count -= 1; + // SAFETY: the count was larger than 1, so the element is + // initialized and hasn't been dropped. + acc = f(acc, unsafe { self.element.assume_init_ref().clone() })?; + } + + // We could just set the count to zero directly, but doing it this + // way should make it easier for the optimizer to fold this tail + // into the loop when `clone()` is equivalent to copying. + self.count -= 1; + // SAFETY: we just set the count to zero from one, so the element + // is still initialized, has not been dropped yet and will not be + // accessed by future calls. + f(acc, unsafe { self.element.assume_init_read() }) + } else { + try { acc } + } + } + + fn fold<B, F>(mut self, init: B, f: F) -> B + where + F: FnMut(B, A) -> B, + { + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + #[inline] fn last(mut self) -> Option<A> { self.take_element() @@ -203,6 +237,23 @@ impl<A: Clone> DoubleEndedIterator for RepeatN<A> { fn nth_back(&mut self, n: usize) -> Option<A> { self.nth(n) } + + #[inline] + fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, A) -> R, + R: Try<Output = B>, + { + self.try_fold(init, f) + } + + #[inline] + fn rfold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, A) -> B, + { + self.fold(init, f) + } } #[stable(feature = "iter_repeat_n", since = "1.82.0")] @@ -220,7 +271,7 @@ impl<A: Clone> UncheckedIterator for RepeatN<A> { // SAFETY: the check above ensured that the count used to be non-zero, // so element hasn't been dropped yet, and we just lowered the count to // zero so it won't be dropped later, and thus it's okay to take it here. - unsafe { mem::replace(&mut self.element, MaybeUninit::uninit()).assume_init() } + unsafe { self.element.assume_init_read() } } else { // SAFETY: the count is non-zero, so it must have not been dropped yet. let element = unsafe { self.element.assume_init_ref() }; diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 5b7d95c2f65..12e2b8b393a 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -10,7 +10,7 @@ use crate::num::Wrapping; /// [`sum()`]: Iterator::sum /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "a value of type `{Self}` cannot be made by summing an iterator over elements of type `{A}`", label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator<Item={A}>`" )] @@ -31,7 +31,7 @@ pub trait Sum<A = Self>: Sized { /// [`product()`]: Iterator::product /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] -#[rustc_on_unimplemented( +#[diagnostic::on_unimplemented( message = "a value of type `{Self}` cannot be made by multiplying all elements of type `{A}` from an iterator", label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator<Item={A}>`" )] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e1ca69edcbb..dc06aa4c38d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -100,6 +100,7 @@ #![feature(bigint_helper_methods)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(cfg_match)] #![feature(closure_track_caller)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index fa0d882181a..5f200b31d1a 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1744,7 +1744,7 @@ pub(crate) mod builtin { } /// Provide a list of type aliases and other opaque-type-containing type definitions. - /// This list will be used in the body of the item it is applied to to define opaque + /// This list will be used in the body of the item it is applied to define opaque /// types' hidden types. /// Can only be applied to things that have bodies. #[unstable( diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 7aa5ed60d04..2f027be6928 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1623,6 +1623,8 @@ impl Ipv6Addr { // IANA says N/A. || matches!(self.segments(), [0x2002, _, _, _, _, _, _, _]) || self.is_documentation() + // Segment Routing (SRv6) SIDs (`5f00::/16`) + || matches!(self.segments(), [0x5f00, ..]) || self.is_unique_local() || self.is_unicast_link_local()) } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 79d864e1b19..53373584d55 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -14,7 +14,7 @@ use crate::convert::FloatToInt; use crate::num::FpCategory; use crate::panic::const_assert; -use crate::{intrinsics, mem}; +use crate::{cfg_match, intrinsics, mem}; /// The radix or base of the internal representation of `f32`. /// Use [`f32::RADIX`] instead. @@ -996,21 +996,22 @@ impl f32 { #[stable(feature = "num_midpoint", since = "1.85.0")] #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f32) -> f32 { - cfg_if! { + cfg_match! { // Allow faster implementation that have known good 64-bit float // implementations. Falling back to the branchy code on targets that don't // have 64-bit hardware floats or buggy implementations. // https://github.com/rust-lang/rust/pull/121062#issuecomment-2123408114 - if #[cfg(any( - target_arch = "x86_64", - target_arch = "aarch64", - all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "d"), - all(target_arch = "arm", target_feature = "vfp2"), - target_arch = "wasm32", - target_arch = "wasm64", - ))] { + any( + target_arch = "x86_64", + target_arch = "aarch64", + all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "d"), + all(target_arch = "arm", target_feature = "vfp2"), + target_arch = "wasm32", + target_arch = "wasm64", + ) => { ((self as f64 + other as f64) / 2.0) as f32 - } else { + } + _ => { const LO: f32 = f32::MIN_POSITIVE * 2.; const HI: f32 = f32::MAX / 2.; diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 7fcd19f67ee..bc097bf198d 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1943,6 +1943,7 @@ unsafe impl<T: ?Sized> PinCoerceUnsized for *mut T {} #[stable(feature = "pin_macro", since = "1.68.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(unsafe_pin_internals)] +#[cfg_attr(not(bootstrap), rustc_macro_edition_2021)] pub macro pin($value:expr $(,)?) { // This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's // review such a hypothetical macro (that any user-code could define): diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 89c856fe107..ba4c849837e 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -127,15 +127,13 @@ mod prim_bool {} /// [`Result<String, !>`] which we can unpack like this: /// /// ``` -/// #![feature(exhaustive_patterns)] /// use std::str::FromStr; /// let Ok(s) = String::from_str("hello"); /// ``` /// -/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` -/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the -/// [`Ok`] variant. This illustrates another behavior of `!` - it can be used to "delete" certain -/// enum variants from generic types like `Result`. +/// Since the [`Err`] variant contains a `!`, it can never occur. This means we can exhaustively +/// match on [`Result<T, !>`] by just taking the [`Ok`] variant. This illustrates another behavior +/// of `!` - it can be used to "delete" certain enum variants from generic types like `Result`. /// /// ## Infinite loops /// diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 7d0839aff3f..71a84aff246 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -386,7 +386,8 @@ impl<T: ?Sized> *const T { /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in /// bounds of that allocated object. In particular, this range must not "wrap around" the edge - /// of the address space. + /// of the address space. Note that "range" here refers to a half-open range as usual in Rust, + /// i.e., `self..result` for non-negative offsets and `result..self` for negative offsets. /// /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. diff --git a/library/core/src/slice/sort/select.rs b/library/core/src/slice/sort/select.rs index 3358c03d30a..c4808b1065d 100644 --- a/library/core/src/slice/sort/select.rs +++ b/library/core/src/slice/sort/select.rs @@ -6,6 +6,7 @@ //! for pivot selection. Using this as a fallback ensures O(n) worst case running time with //! better performance than one would get using heapsort as fallback. +use crate::cfg_match; use crate::mem::{self, SizedTypeProperties}; #[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::shared::pivot::choose_pivot; @@ -41,10 +42,11 @@ where let min_idx = min_index(v, &mut is_less).unwrap(); v.swap(min_idx, index); } else { - cfg_if! { - if #[cfg(feature = "optimize_for_size")] { + cfg_match! { + feature = "optimize_for_size" => { median_of_medians(v, &mut is_less, index); - } else { + } + _ => { partition_at_index_loop(v, index, None, &mut is_less); } } diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs index 090367cdaba..a36e5f7801d 100644 --- a/library/core/src/slice/sort/stable/mod.rs +++ b/library/core/src/slice/sort/stable/mod.rs @@ -2,12 +2,12 @@ #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::cmp; -use crate::intrinsics; use crate::mem::{MaybeUninit, SizedTypeProperties}; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::{ SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left, }; +use crate::{cfg_match, intrinsics}; pub(crate) mod merge; @@ -39,17 +39,18 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less return; } - cfg_if! { - if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] { + cfg_match! { + any(feature = "optimize_for_size", target_pointer_width = "16") => { // Unlike driftsort, mergesort only requires len / 2, // not len - len / 2. let alloc_len = len / 2; - cfg_if! { - if #[cfg(target_pointer_width = "16")] { + cfg_match! { + target_pointer_width = "16" => { let mut heap_buf = BufT::with_capacity(alloc_len); let scratch = heap_buf.as_uninit_slice_mut(); - } else { + } + _ => { // For small inputs 4KiB of stack storage suffices, which allows us to avoid // calling the (de-)allocator. Benchmarks showed this was quite beneficial. let mut stack_buf = AlignedStorage::<T, 4096>::new(); @@ -65,7 +66,8 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less } tiny::mergesort(v, scratch, is_less); - } else { + } + _ => { // More advanced sorting methods than insertion sort are faster if called in // a hot loop for small inputs, but for general-purpose code the small // binary size of insertion sort is more important. The instruction cache in diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs index 2eb653c4601..b6c2e05a06a 100644 --- a/library/core/src/slice/sort/unstable/mod.rs +++ b/library/core/src/slice/sort/unstable/mod.rs @@ -1,11 +1,11 @@ //! This module contains the entry points for `slice::sort_unstable`. -use crate::intrinsics; use crate::mem::SizedTypeProperties; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::find_existing_run; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; +use crate::{cfg_match, intrinsics}; pub(crate) mod heapsort; pub(crate) mod quicksort; @@ -30,10 +30,11 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) { return; } - cfg_if! { - if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] { + cfg_match! { + any(feature = "optimize_for_size", target_pointer_width = "16") => { heapsort::heapsort(v, is_less); - } else { + } + _ => { // More advanced sorting methods than insertion sort are faster if called in // a hot loop for small inputs, but for general-purpose code the small // binary size of insertion sort is more important. The instruction cache in diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs index 68a16118716..7e6cfb55990 100644 --- a/library/core/src/slice/sort/unstable/quicksort.rs +++ b/library/core/src/slice/sort/unstable/quicksort.rs @@ -9,7 +9,7 @@ use crate::slice::sort::shared::pivot::choose_pivot; use crate::slice::sort::shared::smallsort::UnstableSmallSortTypeImpl; #[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::unstable::heapsort; -use crate::{intrinsics, ptr}; +use crate::{cfg_match, intrinsics, ptr}; /// Sorts `v` recursively. /// @@ -142,10 +142,11 @@ const fn inst_partition<T, F: FnMut(&T, &T) -> bool>() -> fn(&mut [T], &T, &mut if size_of::<T>() <= MAX_BRANCHLESS_PARTITION_SIZE { // Specialize for types that are relatively cheap to copy, where branchless optimizations // have large leverage e.g. `u64` and `String`. - cfg_if! { - if #[cfg(feature = "optimize_for_size")] { + cfg_match! { + feature = "optimize_for_size" => { partition_lomuto_branchless_simple::<T, F> - } else { + } + _ => { partition_lomuto_branchless_cyclic::<T, F> } } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 88bee622031..9b1b13e7129 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -469,6 +469,7 @@ impl AtomicBool { /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses + #[inline] #[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool { @@ -1389,6 +1390,7 @@ impl<T> AtomicPtr<T> { /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses + #[inline] #[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> { @@ -2525,6 +2527,7 @@ macro_rules! atomic_int { /// /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses + #[inline] #[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type { diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 206b5b9e2c2..d754bb90343 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -2,6 +2,7 @@ use crate::cmp::Ordering::{self, *}; use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; +use crate::ops::ControlFlow::{Break, Continue}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -80,19 +81,19 @@ macro_rules! tuple_impls { } #[inline] fn lt(&self, other: &($($T,)+)) -> bool { - lexical_ord!(lt, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(lt, __chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn le(&self, other: &($($T,)+)) -> bool { - lexical_ord!(le, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(le, __chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn ge(&self, other: &($($T,)+)) -> bool { - lexical_ord!(ge, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(ge, __chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } #[inline] fn gt(&self, other: &($($T,)+)) -> bool { - lexical_ord!(gt, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + lexical_ord!(gt, __chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } } } @@ -171,15 +172,16 @@ macro_rules! maybe_tuple_doc { // `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1, // a2, b2, a3, b3)` (and similarly for `lexical_cmp`) // -// `$ne_rel` is only used to determine the result after checking that they're -// not equal, so `lt` and `le` can both just use `Less`. +// `$chain_rel` is the chaining method from `PartialOrd` to use for all but the +// final value, to produce better results for simple primitives. macro_rules! lexical_ord { - ($rel: ident, $ne_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{ - let c = PartialOrd::partial_cmp(&$a, &$b); - if c != Some(Equal) { c == Some($ne_rel) } - else { lexical_ord!($rel, $ne_rel, $($rest_a, $rest_b),+) } + ($rel: ident, $chain_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{ + match PartialOrd::$chain_rel(&$a, &$b) { + Break(val) => val, + Continue(()) => lexical_ord!($rel, $chain_rel, $($rest_a, $rest_b),+), + } }}; - ($rel: ident, $ne_rel: ident, $a:expr, $b:expr) => { + ($rel: ident, $chain_rel: ident, $a:expr, $b:expr) => { // Use the specific method for the last element PartialOrd::$rel(&$a, &$b) }; |
