From 1d7984a132663296d0652a9059df46d2a393fcb5 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:14:41 +0100 Subject: [PATCH 01/17] Formatter: Access members via getter methods wherever possible The idea behind this is to make implementing `fmt::FormattingOptions` (as well as any future changes to `std::Formatter`) easier. In theory, this might have a negative performance impact because of the additional function calls. However, I strongly believe that those will be inlined anyway, thereby producing assembly code that has comparable performance. --- library/core/src/fmt/float.rs | 6 +++--- library/core/src/fmt/mod.rs | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 04230b1610aae..ee7a8f08f1986 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.precision { + if let Some(precision) = fmt.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.precision { + if let Some(precision) = fmt.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.precision { + if let Some(precision) = fmt.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 7fc9dd21fdd81..1023fad803771 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1365,7 +1365,7 @@ impl<'a> Formatter<'a> { } // The `width` field is more of a `min-width` parameter at this point. - match self.width { + match self.width() { // If there's no minimum length requirements then we can just // write the bytes. None => { @@ -1433,12 +1433,12 @@ 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.width.is_none() && self.precision.is_none() { + if self.width().is_none() && self.precision().is_none() { return self.buf.write_str(s); } // The `precision` field can be interpreted as a `max-width` for the // string being formatted. - let s = if let Some(max) = self.precision { + let s = if let Some(max) = self.precision() { // If our string is longer that the precision, then we must have // truncation. However other flags like `fill`, `width` and `align` // must act as always. @@ -1455,7 +1455,7 @@ impl<'a> Formatter<'a> { &s }; // The `width` field is more of a `min-width` parameter at this point. - match self.width { + match self.width() { // If we're under the maximum length, and there's no minimum length // requirements, then we can just emit the string None => self.buf.write_str(s), @@ -1501,10 +1501,10 @@ impl<'a> Formatter<'a> { }; for _ in 0..pre_pad { - self.buf.write_char(self.fill)?; + self.buf.write_char(self.fill())?; } - Ok(PostPadding::new(self.fill, post_pad)) + Ok(PostPadding::new(self.fill(), post_pad)) } /// Takes the formatted parts and applies the padding. @@ -1516,12 +1516,12 @@ 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.width { + if let Some(mut width) = self.width() { // 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.fill; - let old_align = self.align; + let old_fill = self.fill(); + let old_align = self.align(); if self.sign_aware_zero_pad() { // a sign always goes first let sign = formatted.sign; @@ -2502,7 +2502,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.width.is_none() && f.precision.is_none() { + if f.width().is_none() && f.precision().is_none() { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; 4])) @@ -2526,8 +2526,8 @@ impl 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.width; - let old_flags = f.flags; + let old_width = f.width(); + let old_flags = f.flags(); // 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 @@ -2536,7 +2536,7 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul if f.alternate() { f.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); - if f.width.is_none() { + if f.width().is_none() { f.width = Some((usize::BITS / 4) as usize + 2); } } From f17d13285c04b71c804d83fdf2eb8e82f0c6096f Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:52:13 +0100 Subject: [PATCH 02/17] Added struct `fmt::FormattingOptions` This allows to build custom `std::Formatter`s at runtime. Also added some related enums and two related methods on `std::Formatter`. --- library/alloc/src/fmt.rs | 2 + library/alloc/src/lib.rs | 1 + library/alloc/src/string.rs | 3 +- library/core/src/fmt/mod.rs | 381 ++++++++++++++++++++++++++++------ library/core/tests/fmt/mod.rs | 28 +++ library/core/tests/lib.rs | 1 + library/std/src/lib.rs | 1 + library/std/src/panicking.rs | 2 +- 8 files changed, 349 insertions(+), 70 deletions(-) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 695dddb25eeb4..e40de13f3d4a9 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -596,6 +596,8 @@ pub use core::fmt::{Arguments, write}; pub use core::fmt::{Binary, Octal}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Debug, Display}; +#[unstable(feature = "formatting_options", issue = "118117")] +pub use core::fmt::{DebugAsHex, FormattingOptions, Sign}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 84f4202c02a9b..927c3aa23b9f7 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -117,6 +117,7 @@ #![feature(extend_one_unchecked)] #![feature(fmt_internals)] #![feature(fn_traits)] +#![feature(formatting_options)] #![feature(hasher_prefixfree_extras)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e0576c2551545..d0d0276c55e7d 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -43,6 +43,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::error::Error; +use core::fmt::FormattingOptions; use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] use core::iter::from_fn; @@ -2682,7 +2683,7 @@ impl ToString for T { #[inline] default fn to_string(&self) -> String { let mut buf = String::new(); - let mut formatter = core::fmt::Formatter::new(&mut buf); + let mut formatter = core::fmt::Formatter::new(&mut buf, FormattingOptions::new()); // Bypass format_args!() to avoid write_str with zero-length strs fmt::Display::fmt(self, &mut formatter) .expect("a Display implementation returned an error unexpectedly"); diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 1023fad803771..8e08b7fe983df 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -33,6 +33,19 @@ pub enum Alignment { Center, } +#[doc(hidden)] +#[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] +impl From for Option { + 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")] @@ -247,6 +260,243 @@ impl Write for &mut W { } } +/// The signedness of a [`Formatter`] (or of a [`FormattingOptions`]). +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[unstable(feature = "formatting_options", issue = "118117")] +pub enum Sign { + /// Represents the `+` flag. + Plus, + /// Represents the `-` flag. + Minus, +} + +/// Specifies whether the [`Debug`] trait should use lower-/upper-case +/// hexadecimal or normal integers. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[unstable(feature = "formatting_options", issue = "118117")] +pub enum DebugAsHex { + /// Use lower-case hexadecimal integers for the `Debug` trait (like [the `x?` type](../../std/fmt/index.html#formatting-traits)). + Lower, + /// Use upper-case hexadecimal integers for the `Debug` trait (like [the `x?` type](../../std/fmt/index.html#formatting-traits)). + Upper, +} + +/// Options for formatting. +/// +/// `FormattingOptions` is a [`Formatter`] without an attached [`Write`] trait. +/// It is mainly used to construct `Formatter` instances. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[unstable(feature = "formatting_options", issue = "118117")] +pub struct FormattingOptions { + sign: Option, + sign_aware_zero_pad: bool, + alternate: bool, + fill: char, + alignment: Option, + width: Option, + precision: Option, + debug_as_hex: Option, +} + +impl FormattingOptions { + /// Construct a new `FormatterBuilder` with the supplied `Write` trait + /// object for output that is equivalent to the `{}` formatting + /// specifier: + /// + /// - no flags, + /// - filled with spaces, + /// - no alignment, + /// - no width, + /// - no precision, and + /// - no [`DebugAsHex`] output mode. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn new() -> Self { + Self { + sign: None, + sign_aware_zero_pad: false, + alternate: false, + fill: ' ', + alignment: None, + width: None, + precision: None, + debug_as_hex: None, + } + } + + /// Sets or removes the sign (the `+` or the `-` flag). + /// + /// - `+`: This is intended for numeric types and indicates that the sign + /// should always be printed. By default only the negative sign of signed + /// values is printed, and the sign of positive or unsigned values is + /// omitted. This flag indicates that the correct sign (+ or -) should + /// always be printed. + /// - `-`: Currently not used + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn sign(&mut self, sign: Option) -> &mut Self { + self.sign = sign; + self + } + /// Sets or unsets the `0` flag. + /// + /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { + self.sign_aware_zero_pad = sign_aware_zero_pad; + self + } + /// Sets or unsets the `#` flag. + /// + /// This flag indicates that the "alternate" form of printing should be + /// used. The alternate forms are: + /// - [`Debug`] : pretty-print the [`Debug`] formatting (adds linebreaks and indentation) + /// - [`LowerHex`] as well as [`UpperHex`] - precedes the argument with a `0x` + /// - [`Octal`] - precedes the argument with a `0b` + /// - [`Binary`] - precedes the argument with a `0o` + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn alternate(&mut self, alternate: bool) -> &mut Self { + self.alternate = alternate; + self + } + /// Sets the fill character. + /// + /// The optional fill character and alignment is provided normally in + /// conjunction with the width parameter. This indicates that if the value + /// being formatted is smaller than width some extra characters will be + /// printed around it. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn fill(&mut self, fill: char) -> &mut Self { + self.fill = fill; + self + } + /// Sets or removes the alignment. + /// + /// The alignment specifies how the value being formatted should be + /// positioned if it is smaller than the width of the formatter. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn alignment(&mut self, alignment: Option) -> &mut Self { + self.alignment = alignment; + self + } + /// Sets or removes the width. + /// + /// This is a parameter for the “minimum width” that the format should take + /// up. If the value’s string does not fill up this many characters, then + /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::alignment`] + /// will be used to take up the required space. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn width(&mut self, width: Option) -> &mut Self { + self.width = width; + self + } + /// Sets or removes the precision. + /// + /// - For non-numeric types, this can be considered a “maximum width”. If + /// the resulting string is longer than this width, then it is truncated + /// down to this many characters and that truncated value is emitted with + /// proper fill, alignment and width if those parameters are set. + /// - For integral types, this is ignored. + /// - For floating-point types, this indicates how many digits after the + /// decimal point should be printed. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn precision(&mut self, precision: Option) -> &mut Self { + self.precision = precision; + 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) -> &mut Self { + self.debug_as_hex = debug_as_hex; + self + } + + /// Returns the current sign (the `+` or the `-` flag). + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_sign(&self) -> Option { + self.sign + } + /// Returns the current `0` flag. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_sign_aware_zero_pad(&self) -> bool { + self.sign_aware_zero_pad + } + /// Returns the current `#` flag. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_alternate(&self) -> bool { + self.alternate + } + /// Returns the current fill character. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_fill(&self) -> char { + self.fill + } + /// Returns the current alignment. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_alignment(&self) -> Option { + self.alignment + } + /// Returns the current width. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_width(&self) -> Option { + self.width + } + /// Returns the current precision. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_precision(&self) -> Option { + self.precision + } + /// Returns the current precision. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_debug_as_hex(&self) -> Option { + self.debug_as_hex + } + + /// Creates a [`Formatter`] that writes its output to the given [`Write`] trait. + /// + /// You may alternatively use [`Formatter::new()`]. + #[unstable(feature = "formatting_options", issue = "118117")] + 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 to standard library", issue = "none")] + /// Flags for formatting + pub fn flags(&mut self, flags: u32) { + self.sign = if flags & (1 << rt::Flag::SignPlus as u32) != 0 { + Some(Sign::Plus) + } else if flags & (1 << rt::Flag::SignMinus as u32) != 0 { + Some(Sign::Minus) + } else { + None + }; + self.alternate = (flags & (1 << rt::Flag::Alternate as u32)) != 0; + self.sign_aware_zero_pad = (flags & (1 << rt::Flag::SignAwareZeroPad as u32)) != 0; + self.debug_as_hex = if flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 { + Some(DebugAsHex::Lower) + } else if flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 { + Some(DebugAsHex::Upper) + } else { + None + }; + } + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] + /// Flags for formatting + pub fn get_flags(&self) -> u32 { + >::into(self.get_sign() == Some(Sign::Plus)) << rt::Flag::SignPlus as u32 + | >::into(self.get_sign() == Some(Sign::Minus)) + << rt::Flag::SignMinus as u32 + | >::into(self.get_alternate()) << rt::Flag::Alternate as u32 + | >::into(self.get_sign_aware_zero_pad()) + << rt::Flag::SignAwareZeroPad as u32 + | >::into(self.debug_as_hex == Some(DebugAsHex::Lower)) + << rt::Flag::DebugLowerHex as u32 + | >::into(self.debug_as_hex == Some(DebugAsHex::Upper)) + << rt::Flag::DebugUpperHex as u32 + } +} + /// Configuration for formatting. /// /// A `Formatter` represents various options related to formatting. Users do not @@ -260,34 +510,28 @@ impl Write for &mut W { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Formatter"] pub struct Formatter<'a> { - flags: u32, - fill: char, - align: rt::Alignment, - width: Option, - precision: Option, + options: FormattingOptions, buf: &'a mut (dyn Write + 'a), } impl<'a> Formatter<'a> { - /// Creates a new formatter with default settings. + /// Creates a new formatter with given [`FormattingOptions`]. /// - /// This can be used as a micro-optimization in cases where a full `Arguments` - /// structure (as created by `format_args!`) is not necessary; `Arguments` - /// is a little more expensive to use in simple formatting scenarios. + /// If `write` is a reference to a formatter, it is recommended to use + /// [`Formatter::with_options`] instead as this can borrow the underlying + /// `write`, thereby bypassing one layer of indirection. /// - /// Currently not intended for use outside of the standard library. - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] - #[doc(hidden)] - pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> { - Formatter { - flags: 0, - fill: ' ', - align: rt::Alignment::Unknown, - width: None, - precision: None, - buf, - } + /// You may alternatively use [`FormattingOptions::create_formatter()`]. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { + Formatter { options, buf: write } + } + + /// Creates a new formatter based on this one with given [`FormattingOptions`]. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn with_options(&'a mut self, options: FormattingOptions) -> Self { + Formatter { options, buf: self.buf } } } @@ -1165,7 +1409,7 @@ pub trait UpperExp { /// [`write!`]: crate::write! #[stable(feature = "rust1", since = "1.0.0")] pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { - let mut formatter = Formatter::new(output); + let mut formatter = Formatter::new(output, FormattingOptions::new()); let mut idx = 0; match args.fmt { @@ -1214,14 +1458,14 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { } unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { - fmt.fill = arg.fill; - fmt.align = arg.align; - fmt.flags = arg.flags; + fmt.options.fill(arg.fill); + fmt.options.alignment(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.width = getcount(args, &arg.width); - fmt.precision = getcount(args, &arg.precision); + fmt.options.width(getcount(args, &arg.width)); + fmt.options.precision(getcount(args, &arg.precision)); } // Extract the correct argument @@ -1280,11 +1524,7 @@ impl<'a> Formatter<'a> { buf: wrap(self.buf), // And preserve these - flags: self.flags, - fill: self.fill, - align: self.align, - width: self.width, - precision: self.precision, + options: self.options, } } @@ -1381,14 +1621,15 @@ impl<'a> Formatter<'a> { // 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.fill, '0'); - let old_align = crate::mem::replace(&mut self.align, rt::Alignment::Right); + let old_fill = crate::mem::replace(&mut self.options.fill, '0'); + let old_align = + crate::mem::replace(&mut self.options.alignment, Some(Alignment::Right)); write_prefix(self, sign, prefix)?; let post_padding = self.padding(min - width, Alignment::Right)?; self.buf.write_str(buf)?; post_padding.write(self)?; - self.fill = old_fill; - self.align = old_align; + self.options.fill = old_fill; + self.options.alignment = old_align; Ok(()) } // Otherwise, the sign and prefix goes after the padding @@ -1487,12 +1728,7 @@ impl<'a> Formatter<'a> { padding: usize, default: Alignment, ) -> result::Result { - let align = match self.align { - rt::Alignment::Unknown => default, - rt::Alignment::Left => Alignment::Left, - rt::Alignment::Right => Alignment::Right, - rt::Alignment::Center => Alignment::Center, - }; + let align = self.align().unwrap_or(default); let (pre_pad, post_pad) = match align { Alignment::Left => (0, padding), @@ -1530,8 +1766,8 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; width = width.saturating_sub(sign.len()); - self.fill = '0'; - self.align = rt::Alignment::Right; + self.options.fill('0'); + self.options.alignment(Some(Alignment::Right)); } // remaining parts go through the ordinary padding process. @@ -1548,8 +1784,8 @@ impl<'a> Formatter<'a> { } post_padding.write(self) }; - self.fill = old_fill; - self.align = old_align; + self.options.fill(old_fill); + self.options.alignment(old_align); ret } else { // this is the common case and we take a shortcut @@ -1675,7 +1911,7 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead" )] pub fn flags(&self) -> u32 { - self.flags + self.options.get_flags() } /// Returns the character used as 'fill' whenever there is alignment. @@ -1708,7 +1944,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { - self.fill + self.options.get_fill() } /// Returns a flag indicating what form of alignment was requested. @@ -1743,12 +1979,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { - match self.align { - rt::Alignment::Left => Some(Alignment::Left), - rt::Alignment::Right => Some(Alignment::Right), - rt::Alignment::Center => Some(Alignment::Center), - rt::Alignment::Unknown => None, - } + self.options.get_alignment() } /// Returns the optionally specified integer width that the output should be. @@ -1778,7 +2009,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.width + self.options.get_width() } /// Returns the optionally specified precision for numeric types. @@ -1809,7 +2040,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.precision + self.options.get_precision() } /// Determines if the `+` flag was specified. @@ -1841,7 +2072,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.flags & (1 << rt::Flag::SignPlus as u32) != 0 + self.options.get_sign() == Some(Sign::Plus) } /// Determines if the `-` flag was specified. @@ -1870,7 +2101,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.flags & (1 << rt::Flag::SignMinus as u32) != 0 + self.options.get_sign() == Some(Sign::Minus) } /// Determines if the `#` flag was specified. @@ -1898,7 +2129,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.flags & (1 << rt::Flag::Alternate as u32) != 0 + self.options.get_alternate() } /// Determines if the `0` flag was specified. @@ -1924,17 +2155,17 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 + self.options.get_sign_aware_zero_pad() } // 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.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 + self.options.debug_as_hex == Some(DebugAsHex::Lower) } fn debug_upper_hex(&self) -> bool { - self.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 + self.options.debug_as_hex == Some(DebugAsHex::Upper) } /// Creates a [`DebugStruct`] builder designed to assist with creation of @@ -2350,6 +2581,18 @@ impl<'a> Formatter<'a> { pub fn debug_map<'b>(&'b mut self) -> DebugMap<'b, 'a> { builders::debug_map_new(self) } + + /// Returns the sign of this formatter (`+` or `-`). + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn sign(&self) -> Option { + self.options.get_sign() + } + + /// Returns the formatting options this formatter corresponds to. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn options(&self) -> FormattingOptions { + self.options + } } #[stable(since = "1.2.0", feature = "formatter_write")] @@ -2527,25 +2770,27 @@ impl 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.width(); - let old_flags = f.flags(); + let old_alternate = f.alternate(); + let old_zero_pad = f.sign_aware_zero_pad(); // 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.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); + f.options.sign_aware_zero_pad(true); if f.width().is_none() { - f.width = Some((usize::BITS / 4) as usize + 2); + f.options.width(Some((usize::BITS / 4) as usize + 2)); } } - f.flags |= 1 << (rt::Flag::Alternate as u32); + f.options.alternate(true); let ret = LowerHex::fmt(&ptr_addr, f); - f.width = old_width; - f.flags = old_flags; + f.options.width(old_width); + f.options.alternate(old_alternate); + f.options.sign_aware_zero_pad(old_zero_pad); ret } diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs index f7512abae3820..9aedfdefa688d 100644 --- a/library/core/tests/fmt/mod.rs +++ b/library/core/tests/fmt/mod.rs @@ -50,3 +50,31 @@ fn test_maybe_uninit_short() { let x = core::mem::MaybeUninit::new(0u32); assert_eq!(format!("{x:?}"), "MaybeUninit"); } + +#[test] +fn formatting_options_flags() { + use core::fmt::*; + for sign in [None, Some(Sign::Plus), Some(Sign::Minus)] { + for alternate in [true, false] { + for sign_aware_zero_pad in [true, false] { + for debug_as_hex in [None, Some(DebugAsHex::Lower), Some(DebugAsHex::Upper)] { + let mut original_formatting_options = FormattingOptions::new(); + original_formatting_options + .sign(sign) + .sign_aware_zero_pad(sign_aware_zero_pad) + .alternate(alternate) + .debug_as_hex(debug_as_hex); + + let mut formatting_options_with_flags_set_to_self = original_formatting_options; + formatting_options_with_flags_set_to_self + .flags(formatting_options_with_flags_set_to_self.get_flags()); + + assert_eq!( + original_formatting_options, formatting_options_with_flags_set_to_self, + "Reading and setting flags changes FormattingOptions; Sign({sign:?}), Alternate({alternate:?}). DebugAsHex({debug_as_hex:?})" + ) + } + } + } + } +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e0b1c21e1ecb9..eae6ef9e24c40 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -31,6 +31,7 @@ #![feature(float_minimum_maximum)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(formatting_options)] #![feature(freeze)] #![feature(future_join)] #![feature(generic_assert_internals)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 6be27b283b291..49a0322003905 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -292,6 +292,7 @@ #![feature(dropck_eyepatch)] #![feature(f128)] #![feature(f16)] +#![feature(formatting_options)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(lang_items)] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 97f800dddaa43..dca5ccca0c404 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -623,7 +623,7 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { // Lazily, the first time this gets called, run the actual string formatting. self.string.get_or_insert_with(|| { let mut s = String::new(); - let mut fmt = fmt::Formatter::new(&mut s); + let mut fmt = fmt::Formatter::new(&mut s, fmt::FormattingOptions::new()); let _err = fmt::Display::fmt(&inner, &mut fmt); s }) From 914ab316466e68ad5923640154f15ad5cf622598 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:50:58 +0100 Subject: [PATCH 03/17] Fixed mir-opt test broken because of `std::Formatter` changes --- ...to_exponential_common.GVN.panic-abort.diff | 59 ++++++++++++++----- ...o_exponential_common.GVN.panic-unwind.diff | 59 ++++++++++++++----- 2 files changed, 90 insertions(+), 28 deletions(-) diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff index ed72ca7262959..6e36aa9aac05c 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff @@ -28,27 +28,38 @@ scope 3 { debug precision => _8; let _8: usize; - scope 5 (inlined Formatter::<'_>::precision) { + scope 11 (inlined Formatter::<'_>::precision) { + scope 12 (inlined FormattingOptions::get_precision) { + } } } } } scope 4 (inlined Formatter::<'_>::sign_plus) { - let mut _20: u32; - let mut _21: u32; + let _20: std::option::Option; + scope 5 (inlined FormattingOptions::get_sign) { + } + scope 6 (inlined as PartialEq>::eq) { + let mut _21: isize; + scope 7 { + scope 8 (inlined ::eq) { + let _22: isize; + scope 9 { + scope 10 { + } + } + } + } + } } bb0: { StorageLive(_4); StorageLive(_20); + _20 = copy (((*_1).0: std::fmt::FormattingOptions).0: std::option::Option); StorageLive(_21); - _21 = copy ((*_1).0: u32); - _20 = BitAnd(move _21, const 1_u32); - StorageDead(_21); - _4 = Ne(move _20, const 0_u32); - StorageDead(_20); - StorageLive(_5); - switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + _21 = discriminant(_20); + switchInt(move _21) -> [0: bb11, 1: bb12, otherwise: bb10]; } bb1: { @@ -58,16 +69,16 @@ } bb2: { -- _5 = Minus; -+ _5 = const Minus; +- _5 = core::num::flt2dec::Sign::Minus; ++ _5 = const core::num::flt2dec::Sign::Minus; goto -> bb3; } bb3: { StorageLive(_6); - _6 = copy ((*_1).4: std::option::Option); + _6 = copy (((*_1).0: std::fmt::FormattingOptions).6: std::option::Option); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; } bb4: { @@ -135,7 +146,27 @@ } bb9: { + StorageDead(_21); + StorageDead(_20); + StorageLive(_5); + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + } + + bb10: { unreachable; } + + bb11: { + _4 = const false; + goto -> bb9; + } + + bb12: { + StorageLive(_22); + _22 = discriminant(((_20 as Some).0: std::fmt::Sign)); + _4 = Eq(copy _22, const 0_isize); + StorageDead(_22); + goto -> bb9; + } } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff index 42d9988374959..dab1d95175f17 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff @@ -28,27 +28,38 @@ scope 3 { debug precision => _8; let _8: usize; - scope 5 (inlined Formatter::<'_>::precision) { + scope 11 (inlined Formatter::<'_>::precision) { + scope 12 (inlined FormattingOptions::get_precision) { + } } } } } scope 4 (inlined Formatter::<'_>::sign_plus) { - let mut _20: u32; - let mut _21: u32; + let _20: std::option::Option; + scope 5 (inlined FormattingOptions::get_sign) { + } + scope 6 (inlined as PartialEq>::eq) { + let mut _21: isize; + scope 7 { + scope 8 (inlined ::eq) { + let _22: isize; + scope 9 { + scope 10 { + } + } + } + } + } } bb0: { StorageLive(_4); StorageLive(_20); + _20 = copy (((*_1).0: std::fmt::FormattingOptions).0: std::option::Option); StorageLive(_21); - _21 = copy ((*_1).0: u32); - _20 = BitAnd(move _21, const 1_u32); - StorageDead(_21); - _4 = Ne(move _20, const 0_u32); - StorageDead(_20); - StorageLive(_5); - switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + _21 = discriminant(_20); + switchInt(move _21) -> [0: bb11, 1: bb12, otherwise: bb10]; } bb1: { @@ -58,16 +69,16 @@ } bb2: { -- _5 = Minus; -+ _5 = const Minus; +- _5 = core::num::flt2dec::Sign::Minus; ++ _5 = const core::num::flt2dec::Sign::Minus; goto -> bb3; } bb3: { StorageLive(_6); - _6 = copy ((*_1).4: std::option::Option); + _6 = copy (((*_1).0: std::fmt::FormattingOptions).6: std::option::Option); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; } bb4: { @@ -135,7 +146,27 @@ } bb9: { + StorageDead(_21); + StorageDead(_20); + StorageLive(_5); + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + } + + bb10: { unreachable; } + + bb11: { + _4 = const false; + goto -> bb9; + } + + bb12: { + StorageLive(_22); + _22 = discriminant(((_20 as Some).0: std::fmt::Sign)); + _4 = Eq(copy _22, const 0_isize); + StorageDead(_22); + goto -> bb9; + } } From ad8f264e46a3420bc90a94b8047d0a6efde497e8 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Wed, 22 Nov 2023 23:40:01 +0100 Subject: [PATCH 04/17] Fixed another broken test --- library/alloc/src/string.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d0d0276c55e7d..c5378d78d591b 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -43,7 +43,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::error::Error; -use core::fmt::FormattingOptions; use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] use core::iter::from_fn; @@ -2683,7 +2682,8 @@ impl ToString for T { #[inline] default fn to_string(&self) -> String { let mut buf = String::new(); - let mut formatter = core::fmt::Formatter::new(&mut buf, FormattingOptions::new()); + let mut formatter = + core::fmt::Formatter::new(&mut buf, core::fmt::FormattingOptions::new()); // Bypass format_args!() to avoid write_str with zero-length strs fmt::Display::fmt(self, &mut formatter) .expect("a Display implementation returned an error unexpectedly"); From b0d3958e00b3b761d728df713665fed64e911ae3 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Mon, 27 Nov 2023 03:31:29 +0100 Subject: [PATCH 05/17] Formatter::with_options: Use different lifetimes Formatter::with_options takes self as a mutable reference (`&'a mut Formatter<'b>`). `'a` and `'b` need to be different lifetimes. Just taking `&'a mut Formatter<'a>` and trusting in Rust being able to implicitely convert from `&'a mut Formatter<'b>` if necessary (after all, `'a` must be smaller than `'b` anyway) fails because `'b` is behind a *mutable* reference. For background on on this behavior, see https://doc.rust-lang.org/nomicon/subtyping.html#variance. --- library/core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 8e08b7fe983df..a5c0e1ce4e30d 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -530,7 +530,7 @@ impl<'a> Formatter<'a> { /// Creates a new formatter based on this one with given [`FormattingOptions`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn with_options(&'a mut self, options: FormattingOptions) -> Self { + pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { Formatter { options, buf: self.buf } } } From ecdf48e2b1cb9667e8f517f19a569f19d2c9479b Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Mon, 27 Nov 2023 04:06:00 +0100 Subject: [PATCH 06/17] fmt::FormattingOptions: Renamed `alignment` to `align` Likewise for `get_alignment`. This is how the method is named on `Formatter`, I want to keep it consistent. --- library/core/src/fmt/mod.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index a5c0e1ce4e30d..8e1d5d1ae6209 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -292,7 +292,7 @@ pub struct FormattingOptions { sign_aware_zero_pad: bool, alternate: bool, fill: char, - alignment: Option, + align: Option, width: Option, precision: Option, debug_as_hex: Option, @@ -316,7 +316,7 @@ impl FormattingOptions { sign_aware_zero_pad: false, alternate: false, fill: ' ', - alignment: None, + align: None, width: None, precision: None, debug_as_hex: None, @@ -373,15 +373,15 @@ impl FormattingOptions { /// The alignment specifies how the value being formatted should be /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn alignment(&mut self, alignment: Option) -> &mut Self { - self.alignment = alignment; + pub fn align(&mut self, align: Option) -> &mut Self { + self.align = align; self } /// Sets or removes the width. /// /// This is a parameter for the “minimum width” that the format should take /// up. If the value’s string does not fill up this many characters, then - /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::alignment`] + /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] pub fn width(&mut self, width: Option) -> &mut Self { @@ -432,8 +432,8 @@ impl FormattingOptions { } /// Returns the current alignment. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_alignment(&self) -> Option { - self.alignment + pub fn get_align(&self) -> Option { + self.align } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] @@ -1459,7 +1459,7 @@ 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.alignment(arg.align.into()); + 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. @@ -1623,13 +1623,13 @@ impl<'a> Formatter<'a> { 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.alignment, Some(Alignment::Right)); + crate::mem::replace(&mut self.options.align, Some(Alignment::Right)); write_prefix(self, sign, prefix)?; let post_padding = self.padding(min - width, Alignment::Right)?; self.buf.write_str(buf)?; post_padding.write(self)?; self.options.fill = old_fill; - self.options.alignment = old_align; + self.options.align = old_align; Ok(()) } // Otherwise, the sign and prefix goes after the padding @@ -1767,7 +1767,7 @@ impl<'a> Formatter<'a> { formatted.sign = ""; width = width.saturating_sub(sign.len()); self.options.fill('0'); - self.options.alignment(Some(Alignment::Right)); + self.options.align(Some(Alignment::Right)); } // remaining parts go through the ordinary padding process. @@ -1785,7 +1785,7 @@ impl<'a> Formatter<'a> { post_padding.write(self) }; self.options.fill(old_fill); - self.options.alignment(old_align); + self.options.align(old_align); ret } else { // this is the common case and we take a shortcut @@ -1979,7 +1979,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { - self.options.get_alignment() + self.options.get_align() } /// Returns the optionally specified integer width that the output should be. From a5a6d40791775d606ad28d20ea464427514db5df Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 00:29:06 +0100 Subject: [PATCH 07/17] Fixed copy+paste error in comment Co-authored-by: Mara Bos --- library/core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 8e1d5d1ae6209..a3b907df8ee10 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -277,7 +277,7 @@ pub enum Sign { pub enum DebugAsHex { /// Use lower-case hexadecimal integers for the `Debug` trait (like [the `x?` type](../../std/fmt/index.html#formatting-traits)). Lower, - /// Use upper-case hexadecimal integers for the `Debug` trait (like [the `x?` type](../../std/fmt/index.html#formatting-traits)). + /// Use upper-case hexadecimal integers for the `Debug` trait (like [the `X?` type](../../std/fmt/index.html#formatting-traits)). Upper, } From de073f42a8fd34e2d3470b8ce1d378a0e24819fc Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 00:30:59 +0100 Subject: [PATCH 08/17] impl Default for fmt::FormattingOptions --- library/core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index a3b907df8ee10..42afc903c83c2 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -285,7 +285,7 @@ pub enum DebugAsHex { /// /// `FormattingOptions` is a [`Formatter`] without an attached [`Write`] trait. /// It is mainly used to construct `Formatter` instances. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] #[unstable(feature = "formatting_options", issue = "118117")] pub struct FormattingOptions { sign: Option, From b8b50aecc41364a671ffe628eb006b299302b4ce Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 01:19:22 +0100 Subject: [PATCH 09/17] Made all fns const --- library/core/src/fmt/mod.rs | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 42afc903c83c2..e2f0597b74d92 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -310,7 +310,7 @@ impl FormattingOptions { /// - no precision, and /// - no [`DebugAsHex`] output mode. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn new() -> Self { + pub const fn new() -> Self { Self { sign: None, sign_aware_zero_pad: false, @@ -332,7 +332,7 @@ impl FormattingOptions { /// always be printed. /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] - pub fn sign(&mut self, sign: Option) -> &mut Self { + pub const fn sign(&mut self, sign: Option) -> &mut Self { self.sign = sign; self } @@ -340,7 +340,7 @@ impl FormattingOptions { /// /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware #[unstable(feature = "formatting_options", issue = "118117")] - pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { + pub const fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { self.sign_aware_zero_pad = sign_aware_zero_pad; self } @@ -353,7 +353,7 @@ impl FormattingOptions { /// - [`Octal`] - precedes the argument with a `0b` /// - [`Binary`] - precedes the argument with a `0o` #[unstable(feature = "formatting_options", issue = "118117")] - pub fn alternate(&mut self, alternate: bool) -> &mut Self { + pub const fn alternate(&mut self, alternate: bool) -> &mut Self { self.alternate = alternate; self } @@ -364,7 +364,7 @@ impl FormattingOptions { /// being formatted is smaller than width some extra characters will be /// printed around it. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn fill(&mut self, fill: char) -> &mut Self { + pub const fn fill(&mut self, fill: char) -> &mut Self { self.fill = fill; self } @@ -373,7 +373,7 @@ impl FormattingOptions { /// The alignment specifies how the value being formatted should be /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn align(&mut self, align: Option) -> &mut Self { + pub const fn align(&mut self, align: Option) -> &mut Self { self.align = align; self } @@ -384,7 +384,7 @@ impl FormattingOptions { /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn width(&mut self, width: Option) -> &mut Self { + pub const fn width(&mut self, width: Option) -> &mut Self { self.width = width; self } @@ -398,56 +398,56 @@ impl FormattingOptions { /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn precision(&mut self, precision: Option) -> &mut Self { + pub const fn precision(&mut self, precision: Option) -> &mut Self { self.precision = precision; 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) -> &mut Self { + pub const fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { self.debug_as_hex = debug_as_hex; self } /// Returns the current sign (the `+` or the `-` flag). #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_sign(&self) -> Option { + pub const fn get_sign(&self) -> Option { self.sign } /// Returns the current `0` flag. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_sign_aware_zero_pad(&self) -> bool { + pub const fn get_sign_aware_zero_pad(&self) -> bool { self.sign_aware_zero_pad } /// Returns the current `#` flag. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_alternate(&self) -> bool { + pub const fn get_alternate(&self) -> bool { self.alternate } /// Returns the current fill character. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_fill(&self) -> char { + pub const fn get_fill(&self) -> char { self.fill } /// Returns the current alignment. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_align(&self) -> Option { + pub const fn get_align(&self) -> Option { self.align } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_width(&self) -> Option { + pub const fn get_width(&self) -> Option { self.width } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_precision(&self) -> Option { + pub const fn get_precision(&self) -> Option { self.precision } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_debug_as_hex(&self) -> Option { + pub const fn get_debug_as_hex(&self) -> Option { self.debug_as_hex } @@ -455,7 +455,7 @@ impl FormattingOptions { /// /// You may alternatively use [`Formatter::new()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { + pub const fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { options: self, buf: write } } @@ -524,13 +524,13 @@ impl<'a> Formatter<'a> { /// /// You may alternatively use [`FormattingOptions::create_formatter()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { + pub const fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { Formatter { options, buf: write } } /// Creates a new formatter based on this one with given [`FormattingOptions`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { + pub const fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { Formatter { options, buf: self.buf } } } @@ -2584,13 +2584,13 @@ impl<'a> Formatter<'a> { /// Returns the sign of this formatter (`+` or `-`). #[unstable(feature = "formatting_options", issue = "118117")] - pub fn sign(&self) -> Option { + pub const fn sign(&self) -> Option { self.options.get_sign() } /// Returns the formatting options this formatter corresponds to. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn options(&self) -> FormattingOptions { + pub const fn options(&self) -> FormattingOptions { self.options } } From 7eac57a3953a3ac5bfab1515ee8281e56510d53e Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 01:30:20 +0100 Subject: [PATCH 10/17] Turned public+unstable+hidden functions into private functions --- library/core/src/fmt/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e2f0597b74d92..4fda439881173 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -459,10 +459,8 @@ impl FormattingOptions { Formatter { options: self, buf: write } } - #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting - pub fn flags(&mut self, flags: u32) { + fn flags(&mut self, flags: u32) { self.sign = if flags & (1 << rt::Flag::SignPlus as u32) != 0 { Some(Sign::Plus) } else if flags & (1 << rt::Flag::SignMinus as u32) != 0 { @@ -480,10 +478,8 @@ impl FormattingOptions { None }; } - #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting - pub fn get_flags(&self) -> u32 { + fn get_flags(&self) -> u32 { >::into(self.get_sign() == Some(Sign::Plus)) << rt::Flag::SignPlus as u32 | >::into(self.get_sign() == Some(Sign::Minus)) << rt::Flag::SignMinus as u32 From 5b236555d2030d6346784544b4c522358db453ab Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 02:04:01 +0100 Subject: [PATCH 11/17] Revert "Turned public+unstable+hidden functions into private functions" See https://github.com/rust-lang/rust/pull/118159#discussion_r1491842170 for context. This reverts commit 62078dffcc1aefd4d678df94bca06e7b864065bd. --- library/core/src/fmt/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4fda439881173..e2f0597b74d92 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -459,8 +459,10 @@ impl FormattingOptions { Formatter { options: self, buf: write } } + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting - fn flags(&mut self, flags: u32) { + pub fn flags(&mut self, flags: u32) { self.sign = if flags & (1 << rt::Flag::SignPlus as u32) != 0 { Some(Sign::Plus) } else if flags & (1 << rt::Flag::SignMinus as u32) != 0 { @@ -478,8 +480,10 @@ impl FormattingOptions { None }; } + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting - fn get_flags(&self) -> u32 { + pub fn get_flags(&self) -> u32 { >::into(self.get_sign() == Some(Sign::Plus)) << rt::Flag::SignPlus as u32 | >::into(self.get_sign() == Some(Sign::Minus)) << rt::Flag::SignMinus as u32 From 832a5f292f4faac8fe32df99f82798f2bc8aebeb Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 03:42:03 +0100 Subject: [PATCH 12/17] Refactored FormattingOptions to use a bitmask for storing flags --- library/core/src/fmt/mod.rs | 90 ++++++++++++++++++----------------- library/core/tests/fmt/mod.rs | 16 +++---- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e2f0597b74d92..9598dd33e9364 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -288,14 +288,11 @@ pub enum DebugAsHex { #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] #[unstable(feature = "formatting_options", issue = "118117")] pub struct FormattingOptions { - sign: Option, - sign_aware_zero_pad: bool, - alternate: bool, + flags: u32, fill: char, align: Option, width: Option, precision: Option, - debug_as_hex: Option, } impl FormattingOptions { @@ -312,14 +309,11 @@ impl FormattingOptions { #[unstable(feature = "formatting_options", issue = "118117")] pub const fn new() -> Self { Self { - sign: None, - sign_aware_zero_pad: false, - alternate: false, + flags: 0, fill: ' ', align: None, width: None, precision: None, - debug_as_hex: None, } } @@ -333,7 +327,12 @@ impl FormattingOptions { /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] pub const fn sign(&mut self, sign: Option) -> &mut Self { - self.sign = sign; + 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, + } self } /// Sets or unsets the `0` flag. @@ -341,7 +340,11 @@ impl FormattingOptions { /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware #[unstable(feature = "formatting_options", issue = "118117")] pub const fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { - self.sign_aware_zero_pad = sign_aware_zero_pad; + if sign_aware_zero_pad { + self.flags |= 1 << rt::Flag::SignAwareZeroPad as u32 + } else { + self.flags &= !(1 << rt::Flag::SignAwareZeroPad as u32) + } self } /// Sets or unsets the `#` flag. @@ -354,7 +357,11 @@ impl FormattingOptions { /// - [`Binary`] - precedes the argument with a `0o` #[unstable(feature = "formatting_options", issue = "118117")] pub const fn alternate(&mut self, alternate: bool) -> &mut Self { - self.alternate = alternate; + if alternate { + self.flags |= 1 << rt::Flag::Alternate as u32 + } else { + self.flags &= !(1 << rt::Flag::Alternate as u32) + } self } /// Sets the fill character. @@ -406,24 +413,36 @@ impl FormattingOptions { /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] pub const fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { - self.debug_as_hex = debug_as_hex; + 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, + } self } /// Returns the current sign (the `+` or the `-` flag). #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign(&self) -> Option { - self.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"), + } } /// Returns the current `0` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign_aware_zero_pad(&self) -> bool { - self.sign_aware_zero_pad + self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 } /// Returns the current `#` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_alternate(&self) -> bool { - self.alternate + self.flags & (1 << rt::Flag::Alternate as u32) != 0 } /// Returns the current fill character. #[unstable(feature = "formatting_options", issue = "118117")] @@ -448,7 +467,14 @@ impl FormattingOptions { /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_debug_as_hex(&self) -> Option { - self.debug_as_hex + 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"), + } } /// Creates a [`Formatter`] that writes its output to the given [`Write`] trait. @@ -463,37 +489,13 @@ impl FormattingOptions { #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting pub fn flags(&mut self, flags: u32) { - self.sign = if flags & (1 << rt::Flag::SignPlus as u32) != 0 { - Some(Sign::Plus) - } else if flags & (1 << rt::Flag::SignMinus as u32) != 0 { - Some(Sign::Minus) - } else { - None - }; - self.alternate = (flags & (1 << rt::Flag::Alternate as u32)) != 0; - self.sign_aware_zero_pad = (flags & (1 << rt::Flag::SignAwareZeroPad as u32)) != 0; - self.debug_as_hex = if flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 { - Some(DebugAsHex::Lower) - } else if flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 { - Some(DebugAsHex::Upper) - } else { - None - }; + self.flags = flags } #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting pub fn get_flags(&self) -> u32 { - >::into(self.get_sign() == Some(Sign::Plus)) << rt::Flag::SignPlus as u32 - | >::into(self.get_sign() == Some(Sign::Minus)) - << rt::Flag::SignMinus as u32 - | >::into(self.get_alternate()) << rt::Flag::Alternate as u32 - | >::into(self.get_sign_aware_zero_pad()) - << rt::Flag::SignAwareZeroPad as u32 - | >::into(self.debug_as_hex == Some(DebugAsHex::Lower)) - << rt::Flag::DebugLowerHex as u32 - | >::into(self.debug_as_hex == Some(DebugAsHex::Upper)) - << rt::Flag::DebugUpperHex as u32 + self.flags } } @@ -2161,11 +2163,11 @@ impl<'a> Formatter<'a> { // 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.debug_as_hex == Some(DebugAsHex::Lower) + self.options.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 } fn debug_upper_hex(&self) -> bool { - self.options.debug_as_hex == Some(DebugAsHex::Upper) + self.options.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 } /// Creates a [`DebugStruct`] builder designed to assist with creation of diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs index 9aedfdefa688d..2c93a9bc80db9 100644 --- a/library/core/tests/fmt/mod.rs +++ b/library/core/tests/fmt/mod.rs @@ -58,21 +58,17 @@ fn formatting_options_flags() { for alternate in [true, false] { for sign_aware_zero_pad in [true, false] { for debug_as_hex in [None, Some(DebugAsHex::Lower), Some(DebugAsHex::Upper)] { - let mut original_formatting_options = FormattingOptions::new(); - original_formatting_options + let mut formatting_options = FormattingOptions::new(); + formatting_options .sign(sign) .sign_aware_zero_pad(sign_aware_zero_pad) .alternate(alternate) .debug_as_hex(debug_as_hex); - let mut formatting_options_with_flags_set_to_self = original_formatting_options; - formatting_options_with_flags_set_to_self - .flags(formatting_options_with_flags_set_to_self.get_flags()); - - assert_eq!( - original_formatting_options, formatting_options_with_flags_set_to_self, - "Reading and setting flags changes FormattingOptions; Sign({sign:?}), Alternate({alternate:?}). DebugAsHex({debug_as_hex:?})" - ) + assert_eq!(formatting_options.get_sign(), sign); + assert_eq!(formatting_options.get_alternate(), alternate); + assert_eq!(formatting_options.get_sign_aware_zero_pad(), sign_aware_zero_pad); + assert_eq!(formatting_options.get_debug_as_hex(), debug_as_hex); } } } From a282d5d30eb1c897428e120472b84460fd9faf65 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 04:07:26 +0100 Subject: [PATCH 13/17] Fixed funky_arms (broken mir-opt test due to refactoring fmt::FormattingOptions) --- ...to_exponential_common.GVN.panic-abort.diff | 176 +++++++----------- ...o_exponential_common.GVN.panic-unwind.diff | 176 +++++++----------- 2 files changed, 144 insertions(+), 208 deletions(-) diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff index 6e36aa9aac05c..ed04bc7dd560b 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff @@ -7,46 +7,30 @@ debug upper => _3; let mut _0: std::result::Result<(), std::fmt::Error>; let _4: bool; - let mut _6: std::option::Option; - let mut _7: isize; - let mut _9: &mut std::fmt::Formatter<'_>; - let mut _10: &T; - let mut _11: core::num::flt2dec::Sign; - let mut _12: u32; + let mut _5: &std::fmt::Formatter<'_>; + let mut _7: std::option::Option; + let mut _8: isize; + let mut _10: &mut std::fmt::Formatter<'_>; + let mut _11: &T; + let mut _12: core::num::flt2dec::Sign; let mut _13: u32; - let mut _14: usize; - let mut _15: bool; - let mut _16: &mut std::fmt::Formatter<'_>; - let mut _17: &T; - let mut _18: core::num::flt2dec::Sign; - let mut _19: bool; + let mut _14: u32; + let mut _15: usize; + let mut _16: bool; + let mut _17: &mut std::fmt::Formatter<'_>; + let mut _18: &T; + let mut _19: core::num::flt2dec::Sign; + let mut _20: bool; scope 1 { debug force_sign => _4; - let _5: core::num::flt2dec::Sign; + let _6: core::num::flt2dec::Sign; scope 2 { - debug sign => _5; + debug sign => _6; scope 3 { - debug precision => _8; - let _8: usize; - scope 11 (inlined Formatter::<'_>::precision) { - scope 12 (inlined FormattingOptions::get_precision) { - } - } - } - } - } - scope 4 (inlined Formatter::<'_>::sign_plus) { - let _20: std::option::Option; - scope 5 (inlined FormattingOptions::get_sign) { - } - scope 6 (inlined as PartialEq>::eq) { - let mut _21: isize; - scope 7 { - scope 8 (inlined ::eq) { - let _22: isize; - scope 9 { - scope 10 { - } + debug precision => _9; + let _9: usize; + scope 4 (inlined Formatter::<'_>::precision) { + scope 5 (inlined FormattingOptions::get_precision) { } } } @@ -55,118 +39,102 @@ bb0: { StorageLive(_4); - StorageLive(_20); - _20 = copy (((*_1).0: std::fmt::FormattingOptions).0: std::option::Option); - StorageLive(_21); - _21 = discriminant(_20); - switchInt(move _21) -> [0: bb11, 1: bb12, otherwise: bb10]; + StorageLive(_5); + _5 = &(*_1); + _4 = Formatter::<'_>::sign_plus(move _5) -> [return: bb1, unwind unreachable]; } bb1: { -- _5 = MinusPlus; -+ _5 = const MinusPlus; - goto -> bb3; + StorageDead(_5); + StorageLive(_6); + switchInt(copy _4) -> [0: bb3, otherwise: bb2]; } bb2: { -- _5 = core::num::flt2dec::Sign::Minus; -+ _5 = const core::num::flt2dec::Sign::Minus; - goto -> bb3; +- _6 = MinusPlus; ++ _6 = const MinusPlus; + goto -> bb4; } bb3: { - StorageLive(_6); - _6 = copy (((*_1).0: std::fmt::FormattingOptions).6: std::option::Option); - _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; +- _6 = core::num::flt2dec::Sign::Minus; ++ _6 = const core::num::flt2dec::Sign::Minus; + goto -> bb4; } bb4: { -- StorageLive(_8); + StorageLive(_7); + _7 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); + _8 = discriminant(_7); + switchInt(move _8) -> [1: bb5, 0: bb7, otherwise: bb10]; + } + + bb5: { +- StorageLive(_9); + nop; - _8 = copy ((_6 as Some).0: usize); - StorageLive(_9); - _9 = copy _1; + _9 = copy ((_7 as Some).0: usize); StorageLive(_10); - _10 = copy _2; + _10 = copy _1; StorageLive(_11); - _11 = copy _5; + _11 = copy _2; StorageLive(_12); + _12 = copy _6; StorageLive(_13); StorageLive(_14); - _14 = copy _8; -- _13 = move _14 as u32 (IntToInt); -+ _13 = copy _8 as u32 (IntToInt); - StorageDead(_14); - _12 = Add(move _13, const 1_u32); - StorageDead(_13); StorageLive(_15); - _15 = copy _3; -- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind unreachable]; -+ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _11, move _12, copy _3) -> [return: bb5, unwind unreachable]; + _15 = copy _9; +- _14 = move _15 as u32 (IntToInt); ++ _14 = copy _9 as u32 (IntToInt); + StorageDead(_15); + _13 = Add(move _14, const 1_u32); + StorageDead(_14); + StorageLive(_16); + _16 = copy _3; +- _0 = float_to_exponential_common_exact::(move _10, move _11, move _12, move _13, move _16) -> [return: bb6, unwind unreachable]; ++ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _12, move _13, copy _3) -> [return: bb6, unwind unreachable]; } - bb5: { - StorageDead(_15); + bb6: { + StorageDead(_16); + StorageDead(_13); StorageDead(_12); StorageDead(_11); StorageDead(_10); - StorageDead(_9); -- StorageDead(_8); +- StorageDead(_9); + nop; - goto -> bb8; + goto -> bb9; } - bb6: { - StorageLive(_16); - _16 = copy _1; + bb7: { StorageLive(_17); - _17 = copy _2; + _17 = copy _1; StorageLive(_18); - _18 = copy _5; + _18 = copy _2; StorageLive(_19); - _19 = copy _3; -- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind unreachable]; -+ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _18, copy _3) -> [return: bb7, unwind unreachable]; + _19 = copy _6; + StorageLive(_20); + _20 = copy _3; +- _0 = float_to_exponential_common_shortest::(move _17, move _18, move _19, move _20) -> [return: bb8, unwind unreachable]; ++ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _19, copy _3) -> [return: bb8, unwind unreachable]; } - bb7: { + bb8: { + StorageDead(_20); StorageDead(_19); StorageDead(_18); StorageDead(_17); - StorageDead(_16); - goto -> bb8; + goto -> bb9; } - bb8: { - StorageDead(_5); - StorageDead(_4); + bb9: { StorageDead(_6); + StorageDead(_4); + StorageDead(_7); return; } - bb9: { - StorageDead(_21); - StorageDead(_20); - StorageLive(_5); - switchInt(copy _4) -> [0: bb2, otherwise: bb1]; - } - bb10: { unreachable; } - - bb11: { - _4 = const false; - goto -> bb9; - } - - bb12: { - StorageLive(_22); - _22 = discriminant(((_20 as Some).0: std::fmt::Sign)); - _4 = Eq(copy _22, const 0_isize); - StorageDead(_22); - goto -> bb9; - } } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff index dab1d95175f17..33640bb2d8f06 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff @@ -7,46 +7,30 @@ debug upper => _3; let mut _0: std::result::Result<(), std::fmt::Error>; let _4: bool; - let mut _6: std::option::Option; - let mut _7: isize; - let mut _9: &mut std::fmt::Formatter<'_>; - let mut _10: &T; - let mut _11: core::num::flt2dec::Sign; - let mut _12: u32; + let mut _5: &std::fmt::Formatter<'_>; + let mut _7: std::option::Option; + let mut _8: isize; + let mut _10: &mut std::fmt::Formatter<'_>; + let mut _11: &T; + let mut _12: core::num::flt2dec::Sign; let mut _13: u32; - let mut _14: usize; - let mut _15: bool; - let mut _16: &mut std::fmt::Formatter<'_>; - let mut _17: &T; - let mut _18: core::num::flt2dec::Sign; - let mut _19: bool; + let mut _14: u32; + let mut _15: usize; + let mut _16: bool; + let mut _17: &mut std::fmt::Formatter<'_>; + let mut _18: &T; + let mut _19: core::num::flt2dec::Sign; + let mut _20: bool; scope 1 { debug force_sign => _4; - let _5: core::num::flt2dec::Sign; + let _6: core::num::flt2dec::Sign; scope 2 { - debug sign => _5; + debug sign => _6; scope 3 { - debug precision => _8; - let _8: usize; - scope 11 (inlined Formatter::<'_>::precision) { - scope 12 (inlined FormattingOptions::get_precision) { - } - } - } - } - } - scope 4 (inlined Formatter::<'_>::sign_plus) { - let _20: std::option::Option; - scope 5 (inlined FormattingOptions::get_sign) { - } - scope 6 (inlined as PartialEq>::eq) { - let mut _21: isize; - scope 7 { - scope 8 (inlined ::eq) { - let _22: isize; - scope 9 { - scope 10 { - } + debug precision => _9; + let _9: usize; + scope 4 (inlined Formatter::<'_>::precision) { + scope 5 (inlined FormattingOptions::get_precision) { } } } @@ -55,118 +39,102 @@ bb0: { StorageLive(_4); - StorageLive(_20); - _20 = copy (((*_1).0: std::fmt::FormattingOptions).0: std::option::Option); - StorageLive(_21); - _21 = discriminant(_20); - switchInt(move _21) -> [0: bb11, 1: bb12, otherwise: bb10]; + StorageLive(_5); + _5 = &(*_1); + _4 = Formatter::<'_>::sign_plus(move _5) -> [return: bb1, unwind continue]; } bb1: { -- _5 = MinusPlus; -+ _5 = const MinusPlus; - goto -> bb3; + StorageDead(_5); + StorageLive(_6); + switchInt(copy _4) -> [0: bb3, otherwise: bb2]; } bb2: { -- _5 = core::num::flt2dec::Sign::Minus; -+ _5 = const core::num::flt2dec::Sign::Minus; - goto -> bb3; +- _6 = MinusPlus; ++ _6 = const MinusPlus; + goto -> bb4; } bb3: { - StorageLive(_6); - _6 = copy (((*_1).0: std::fmt::FormattingOptions).6: std::option::Option); - _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; +- _6 = core::num::flt2dec::Sign::Minus; ++ _6 = const core::num::flt2dec::Sign::Minus; + goto -> bb4; } bb4: { -- StorageLive(_8); + StorageLive(_7); + _7 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); + _8 = discriminant(_7); + switchInt(move _8) -> [1: bb5, 0: bb7, otherwise: bb10]; + } + + bb5: { +- StorageLive(_9); + nop; - _8 = copy ((_6 as Some).0: usize); - StorageLive(_9); - _9 = copy _1; + _9 = copy ((_7 as Some).0: usize); StorageLive(_10); - _10 = copy _2; + _10 = copy _1; StorageLive(_11); - _11 = copy _5; + _11 = copy _2; StorageLive(_12); + _12 = copy _6; StorageLive(_13); StorageLive(_14); - _14 = copy _8; -- _13 = move _14 as u32 (IntToInt); -+ _13 = copy _8 as u32 (IntToInt); - StorageDead(_14); - _12 = Add(move _13, const 1_u32); - StorageDead(_13); StorageLive(_15); - _15 = copy _3; -- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind continue]; -+ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _11, move _12, copy _3) -> [return: bb5, unwind continue]; + _15 = copy _9; +- _14 = move _15 as u32 (IntToInt); ++ _14 = copy _9 as u32 (IntToInt); + StorageDead(_15); + _13 = Add(move _14, const 1_u32); + StorageDead(_14); + StorageLive(_16); + _16 = copy _3; +- _0 = float_to_exponential_common_exact::(move _10, move _11, move _12, move _13, move _16) -> [return: bb6, unwind continue]; ++ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _12, move _13, copy _3) -> [return: bb6, unwind continue]; } - bb5: { - StorageDead(_15); + bb6: { + StorageDead(_16); + StorageDead(_13); StorageDead(_12); StorageDead(_11); StorageDead(_10); - StorageDead(_9); -- StorageDead(_8); +- StorageDead(_9); + nop; - goto -> bb8; + goto -> bb9; } - bb6: { - StorageLive(_16); - _16 = copy _1; + bb7: { StorageLive(_17); - _17 = copy _2; + _17 = copy _1; StorageLive(_18); - _18 = copy _5; + _18 = copy _2; StorageLive(_19); - _19 = copy _3; -- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind continue]; -+ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _18, copy _3) -> [return: bb7, unwind continue]; + _19 = copy _6; + StorageLive(_20); + _20 = copy _3; +- _0 = float_to_exponential_common_shortest::(move _17, move _18, move _19, move _20) -> [return: bb8, unwind continue]; ++ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _19, copy _3) -> [return: bb8, unwind continue]; } - bb7: { + bb8: { + StorageDead(_20); StorageDead(_19); StorageDead(_18); StorageDead(_17); - StorageDead(_16); - goto -> bb8; + goto -> bb9; } - bb8: { - StorageDead(_5); - StorageDead(_4); + bb9: { StorageDead(_6); + StorageDead(_4); + StorageDead(_7); return; } - bb9: { - StorageDead(_21); - StorageDead(_20); - StorageLive(_5); - switchInt(copy _4) -> [0: bb2, otherwise: bb1]; - } - bb10: { unreachable; } - - bb11: { - _4 = const false; - goto -> bb9; - } - - bb12: { - StorageLive(_22); - _22 = discriminant(((_20 as Some).0: std::fmt::Sign)); - _4 = Eq(copy _22, const 0_isize); - StorageDead(_22); - goto -> bb9; - } } From 2fc260802c113cdb8c63a9c2168194a22c57bf31 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 04:10:58 +0100 Subject: [PATCH 14/17] Formatted --- library/core/src/fmt/mod.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 9598dd33e9364..ccad3748bbd12 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -308,13 +308,7 @@ 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: 0, fill: ' ', align: None, width: None, precision: None } } /// Sets or removes the sign (the `+` or the `-` flag). @@ -327,9 +321,10 @@ impl FormattingOptions { /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] pub const fn sign(&mut self, sign: Option) -> &mut Self { - self.flags = self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); + self.flags = + self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); match sign { - None => {}, + None => {} Some(Sign::Plus) => self.flags |= 1 << rt::Flag::SignPlus as u32, Some(Sign::Minus) => self.flags |= 1 << rt::Flag::SignMinus as u32, } @@ -413,9 +408,10 @@ impl FormattingOptions { /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] pub const fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { - self.flags = self.flags & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); + self.flags = self.flags + & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); match debug_as_hex { - None => {}, + None => {} Some(DebugAsHex::Upper) => self.flags |= 1 << rt::Flag::DebugUpperHex as u32, Some(DebugAsHex::Lower) => self.flags |= 1 << rt::Flag::DebugLowerHex as u32, } @@ -469,7 +465,9 @@ impl FormattingOptions { pub const fn get_debug_as_hex(&self) -> Option { 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)) { + 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, From 245acf819df592f351e34fa5bb12acfbcf9d3823 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Sun, 3 Mar 2024 03:36:37 +0100 Subject: [PATCH 15/17] Added better reason for exposing `flags` and `get_flags` as unstable --- library/core/src/fmt/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index ccad3748bbd12..422d9b25183d9 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -484,13 +484,21 @@ impl FormattingOptions { } #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] + #[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 to standard library", issue = "none")] + #[unstable( + feature = "fmt_internals", + reason = "internal routines only exposed for testing", + issue = "none" + )] /// Flags for formatting pub fn get_flags(&self) -> u32 { self.flags From 2f9e0c984bd6c1a9e9acbc8478de2496a3ac481e Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Sun, 3 Mar 2024 03:53:11 +0100 Subject: [PATCH 16/17] Removed constness for methods receiving a `&mut` parameter See https://github.com/rust-lang/rust/pull/118159#discussion_r1495760867 for context. --- library/core/src/fmt/mod.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 422d9b25183d9..da89acdcd1ef4 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -320,7 +320,7 @@ impl FormattingOptions { /// always be printed. /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn sign(&mut self, sign: Option) -> &mut Self { + pub fn sign(&mut self, sign: Option) -> &mut Self { self.flags = self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); match sign { @@ -334,7 +334,7 @@ impl FormattingOptions { /// /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { + 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 } else { @@ -351,7 +351,7 @@ impl FormattingOptions { /// - [`Octal`] - precedes the argument with a `0b` /// - [`Binary`] - precedes the argument with a `0o` #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn alternate(&mut self, alternate: bool) -> &mut Self { + pub fn alternate(&mut self, alternate: bool) -> &mut Self { if alternate { self.flags |= 1 << rt::Flag::Alternate as u32 } else { @@ -366,7 +366,7 @@ impl FormattingOptions { /// being formatted is smaller than width some extra characters will be /// printed around it. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn fill(&mut self, fill: char) -> &mut Self { + pub fn fill(&mut self, fill: char) -> &mut Self { self.fill = fill; self } @@ -375,7 +375,7 @@ impl FormattingOptions { /// The alignment specifies how the value being formatted should be /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn align(&mut self, align: Option) -> &mut Self { + pub fn align(&mut self, align: Option) -> &mut Self { self.align = align; self } @@ -386,7 +386,7 @@ impl FormattingOptions { /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn width(&mut self, width: Option) -> &mut Self { + pub fn width(&mut self, width: Option) -> &mut Self { self.width = width; self } @@ -400,14 +400,14 @@ impl FormattingOptions { /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn precision(&mut self, precision: Option) -> &mut Self { + pub fn precision(&mut self, precision: Option) -> &mut Self { self.precision = precision; self } /// Specifies whether the [`Debug`] trait should use lower-/upper-case /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { + pub fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { self.flags = self.flags & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); match debug_as_hex { @@ -479,7 +479,7 @@ impl FormattingOptions { /// /// You may alternatively use [`Formatter::new()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { + pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { options: self, buf: write } } @@ -532,13 +532,13 @@ impl<'a> Formatter<'a> { /// /// You may alternatively use [`FormattingOptions::create_formatter()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { + pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { Formatter { options, buf: write } } /// Creates a new formatter based on this one with given [`FormattingOptions`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { + pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { Formatter { options, buf: self.buf } } } From 31a56571091a9bdcc3fc9f4dff9e4fafeddc2ea8 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Sun, 3 Mar 2024 05:17:55 +0100 Subject: [PATCH 17/17] Access members of `FormattingOptions` directly instead of via getters/setters --- library/core/src/fmt/float.rs | 6 +- library/core/src/fmt/mod.rs | 74 +++++---- ...to_exponential_common.GVN.panic-abort.diff | 147 +++++++++--------- ...o_exponential_common.GVN.panic-unwind.diff | 147 +++++++++--------- 4 files changed, 187 insertions(+), 187 deletions(-) diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index ee7a8f08f1986..3f10158193d76 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.precision() { + if let Some(precision) = fmt.options.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.precision() { + if let Some(precision) = fmt.options.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.precision() { + if let Some(precision) = fmt.options.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 da89acdcd1ef4..14c7006510162 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1466,14 +1466,14 @@ 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); + 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)); + fmt.options.width = getcount(args, &arg.width); + fmt.options.precision = getcount(args, &arg.precision); } // Extract the correct argument @@ -1613,7 +1613,7 @@ impl<'a> Formatter<'a> { } // The `width` field is more of a `min-width` parameter at this point. - match self.width() { + match self.options.width { // If there's no minimum length requirements then we can just // write the bytes. None => { @@ -1682,12 +1682,12 @@ 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.width().is_none() && self.precision().is_none() { + if self.options.width.is_none() && self.options.precision.is_none() { return self.buf.write_str(s); } // The `precision` field can be interpreted as a `max-width` for the // string being formatted. - let s = if let Some(max) = self.precision() { + let s = if let Some(max) = self.options.precision { // If our string is longer that the precision, then we must have // truncation. However other flags like `fill`, `width` and `align` // must act as always. @@ -1704,7 +1704,7 @@ impl<'a> Formatter<'a> { &s }; // The `width` field is more of a `min-width` parameter at this point. - match self.width() { + match self.options.width { // If we're under the maximum length, and there's no minimum length // requirements, then we can just emit the string None => self.buf.write_str(s), @@ -1745,10 +1745,10 @@ impl<'a> Formatter<'a> { }; for _ in 0..pre_pad { - self.buf.write_char(self.fill())?; + self.buf.write_char(self.options.fill)?; } - Ok(PostPadding::new(self.fill(), post_pad)) + Ok(PostPadding::new(self.options.fill, post_pad)) } /// Takes the formatted parts and applies the padding. @@ -1760,12 +1760,12 @@ 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.width() { + if let Some(mut width) = self.options.width { // 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.fill(); - let old_align = self.align(); + let old_fill = self.options.fill; + let old_align = self.options.align; if self.sign_aware_zero_pad() { // a sign always goes first let sign = formatted.sign; @@ -1774,8 +1774,8 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; width = width.saturating_sub(sign.len()); - self.options.fill('0'); - self.options.align(Some(Alignment::Right)); + self.options.fill = '0'; + self.options.align = Some(Alignment::Right); } // remaining parts go through the ordinary padding process. @@ -1792,8 +1792,8 @@ impl<'a> Formatter<'a> { } post_padding.write(self) }; - self.options.fill(old_fill); - self.options.align(old_align); + self.options.fill = old_fill; + self.options.align = old_align; ret } else { // this is the common case and we take a shortcut @@ -1919,7 +1919,7 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead" )] pub fn flags(&self) -> u32 { - self.options.get_flags() + self.options.flags } /// Returns the character used as 'fill' whenever there is alignment. @@ -1952,7 +1952,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { - self.options.get_fill() + self.options.fill } /// Returns a flag indicating what form of alignment was requested. @@ -1987,7 +1987,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { - self.options.get_align() + self.options.align } /// Returns the optionally specified integer width that the output should be. @@ -2017,7 +2017,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.options.get_width() + self.options.width } /// Returns the optionally specified precision for numeric types. @@ -2048,7 +2048,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.options.get_precision() + self.options.precision } /// Determines if the `+` flag was specified. @@ -2080,7 +2080,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.options.get_sign() == Some(Sign::Plus) + self.options.flags & (1 << rt::Flag::SignPlus as u32) != 0 } /// Determines if the `-` flag was specified. @@ -2109,7 +2109,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.options.get_sign() == Some(Sign::Minus) + self.options.flags & (1 << rt::Flag::SignMinus as u32) != 0 } /// Determines if the `#` flag was specified. @@ -2137,7 +2137,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.options.get_alternate() + self.options.flags & (1 << rt::Flag::Alternate as u32) != 0 } /// Determines if the `0` flag was specified. @@ -2163,7 +2163,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.options.get_sign_aware_zero_pad() + self.options.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 } // FIXME: Decide what public API we want for these two flags. @@ -2753,7 +2753,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.width().is_none() && f.precision().is_none() { + if f.options.width.is_none() && f.options.precision.is_none() { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; 4])) @@ -2777,28 +2777,26 @@ impl 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.width(); - let old_alternate = f.alternate(); - let old_zero_pad = f.sign_aware_zero_pad(); + let old_width = f.options.width; + let old_flags = f.options.flags; // 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.sign_aware_zero_pad(true); + f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); - if f.width().is_none() { - f.options.width(Some((usize::BITS / 4) as usize + 2)); + if f.options.width.is_none() { + f.options.width = Some((usize::BITS / 4) as usize + 2); } } - f.options.alternate(true); + f.options.flags |= 1 << (rt::Flag::Alternate as u32); let ret = LowerHex::fmt(&ptr_addr, f); - f.options.width(old_width); - f.options.alternate(old_alternate); - f.options.sign_aware_zero_pad(old_zero_pad); + f.options.width = old_width; + f.options.flags = old_flags; ret } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff index ed04bc7dd560b..a1be927e1c04a 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff @@ -7,133 +7,134 @@ debug upper => _3; let mut _0: std::result::Result<(), std::fmt::Error>; let _4: bool; - let mut _5: &std::fmt::Formatter<'_>; - let mut _7: std::option::Option; - let mut _8: isize; - let mut _10: &mut std::fmt::Formatter<'_>; - let mut _11: &T; - let mut _12: core::num::flt2dec::Sign; + let mut _6: std::option::Option; + let mut _7: isize; + let mut _9: &mut std::fmt::Formatter<'_>; + let mut _10: &T; + let mut _11: core::num::flt2dec::Sign; + let mut _12: u32; let mut _13: u32; - let mut _14: u32; - let mut _15: usize; - let mut _16: bool; - let mut _17: &mut std::fmt::Formatter<'_>; - let mut _18: &T; - let mut _19: core::num::flt2dec::Sign; - let mut _20: bool; + let mut _14: usize; + let mut _15: bool; + let mut _16: &mut std::fmt::Formatter<'_>; + let mut _17: &T; + let mut _18: core::num::flt2dec::Sign; + let mut _19: bool; scope 1 { debug force_sign => _4; - let _6: core::num::flt2dec::Sign; + let _5: core::num::flt2dec::Sign; scope 2 { - debug sign => _6; + debug sign => _5; scope 3 { - debug precision => _9; - let _9: usize; - scope 4 (inlined Formatter::<'_>::precision) { - scope 5 (inlined FormattingOptions::get_precision) { - } + debug precision => _8; + let _8: usize; + scope 5 (inlined Formatter::<'_>::precision) { } } } } + scope 4 (inlined Formatter::<'_>::sign_plus) { + let mut _20: u32; + let mut _21: u32; + } bb0: { StorageLive(_4); + StorageLive(_20); + StorageLive(_21); + _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _20 = BitAnd(move _21, const 1_u32); + StorageDead(_21); + _4 = Ne(move _20, const 0_u32); + StorageDead(_20); StorageLive(_5); - _5 = &(*_1); - _4 = Formatter::<'_>::sign_plus(move _5) -> [return: bb1, unwind unreachable]; + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; } bb1: { - StorageDead(_5); - StorageLive(_6); - switchInt(copy _4) -> [0: bb3, otherwise: bb2]; +- _5 = MinusPlus; ++ _5 = const MinusPlus; + goto -> bb3; } bb2: { -- _6 = MinusPlus; -+ _6 = const MinusPlus; - goto -> bb4; +- _5 = core::num::flt2dec::Sign::Minus; ++ _5 = const core::num::flt2dec::Sign::Minus; + goto -> bb3; } bb3: { -- _6 = core::num::flt2dec::Sign::Minus; -+ _6 = const core::num::flt2dec::Sign::Minus; - goto -> bb4; + StorageLive(_6); + _6 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; } bb4: { - StorageLive(_7); - _7 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); - _8 = discriminant(_7); - switchInt(move _8) -> [1: bb5, 0: bb7, otherwise: bb10]; - } - - bb5: { -- StorageLive(_9); +- StorageLive(_8); + nop; - _9 = copy ((_7 as Some).0: usize); + _8 = copy ((_6 as Some).0: usize); + StorageLive(_9); + _9 = copy _1; StorageLive(_10); - _10 = copy _1; + _10 = copy _2; StorageLive(_11); - _11 = copy _2; + _11 = copy _5; StorageLive(_12); - _12 = copy _6; StorageLive(_13); StorageLive(_14); - StorageLive(_15); - _15 = copy _9; -- _14 = move _15 as u32 (IntToInt); -+ _14 = copy _9 as u32 (IntToInt); - StorageDead(_15); - _13 = Add(move _14, const 1_u32); + _14 = copy _8; +- _13 = move _14 as u32 (IntToInt); ++ _13 = copy _8 as u32 (IntToInt); StorageDead(_14); - StorageLive(_16); - _16 = copy _3; -- _0 = float_to_exponential_common_exact::(move _10, move _11, move _12, move _13, move _16) -> [return: bb6, unwind unreachable]; -+ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _12, move _13, copy _3) -> [return: bb6, unwind unreachable]; + _12 = Add(move _13, const 1_u32); + StorageDead(_13); + StorageLive(_15); + _15 = copy _3; +- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind unreachable]; ++ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _11, move _12, copy _3) -> [return: bb5, unwind unreachable]; } - bb6: { - StorageDead(_16); - StorageDead(_13); + bb5: { + StorageDead(_15); StorageDead(_12); StorageDead(_11); StorageDead(_10); -- StorageDead(_9); + StorageDead(_9); +- StorageDead(_8); + nop; - goto -> bb9; + goto -> bb8; } - bb7: { + bb6: { + StorageLive(_16); + _16 = copy _1; StorageLive(_17); - _17 = copy _1; + _17 = copy _2; StorageLive(_18); - _18 = copy _2; + _18 = copy _5; StorageLive(_19); - _19 = copy _6; - StorageLive(_20); - _20 = copy _3; -- _0 = float_to_exponential_common_shortest::(move _17, move _18, move _19, move _20) -> [return: bb8, unwind unreachable]; -+ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _19, copy _3) -> [return: bb8, unwind unreachable]; + _19 = copy _3; +- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind unreachable]; ++ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _18, copy _3) -> [return: bb7, unwind unreachable]; } - bb8: { - StorageDead(_20); + bb7: { StorageDead(_19); StorageDead(_18); StorageDead(_17); - goto -> bb9; + StorageDead(_16); + goto -> bb8; } - bb9: { - StorageDead(_6); + bb8: { + StorageDead(_5); StorageDead(_4); - StorageDead(_7); + StorageDead(_6); return; } - bb10: { + bb9: { unreachable; } } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff index 33640bb2d8f06..87ab71feb2faa 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff @@ -7,133 +7,134 @@ debug upper => _3; let mut _0: std::result::Result<(), std::fmt::Error>; let _4: bool; - let mut _5: &std::fmt::Formatter<'_>; - let mut _7: std::option::Option; - let mut _8: isize; - let mut _10: &mut std::fmt::Formatter<'_>; - let mut _11: &T; - let mut _12: core::num::flt2dec::Sign; + let mut _6: std::option::Option; + let mut _7: isize; + let mut _9: &mut std::fmt::Formatter<'_>; + let mut _10: &T; + let mut _11: core::num::flt2dec::Sign; + let mut _12: u32; let mut _13: u32; - let mut _14: u32; - let mut _15: usize; - let mut _16: bool; - let mut _17: &mut std::fmt::Formatter<'_>; - let mut _18: &T; - let mut _19: core::num::flt2dec::Sign; - let mut _20: bool; + let mut _14: usize; + let mut _15: bool; + let mut _16: &mut std::fmt::Formatter<'_>; + let mut _17: &T; + let mut _18: core::num::flt2dec::Sign; + let mut _19: bool; scope 1 { debug force_sign => _4; - let _6: core::num::flt2dec::Sign; + let _5: core::num::flt2dec::Sign; scope 2 { - debug sign => _6; + debug sign => _5; scope 3 { - debug precision => _9; - let _9: usize; - scope 4 (inlined Formatter::<'_>::precision) { - scope 5 (inlined FormattingOptions::get_precision) { - } + debug precision => _8; + let _8: usize; + scope 5 (inlined Formatter::<'_>::precision) { } } } } + scope 4 (inlined Formatter::<'_>::sign_plus) { + let mut _20: u32; + let mut _21: u32; + } bb0: { StorageLive(_4); + StorageLive(_20); + StorageLive(_21); + _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _20 = BitAnd(move _21, const 1_u32); + StorageDead(_21); + _4 = Ne(move _20, const 0_u32); + StorageDead(_20); StorageLive(_5); - _5 = &(*_1); - _4 = Formatter::<'_>::sign_plus(move _5) -> [return: bb1, unwind continue]; + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; } bb1: { - StorageDead(_5); - StorageLive(_6); - switchInt(copy _4) -> [0: bb3, otherwise: bb2]; +- _5 = MinusPlus; ++ _5 = const MinusPlus; + goto -> bb3; } bb2: { -- _6 = MinusPlus; -+ _6 = const MinusPlus; - goto -> bb4; +- _5 = core::num::flt2dec::Sign::Minus; ++ _5 = const core::num::flt2dec::Sign::Minus; + goto -> bb3; } bb3: { -- _6 = core::num::flt2dec::Sign::Minus; -+ _6 = const core::num::flt2dec::Sign::Minus; - goto -> bb4; + StorageLive(_6); + _6 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; } bb4: { - StorageLive(_7); - _7 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); - _8 = discriminant(_7); - switchInt(move _8) -> [1: bb5, 0: bb7, otherwise: bb10]; - } - - bb5: { -- StorageLive(_9); +- StorageLive(_8); + nop; - _9 = copy ((_7 as Some).0: usize); + _8 = copy ((_6 as Some).0: usize); + StorageLive(_9); + _9 = copy _1; StorageLive(_10); - _10 = copy _1; + _10 = copy _2; StorageLive(_11); - _11 = copy _2; + _11 = copy _5; StorageLive(_12); - _12 = copy _6; StorageLive(_13); StorageLive(_14); - StorageLive(_15); - _15 = copy _9; -- _14 = move _15 as u32 (IntToInt); -+ _14 = copy _9 as u32 (IntToInt); - StorageDead(_15); - _13 = Add(move _14, const 1_u32); + _14 = copy _8; +- _13 = move _14 as u32 (IntToInt); ++ _13 = copy _8 as u32 (IntToInt); StorageDead(_14); - StorageLive(_16); - _16 = copy _3; -- _0 = float_to_exponential_common_exact::(move _10, move _11, move _12, move _13, move _16) -> [return: bb6, unwind continue]; -+ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _12, move _13, copy _3) -> [return: bb6, unwind continue]; + _12 = Add(move _13, const 1_u32); + StorageDead(_13); + StorageLive(_15); + _15 = copy _3; +- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind continue]; ++ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _11, move _12, copy _3) -> [return: bb5, unwind continue]; } - bb6: { - StorageDead(_16); - StorageDead(_13); + bb5: { + StorageDead(_15); StorageDead(_12); StorageDead(_11); StorageDead(_10); -- StorageDead(_9); + StorageDead(_9); +- StorageDead(_8); + nop; - goto -> bb9; + goto -> bb8; } - bb7: { + bb6: { + StorageLive(_16); + _16 = copy _1; StorageLive(_17); - _17 = copy _1; + _17 = copy _2; StorageLive(_18); - _18 = copy _2; + _18 = copy _5; StorageLive(_19); - _19 = copy _6; - StorageLive(_20); - _20 = copy _3; -- _0 = float_to_exponential_common_shortest::(move _17, move _18, move _19, move _20) -> [return: bb8, unwind continue]; -+ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _19, copy _3) -> [return: bb8, unwind continue]; + _19 = copy _3; +- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind continue]; ++ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _18, copy _3) -> [return: bb7, unwind continue]; } - bb8: { - StorageDead(_20); + bb7: { StorageDead(_19); StorageDead(_18); StorageDead(_17); - goto -> bb9; + StorageDead(_16); + goto -> bb8; } - bb9: { - StorageDead(_6); + bb8: { + StorageDead(_5); StorageDead(_4); - StorageDead(_7); + StorageDead(_6); return; } - bb10: { + bb9: { unreachable; } }