From 47009956e00d5c4886c062f22695c44a84f37a8d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Feb 2025 23:56:16 +0100 Subject: [PATCH] Reduce FormattingOptions to 64 bit. --- compiler/rustc_ast_lowering/src/expr.rs | 5 - compiler/rustc_ast_lowering/src/format.rs | 40 +- compiler/rustc_hir/src/lang_items.rs | 1 - compiler/rustc_span/src/symbol.rs | 1 - library/core/src/fmt/float.rs | 6 +- library/core/src/fmt/mod.rs | 417 ++++++++++-------- library/core/src/fmt/rt.rs | 21 +- ...onential_common.GVN.32bit.panic-abort.diff | 49 +- ...nential_common.GVN.32bit.panic-unwind.diff | 49 +- ...onential_common.GVN.64bit.panic-abort.diff | 49 +- ...nential_common.GVN.64bit.panic-unwind.diff | 49 +- 11 files changed, 353 insertions(+), 334 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 757e1dbd54b1a..d967772c93bfd 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2162,11 +2162,6 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(sp, hir::ExprKind::Lit(lit)) } - pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Char(value) }); - self.expr(sp, hir::ExprKind::Lit(lit)) - } - pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { let lit = self .arena diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index faa47274f96ce..343895984ca42 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -361,24 +361,26 @@ fn make_format_spec<'hir>( zero_pad, debug_hex, } = &placeholder.format_options; - let fill = ctx.expr_char(sp, fill.unwrap_or(' ')); - let align = ctx.expr_lang_item_type_relative( - sp, - hir::LangItem::FormatAlignment, - match alignment { - Some(FormatAlignment::Left) => sym::Left, - Some(FormatAlignment::Right) => sym::Right, - Some(FormatAlignment::Center) => sym::Center, - None => sym::Unknown, - }, - ); - // This needs to match `Flag` in library/core/src/fmt/rt.rs. - let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) - | ((sign == Some(FormatSign::Minus)) as u32) << 1 - | (alternate as u32) << 2 - | (zero_pad as u32) << 3 - | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4 - | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5; + let fill = fill.unwrap_or(' '); + // These need to match the constants in library/core/src/fmt/rt.rs. + let align = match alignment { + Some(FormatAlignment::Left) => 0, + Some(FormatAlignment::Right) => 1, + Some(FormatAlignment::Center) => 2, + None => 3, + }; + // This needs to match the constants in library/core/src/fmt/rt.rs. + let flags: u32 = fill as u32 + | ((sign == Some(FormatSign::Plus)) as u32) << 21 + | ((sign == Some(FormatSign::Minus)) as u32) << 22 + | (alternate as u32) << 23 + | (zero_pad as u32) << 24 + | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25 + | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26 + | (width.is_some() as u32) << 27 + | (precision.is_some() as u32) << 28 + | align << 29 + | 1 << 31; // Highest bit always set. let flags = ctx.expr_u32(sp, flags); let precision = make_count(ctx, sp, precision, argmap); let width = make_count(ctx, sp, width, argmap); @@ -387,7 +389,7 @@ fn make_format_spec<'hir>( hir::LangItem::FormatPlaceholder, sym::new, )); - let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]); + let args = ctx.arena.alloc_from_iter([position, flags, precision, width]); ctx.expr_call_mut(sp, format_placeholder_new, args) } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 1852987b1677f..35b3f871f5cd9 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -321,7 +321,6 @@ language_item_table! { BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; // Lang items needed for `format_args!()`. - FormatAlignment, sym::format_alignment, format_alignment, Target::Enum, GenericRequirement::None; FormatArgument, sym::format_argument, format_argument, Target::Struct, GenericRequirement::None; FormatArguments, sym::format_arguments, format_arguments, Target::Struct, GenericRequirement::None; FormatCount, sym::format_count, format_count, Target::Enum, GenericRequirement::None; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 534cbf08ae8fc..be48296ef5348 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -975,7 +975,6 @@ symbols! { forbid, forget, format, - format_alignment, format_args, format_args_capture, format_args_macro, diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 4a43c12be9aaa..870ad9df4fd33 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -86,7 +86,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { float_to_decimal_common_exact(fmt, num, sign, precision) } else { let min_precision = 0; @@ -162,7 +162,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { // 1 integral digit + `precision` fractional digits = `precision + 1` total digits float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper) } else { @@ -180,7 +180,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.options.precision { + if let Some(precision) = fmt.options.get_precision() { // this behavior of {:.PREC?} predates exponential formatting for {:?} float_to_decimal_common_exact(fmt, num, sign, precision) } else { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index eab324aec7803..bbd1939a0a9fe 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -33,19 +33,6 @@ pub enum Alignment { Center, } -#[doc(hidden)] -#[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] -impl From 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")] @@ -291,11 +278,50 @@ pub enum DebugAsHex { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "formatting_options", issue = "118117")] pub struct FormattingOptions { + /// Flags, with the following bit fields: + /// + /// ```text + /// 31 30 29 28 27 26 25 24 23 22 21 20 0 + /// ┌───┬───────┬───┬───┬───┬───┬───┬───┬───┬───┬──────────────────────────────────┐ + /// │ 1 │ align │ p │ w │ X?│ x?│'0'│ # │ - │ + │ fill │ + /// └───┴───────┴───┴───┴───┴───┴───┴───┴───┴───┴──────────────────────────────────┘ + /// │ │ │ │ └─┬───────────────────┘ └─┬──────────────────────────────┘ + /// │ │ │ │ │ └─ The fill character (21 bits char). + /// │ │ │ │ └─ The debug upper/lower hex, zero pad, alternate, and plus/minus flags. + /// │ │ │ └─ Whether a width is set. (The value is stored separately.) + /// │ │ └─ Whether a precision is set. (The value is stored separately.) + /// │ ├─ 0: Align left. (<) + /// │ ├─ 1: Align right. (>) + /// │ ├─ 2: Align center. (^) + /// │ └─ 3: Alignment not set. (default) + /// └─ Always set. + /// This makes it possible to distinguish formatting flags from + /// a &str size when stored in (the upper bits of) the same field. + /// (fmt::Arguments will make use of this property in the future.) + /// ``` flags: u32, - fill: char, - align: Option, - width: Option, - precision: Option, + /// Width if width flag (bit 27) above is set. Otherwise, always 0. + width: u16, + /// Precision if precision flag (bit 28) above is set. Otherwise, always 0. + precision: u16, +} + +// This needs to match with compiler/rustc_ast_lowering/src/format.rs. +mod flags { + pub(super) const SIGN_PLUS_FLAG: u32 = 1 << 21; + pub(super) const SIGN_MINUS_FLAG: u32 = 1 << 22; + pub(super) const ALTERNATE_FLAG: u32 = 1 << 23; + pub(super) const SIGN_AWARE_ZERO_PAD_FLAG: u32 = 1 << 24; + pub(super) const DEBUG_LOWER_HEX_FLAG: u32 = 1 << 25; + pub(super) const DEBUG_UPPER_HEX_FLAG: u32 = 1 << 26; + pub(super) const WIDTH_FLAG: u32 = 1 << 27; + pub(super) const PRECISION_FLAG: u32 = 1 << 28; + pub(super) const ALIGN_BITS: u32 = 0b11 << 29; + pub(super) const ALIGN_LEFT: u32 = 0 << 29; + pub(super) const ALIGN_RIGHT: u32 = 1 << 29; + pub(super) const ALIGN_CENTER: u32 = 2 << 29; + pub(super) const ALIGN_UNKNOWN: u32 = 3 << 29; + pub(super) const ALWAYS_SET: u32 = 1 << 31; } impl FormattingOptions { @@ -311,7 +337,11 @@ impl FormattingOptions { /// - no [`DebugAsHex`] output mode. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn new() -> Self { - Self { flags: 0, fill: ' ', align: None, width: None, precision: None } + Self { + flags: ' ' as u32 | flags::ALIGN_UNKNOWN | flags::ALWAYS_SET, + width: 0, + precision: 0, + } } /// Sets or removes the sign (the `+` or the `-` flag). @@ -324,13 +354,12 @@ impl FormattingOptions { /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] 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 { - None => {} - Some(Sign::Plus) => self.flags |= 1 << rt::Flag::SignPlus as u32, - Some(Sign::Minus) => self.flags |= 1 << rt::Flag::SignMinus as u32, - } + let sign = match sign { + None => 0, + Some(Sign::Plus) => flags::SIGN_PLUS_FLAG, + Some(Sign::Minus) => flags::SIGN_MINUS_FLAG, + }; + self.flags = self.flags & !(flags::SIGN_PLUS_FLAG | flags::SIGN_MINUS_FLAG) | sign; self } /// Sets or unsets the `0` flag. @@ -339,9 +368,9 @@ impl FormattingOptions { #[unstable(feature = "formatting_options", issue = "118117")] pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { if sign_aware_zero_pad { - self.flags |= 1 << rt::Flag::SignAwareZeroPad as u32 + self.flags |= flags::SIGN_AWARE_ZERO_PAD_FLAG; } else { - self.flags &= !(1 << rt::Flag::SignAwareZeroPad as u32) + self.flags &= !flags::SIGN_AWARE_ZERO_PAD_FLAG; } self } @@ -356,9 +385,9 @@ impl FormattingOptions { #[unstable(feature = "formatting_options", issue = "118117")] pub fn alternate(&mut self, alternate: bool) -> &mut Self { if alternate { - self.flags |= 1 << rt::Flag::Alternate as u32 + self.flags |= flags::ALTERNATE_FLAG; } else { - self.flags &= !(1 << rt::Flag::Alternate as u32) + self.flags &= !flags::ALTERNATE_FLAG; } self } @@ -370,7 +399,7 @@ impl FormattingOptions { /// printed around it. #[unstable(feature = "formatting_options", issue = "118117")] pub fn fill(&mut self, fill: char) -> &mut Self { - self.fill = fill; + self.flags = self.flags & (u32::MAX << 21) | fill as u32; self } /// Sets or removes the alignment. @@ -379,7 +408,13 @@ impl FormattingOptions { /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] pub fn align(&mut self, align: Option) -> &mut Self { - self.align = align; + let align: u32 = match align { + Some(Alignment::Left) => flags::ALIGN_LEFT, + Some(Alignment::Right) => flags::ALIGN_RIGHT, + Some(Alignment::Center) => flags::ALIGN_CENTER, + None => flags::ALIGN_UNKNOWN, + }; + self.flags = self.flags & !flags::ALIGN_BITS | align; self } /// Sets or removes the width. @@ -390,7 +425,13 @@ impl FormattingOptions { /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] pub fn width(&mut self, width: Option) -> &mut Self { - self.width = width; + if let Some(width) = width { + self.flags |= flags::WIDTH_FLAG; + self.width = width; + } else { + self.flags &= !flags::WIDTH_FLAG; + self.width = 0; + } self } /// Sets or removes the precision. @@ -404,77 +445,85 @@ impl FormattingOptions { /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] pub fn precision(&mut self, precision: Option) -> &mut Self { - self.precision = precision; + if let Some(precision) = precision { + self.flags |= flags::PRECISION_FLAG; + self.precision = precision; + } else { + self.flags &= !flags::PRECISION_FLAG; + self.precision = 0; + } self } /// Specifies whether the [`Debug`] trait should use lower-/upper-case /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] pub fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { - self.flags = self.flags - & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); - match debug_as_hex { - None => {} - Some(DebugAsHex::Upper) => self.flags |= 1 << rt::Flag::DebugUpperHex as u32, - Some(DebugAsHex::Lower) => self.flags |= 1 << rt::Flag::DebugLowerHex as u32, - } + let debug_as_hex = match debug_as_hex { + None => 0, + Some(DebugAsHex::Lower) => flags::DEBUG_LOWER_HEX_FLAG, + Some(DebugAsHex::Upper) => flags::DEBUG_UPPER_HEX_FLAG, + }; + self.flags = self.flags & !(flags::DEBUG_LOWER_HEX_FLAG | flags::DEBUG_UPPER_HEX_FLAG) + | debug_as_hex; self } /// Returns the current sign (the `+` or the `-` flag). #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign(&self) -> Option { - const SIGN_PLUS_BITFIELD: u32 = 1 << rt::Flag::SignPlus as u32; - const SIGN_MINUS_BITFIELD: u32 = 1 << rt::Flag::SignMinus as u32; - match self.flags & ((1 << rt::Flag::SignPlus as u32) | (1 << rt::Flag::SignMinus as u32)) { - SIGN_PLUS_BITFIELD => Some(Sign::Plus), - SIGN_MINUS_BITFIELD => Some(Sign::Minus), - 0 => None, - _ => panic!("Invalid sign bits set in flags"), + if self.flags & flags::SIGN_PLUS_FLAG != 0 { + Some(Sign::Plus) + } else if self.flags & flags::SIGN_MINUS_FLAG != 0 { + Some(Sign::Minus) + } else { + None } } /// Returns the current `0` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign_aware_zero_pad(&self) -> bool { - self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 + self.flags & flags::SIGN_AWARE_ZERO_PAD_FLAG != 0 } /// Returns the current `#` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_alternate(&self) -> bool { - self.flags & (1 << rt::Flag::Alternate as u32) != 0 + self.flags & flags::ALTERNATE_FLAG != 0 } /// Returns the current fill character. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_fill(&self) -> char { - self.fill + // SAFETY: We only ever put a valid `char` in the lower 21 bits of the flags field. + unsafe { char::from_u32_unchecked(self.flags & 0x1FFFFF) } } /// Returns the current alignment. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_align(&self) -> Option { - self.align + match self.flags & flags::ALIGN_BITS { + flags::ALIGN_LEFT => Some(Alignment::Left), + flags::ALIGN_RIGHT => Some(Alignment::Right), + flags::ALIGN_CENTER => Some(Alignment::Center), + _ => None, + } } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_width(&self) -> Option { - self.width + if self.flags & flags::WIDTH_FLAG != 0 { Some(self.width) } else { None } } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_precision(&self) -> Option { - self.precision + if self.flags & flags::PRECISION_FLAG != 0 { Some(self.precision) } else { None } } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_debug_as_hex(&self) -> Option { - const DEBUG_UPPER_BITFIELD: u32 = 1 << rt::Flag::DebugUpperHex as u32; - const DEBUG_LOWER_BITFIELD: u32 = 1 << rt::Flag::DebugLowerHex as u32; - match self.flags - & ((1 << rt::Flag::DebugUpperHex as u32) | (1 << rt::Flag::DebugLowerHex as u32)) - { - DEBUG_UPPER_BITFIELD => Some(DebugAsHex::Upper), - DEBUG_LOWER_BITFIELD => Some(DebugAsHex::Lower), - 0 => None, - _ => panic!("Invalid hex debug bits set in flags"), + if self.flags & flags::DEBUG_LOWER_HEX_FLAG != 0 { + Some(DebugAsHex::Lower) + } else if self.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 { + Some(DebugAsHex::Upper) + } else { + None } } @@ -485,27 +534,6 @@ impl FormattingOptions { pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { options: self, buf: write } } - - #[doc(hidden)] - #[unstable( - feature = "fmt_internals", - reason = "internal routines only exposed for testing", - issue = "none" - )] - /// Flags for formatting - pub fn flags(&mut self, flags: u32) { - self.flags = flags - } - #[doc(hidden)] - #[unstable( - feature = "fmt_internals", - reason = "internal routines only exposed for testing", - issue = "none" - )] - /// Flags for formatting - pub fn get_flags(&self) -> u32 { - self.flags - } } #[unstable(feature = "formatting_options", issue = "118117")] @@ -1478,15 +1506,24 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { } unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { - fmt.options.fill = arg.fill; - fmt.options.align = arg.align.into(); - fmt.options.flags = arg.flags; - // SAFETY: arg and args come from the same Arguments, - // which guarantees the indexes are always within bounds. - unsafe { - fmt.options.width = getcount(args, &arg.width); - fmt.options.precision = getcount(args, &arg.precision); - } + let (width, precision) = + // SAFETY: arg and args come from the same Arguments, + // which guarantees the indexes are always within bounds. + unsafe { (getcount(args, &arg.width), getcount(args, &arg.precision)) }; + + #[cfg(bootstrap)] + let options = *FormattingOptions { flags: arg.flags << 21, width: 0, precision: 0 } + .align(match arg.align { + rt::Alignment::Left => Some(Alignment::Left), + rt::Alignment::Right => Some(Alignment::Right), + rt::Alignment::Center => Some(Alignment::Center), + rt::Alignment::Unknown => None, + }) + .fill(arg.fill) + .width(width) + .precision(precision); + #[cfg(not(bootstrap))] + let options = FormattingOptions { flags: arg.flags, width, precision }; // Extract the correct argument debug_assert!(arg.position < args.len()); @@ -1494,17 +1531,18 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume // which guarantees its index is always within bounds. let value = unsafe { args.get_unchecked(arg.position) }; + // Set all the formatting options. + fmt.options = options; + // Then actually do some printing // SAFETY: this is a placeholder argument. unsafe { value.fmt(fmt) } } +#[cfg(bootstrap)] unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { match *cnt { - #[cfg(bootstrap)] rt::Count::Is(n) => Some(n as u16), - #[cfg(not(bootstrap))] - rt::Count::Is(n) => Some(n), rt::Count::Implied => None, rt::Count::Param(i) => { debug_assert!(i < args.len()); @@ -1515,6 +1553,20 @@ unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { } } +#[cfg(not(bootstrap))] +unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> u16 { + match *cnt { + rt::Count::Is(n) => n, + rt::Count::Implied => 0, + rt::Count::Param(i) => { + debug_assert!(i < args.len()); + // SAFETY: cnt and args come from the same Arguments, + // which guarantees this index is always within bounds. + unsafe { args.get_unchecked(i).as_u16().unwrap_unchecked() } + } + } +} + /// Padding after the end of something. Returned by `Formatter::padding`. #[must_use = "don't forget to write the post padding"] pub(crate) struct PostPadding { @@ -1628,40 +1680,28 @@ impl<'a> Formatter<'a> { } // The `width` field is more of a `min-width` parameter at this point. - match self.options.width { - // If there's no minimum length requirements then we can just - // write the bytes. - None => { - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf) - } - // Check if we're over the minimum width, if so then we can also - // just write the bytes. - Some(min) if width >= usize::from(min) => { - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf) - } + let min = self.options.width; + if width >= usize::from(min) { + // We're over the minimum width, so then we can just write the bytes. + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf) + } else if self.sign_aware_zero_pad() { // The sign and prefix goes before the padding if the fill character // is zero - Some(min) if self.sign_aware_zero_pad() => { - let old_fill = crate::mem::replace(&mut self.options.fill, '0'); - let old_align = - crate::mem::replace(&mut self.options.align, Some(Alignment::Right)); - write_prefix(self, sign, prefix)?; - let post_padding = self.padding(min - width as u16, Alignment::Right)?; - self.buf.write_str(buf)?; - post_padding.write(self)?; - self.options.fill = old_fill; - self.options.align = old_align; - Ok(()) - } + let old_options = self.options; + self.options.fill('0').align(Some(Alignment::Right)); + write_prefix(self, sign, prefix)?; + let post_padding = self.padding(min - width as u16, Alignment::Right)?; + self.buf.write_str(buf)?; + post_padding.write(self)?; + self.options = old_options; + Ok(()) + } else { // Otherwise, the sign and prefix goes after the padding - Some(min) => { - let post_padding = self.padding(min - width as u16, Alignment::Right)?; - write_prefix(self, sign, prefix)?; - self.buf.write_str(buf)?; - post_padding.write(self) - } + let post_padding = self.padding(min - width as u16, Alignment::Right)?; + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf)?; + post_padding.write(self) } } @@ -1697,12 +1737,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.options.width.is_none() && self.options.precision.is_none() { + if self.options.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { return self.buf.write_str(s); } // The `precision` field can be interpreted as a `max-width` for the // string being formatted. - let s = if let Some(max) = self.options.precision { + let s = if let Some(max) = self.options.get_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. @@ -1719,25 +1759,24 @@ impl<'a> Formatter<'a> { &s }; // The `width` field is more of a `min-width` parameter at this point. - match self.options.width { + if self.options.width == 0 { // 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), - Some(width) => { - let chars_count = s.chars().count(); - // If we're under the maximum width, check if we're over the minimum - // width, if so it's as easy as just emitting the string. - if chars_count >= usize::from(width) { - self.buf.write_str(s) - } - // If we're under both the maximum and the minimum width, then fill - // up the minimum width with the specified string + some alignment. - else { - let align = Alignment::Left; - let post_padding = self.padding(width - chars_count as u16, align)?; - self.buf.write_str(s)?; - post_padding.write(self) - } + self.buf.write_str(s) + } else { + let chars_count = s.chars().count(); + // If we're under the maximum width, check if we're over the minimum + // width, if so it's as easy as just emitting the string. + if chars_count >= usize::from(self.options.width) { + self.buf.write_str(s) + } + // If we're under both the maximum and the minimum width, then fill + // up the minimum width with the specified string + some alignment. + else { + let align = Alignment::Left; + let post_padding = self.padding(self.options.width - chars_count as u16, align)?; + self.buf.write_str(s)?; + post_padding.write(self) } } } @@ -1751,19 +1790,20 @@ impl<'a> Formatter<'a> { padding: u16, default: Alignment, ) -> result::Result { - let align = self.align().unwrap_or(default); + let align = self.options.get_align().unwrap_or(default); + let fill = self.options.get_fill(); - let (pre_pad, post_pad) = match align { - Alignment::Left => (0, padding), - Alignment::Right => (padding, 0), - Alignment::Center => (padding / 2, (padding + 1) / 2), + let padding_left = match align { + Alignment::Left => 0, + Alignment::Right => padding, + Alignment::Center => padding / 2, }; - for _ in 0..pre_pad { - self.buf.write_char(self.options.fill)?; + for _ in 0..padding_left { + self.buf.write_char(fill)?; } - Ok(PostPadding::new(self.options.fill, post_pad)) + Ok(PostPadding::new(fill, padding - padding_left)) } /// Takes the formatted parts and applies the padding. @@ -1775,12 +1815,16 @@ impl<'a> Formatter<'a> { /// /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { - if let Some(mut width) = self.options.width { + if self.options.width == 0 { + // this is the common case and we take a shortcut + // SAFETY: Per the precondition. + unsafe { self.write_formatted_parts(formatted) } + } else { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. let mut formatted = formatted.clone(); - let old_fill = self.options.fill; - let old_align = self.options.align; + let mut width = self.options.width; + let old_options = self.options; if self.sign_aware_zero_pad() { // a sign always goes first let sign = formatted.sign; @@ -1789,8 +1833,7 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; width = width.saturating_sub(sign.len() as u16); - self.options.fill = '0'; - self.options.align = Some(Alignment::Right); + self.options.fill('0').align(Some(Alignment::Right)); } // remaining parts go through the ordinary padding process. @@ -1807,13 +1850,8 @@ impl<'a> Formatter<'a> { } post_padding.write(self) }; - self.options.fill = old_fill; - self.options.align = old_align; + self.options = old_options; ret - } else { - // this is the common case and we take a shortcut - // SAFETY: Per the precondition. - unsafe { self.write_formatted_parts(formatted) } } } @@ -1934,7 +1972,9 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead" )] pub fn flags(&self) -> u32 { - self.options.flags + // Extract the debug upper/lower hex, zero pad, alternate, and plus/minus flags + // to stay compatible with older versions of Rust. + self.options.flags >> 21 & 0x3F } /// Returns the character used as 'fill' whenever there is alignment. @@ -1967,7 +2007,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { - self.options.fill + self.options.get_fill() } /// Returns a flag indicating what form of alignment was requested. @@ -2002,7 +2042,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { - self.options.align + self.options.get_align() } /// Returns the optionally specified integer width that the output should be. @@ -2032,7 +2072,11 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.options.width.map(|x| x as usize) + if self.options.flags & flags::WIDTH_FLAG == 0 { + None + } else { + Some(self.options.width as usize) + } } /// Returns the optionally specified precision for numeric types. @@ -2063,7 +2107,11 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.options.precision.map(|x| x as usize) + if self.options.flags & flags::PRECISION_FLAG == 0 { + None + } else { + Some(self.options.precision as usize) + } } /// Determines if the `+` flag was specified. @@ -2095,7 +2143,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignPlus as u32) != 0 + self.options.flags & flags::SIGN_PLUS_FLAG != 0 } /// Determines if the `-` flag was specified. @@ -2124,7 +2172,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignMinus as u32) != 0 + self.options.flags & flags::SIGN_MINUS_FLAG != 0 } /// Determines if the `#` flag was specified. @@ -2152,7 +2200,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.options.flags & (1 << rt::Flag::Alternate as u32) != 0 + self.options.flags & flags::ALTERNATE_FLAG != 0 } /// Determines if the `0` flag was specified. @@ -2178,17 +2226,16 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.options.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 + self.options.flags & flags::SIGN_AWARE_ZERO_PAD_FLAG != 0 } // FIXME: Decide what public API we want for these two flags. // https://github.com/rust-lang/rust/issues/48584 fn debug_lower_hex(&self) -> bool { - self.options.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 + self.options.flags & flags::DEBUG_LOWER_HEX_FLAG != 0 } - fn debug_upper_hex(&self) -> bool { - self.options.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 + self.options.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 } /// Creates a [`DebugStruct`] builder designed to assist with creation of @@ -2768,7 +2815,7 @@ impl Debug for char { #[stable(feature = "rust1", since = "1.0.0")] impl Display for char { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - if f.options.width.is_none() && f.options.precision.is_none() { + if f.options.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; 4])) @@ -2792,26 +2839,24 @@ 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.options.width; - let old_flags = f.options.flags; + let old_options = f.options; // The alternate flag is already treated by LowerHex as being special- // it denotes whether to prefix with 0x. We use it to work out whether // or not to zero extend, and then unconditionally set it to get the // prefix. - if f.alternate() { - f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); + if f.options.get_alternate() { + f.options.sign_aware_zero_pad(true); - if f.options.width.is_none() { - f.options.width = Some((usize::BITS / 4) as u16 + 2); + if f.options.get_width().is_none() { + f.options.width(Some((usize::BITS / 4) as u16 + 2)); } } - f.options.flags |= 1 << (rt::Flag::Alternate as u32); + f.options.alternate(true); let ret = LowerHex::fmt(&ptr_addr, f); - f.options.width = old_width; - f.options.flags = old_flags; + f.options = old_options; ret } diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index cb908adc1cbaf..f6d5d2746b29e 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -11,7 +11,9 @@ use crate::ptr::NonNull; #[derive(Copy, Clone)] pub struct Placeholder { pub position: usize, + #[cfg(bootstrap)] pub fill: char, + #[cfg(bootstrap)] pub align: Alignment, pub flags: u32, pub precision: Count, @@ -19,6 +21,7 @@ pub struct Placeholder { } impl Placeholder { + #[cfg(bootstrap)] #[inline] pub const fn new( position: usize, @@ -30,8 +33,15 @@ impl Placeholder { ) -> Self { Self { position, fill, align, flags, precision, width } } + + #[cfg(not(bootstrap))] + #[inline] + pub const fn new(position: usize, flags: u32, precision: Count, width: Count) -> Self { + Self { position, flags, precision, width } + } } +#[cfg(bootstrap)] #[lang = "format_alignment"] #[derive(Copy, Clone, PartialEq, Eq)] pub enum Alignment { @@ -58,17 +68,6 @@ pub enum Count { Implied, } -// This needs to match the order of flags in compiler/rustc_ast_lowering/src/format.rs. -#[derive(Copy, Clone)] -pub(super) enum Flag { - SignPlus, - SignMinus, - Alternate, - SignAwareZeroPad, - DebugLowerHex, - DebugUpperHex, -} - #[derive(Copy, Clone)] enum ArgumentType<'a> { Placeholder { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff index 45fc7365d8d6c..6baa902b6f4bd 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff @@ -29,16 +29,10 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { - let mut _22: std::option::Option; - scope 6 (inlined Option::::map::::precision::{closure#0}}>) { - let mut _23: isize; - let _24: u16; - let mut _25: usize; - scope 7 { - scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { - } - } - } + let mut _22: u32; + let mut _23: u32; + let mut _24: usize; + let mut _25: u16; } } } @@ -53,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const 1_u32); + _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -75,12 +69,12 @@ bb3: { StorageLive(_6); - StorageLive(_24); StorageLive(_22); - _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); StorageLive(_23); - _23 = discriminant(_22); - switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + StorageDead(_23); + switchInt(move _22) -> [0: bb10, otherwise: bb11]; } bb4: { @@ -148,30 +142,31 @@ } bb9: { - StorageDead(_23); - StorageDead(_22); - StorageDead(_24); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12]; } bb10: { - unreachable; - } - - bb11: { + StorageDead(_22); _6 = const Option::::None; goto -> bb9; } - bb12: { - _24 = move ((_22 as Some).0: u16); + bb11: { + StorageDead(_22); + StorageLive(_24); StorageLive(_25); - _25 = copy _24 as usize (IntToInt); - _6 = Option::::Some(move _25); + _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16); + _24 = move _25 as usize (IntToInt); StorageDead(_25); + _6 = Option::::Some(move _24); + StorageDead(_24); goto -> bb9; } + + bb12: { + unreachable; + } } ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff index 578d2c2194b0e..36540e038654f 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff @@ -29,16 +29,10 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { - let mut _22: std::option::Option; - scope 6 (inlined Option::::map::::precision::{closure#0}}>) { - let mut _23: isize; - let _24: u16; - let mut _25: usize; - scope 7 { - scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { - } - } - } + let mut _22: u32; + let mut _23: u32; + let mut _24: usize; + let mut _25: u16; } } } @@ -53,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const 1_u32); + _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -75,12 +69,12 @@ bb3: { StorageLive(_6); - StorageLive(_24); StorageLive(_22); - _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); StorageLive(_23); - _23 = discriminant(_22); - switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + StorageDead(_23); + switchInt(move _22) -> [0: bb10, otherwise: bb11]; } bb4: { @@ -148,30 +142,31 @@ } bb9: { - StorageDead(_23); - StorageDead(_22); - StorageDead(_24); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12]; } bb10: { - unreachable; - } - - bb11: { + StorageDead(_22); _6 = const Option::::None; goto -> bb9; } - bb12: { - _24 = move ((_22 as Some).0: u16); + bb11: { + StorageDead(_22); + StorageLive(_24); StorageLive(_25); - _25 = copy _24 as usize (IntToInt); - _6 = Option::::Some(move _25); + _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16); + _24 = move _25 as usize (IntToInt); StorageDead(_25); + _6 = Option::::Some(move _24); + StorageDead(_24); goto -> bb9; } + + bb12: { + unreachable; + } } ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff index 5f0f7d6cc74fb..41c350f3eaeb5 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff @@ -29,16 +29,10 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { - let mut _22: std::option::Option; - scope 6 (inlined Option::::map::::precision::{closure#0}}>) { - let mut _23: isize; - let _24: u16; - let mut _25: usize; - scope 7 { - scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { - } - } - } + let mut _22: u32; + let mut _23: u32; + let mut _24: usize; + let mut _25: u16; } } } @@ -53,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const 1_u32); + _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -75,12 +69,12 @@ bb3: { StorageLive(_6); - StorageLive(_24); StorageLive(_22); - _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); StorageLive(_23); - _23 = discriminant(_22); - switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + StorageDead(_23); + switchInt(move _22) -> [0: bb10, otherwise: bb11]; } bb4: { @@ -148,30 +142,31 @@ } bb9: { - StorageDead(_23); - StorageDead(_22); - StorageDead(_24); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12]; } bb10: { - unreachable; - } - - bb11: { + StorageDead(_22); _6 = const Option::::None; goto -> bb9; } - bb12: { - _24 = move ((_22 as Some).0: u16); + bb11: { + StorageDead(_22); + StorageLive(_24); StorageLive(_25); - _25 = copy _24 as usize (IntToInt); - _6 = Option::::Some(move _25); + _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16); + _24 = move _25 as usize (IntToInt); StorageDead(_25); + _6 = Option::::Some(move _24); + StorageDead(_24); goto -> bb9; } + + bb12: { + unreachable; + } } ALLOC0 (size: 16, align: 8) { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff index 10cc46a8b8285..b839bf81eaf45 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff @@ -29,16 +29,10 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { - let mut _22: std::option::Option; - scope 6 (inlined Option::::map::::precision::{closure#0}}>) { - let mut _23: isize; - let _24: u16; - let mut _25: usize; - scope 7 { - scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { - } - } - } + let mut _22: u32; + let mut _23: u32; + let mut _24: usize; + let mut _25: u16; } } } @@ -53,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const 1_u32); + _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -75,12 +69,12 @@ bb3: { StorageLive(_6); - StorageLive(_24); StorageLive(_22); - _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); StorageLive(_23); - _23 = discriminant(_22); - switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + StorageDead(_23); + switchInt(move _22) -> [0: bb10, otherwise: bb11]; } bb4: { @@ -148,30 +142,31 @@ } bb9: { - StorageDead(_23); - StorageDead(_22); - StorageDead(_24); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12]; } bb10: { - unreachable; - } - - bb11: { + StorageDead(_22); _6 = const Option::::None; goto -> bb9; } - bb12: { - _24 = move ((_22 as Some).0: u16); + bb11: { + StorageDead(_22); + StorageLive(_24); StorageLive(_25); - _25 = copy _24 as usize (IntToInt); - _6 = Option::::Some(move _25); + _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16); + _24 = move _25 as usize (IntToInt); StorageDead(_25); + _6 = Option::::Some(move _24); + StorageDead(_24); goto -> bb9; } + + bb12: { + unreachable; + } } ALLOC0 (size: 16, align: 8) {