Auto merge of #136974 - m-ou-se:fmt-options-64-bit, r=scottmcm

Reduce FormattingOptions to 64 bits

This is part of https://github.com/rust-lang/rust/issues/99012

This reduces FormattingOptions from 6-7 machine words (384 bits on 64-bit platforms, 224 bits on 32-bit platforms) to just 64 bits (a single register on 64-bit platforms).

Before:

```rust
pub struct FormattingOptions {
    flags: u32, // only 6 bits used
    fill: char,
    align: Option<Alignment>,
    width: Option<usize>,
    precision: Option<usize>,
}
```

After:

```rust
pub struct FormattingOptions {
    /// Bits:
    ///  - 0-20: fill character (21 bits, a full `char`)
    ///  - 21: `+` flag
    ///  - 22: `-` flag
    ///  - 23: `#` flag
    ///  - 24: `0` flag
    ///  - 25: `x?` flag
    ///  - 26: `X?` flag
    ///  - 27: Width flag (if set, the width field below is used)
    ///  - 28: Precision flag (if set, the precision field below is used)
    ///  - 29-30: Alignment (0: Left, 1: Right, 2: Center, 3: Unknown)
    ///  - 31: Always set to 1
    flags: u32,
    /// Width if width flag above is set. Otherwise, always 0.
    width: u16,
    /// Precision if precision flag above is set. Otherwise, always 0.
    precision: u16,
}
```
This commit is contained in:
bors 2025-03-22 10:56:14 +00:00
commit 0ce1369bde
12 changed files with 363 additions and 321 deletions

View file

@ -2150,11 +2150,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.expr_uint(sp, ast::UintTy::U16, value as u128) self.expr_uint(sp, ast::UintTy::U16, value as u128)
} }
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> { pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
let lit = self let lit = self
.arena .arena

View file

@ -361,24 +361,26 @@ fn make_format_spec<'hir>(
zero_pad, zero_pad,
debug_hex, debug_hex,
} = &placeholder.format_options; } = &placeholder.format_options;
let fill = ctx.expr_char(sp, fill.unwrap_or(' ')); let fill = fill.unwrap_or(' ');
let align = ctx.expr_lang_item_type_relative( // These need to match the constants in library/core/src/fmt/rt.rs.
sp, let align = match alignment {
hir::LangItem::FormatAlignment, Some(FormatAlignment::Left) => 0,
match alignment { Some(FormatAlignment::Right) => 1,
Some(FormatAlignment::Left) => sym::Left, Some(FormatAlignment::Center) => 2,
Some(FormatAlignment::Right) => sym::Right, None => 3,
Some(FormatAlignment::Center) => sym::Center, };
None => sym::Unknown, // 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
// This needs to match `Flag` in library/core/src/fmt/rt.rs. | ((sign == Some(FormatSign::Minus)) as u32) << 22
let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) | (alternate as u32) << 23
| ((sign == Some(FormatSign::Minus)) as u32) << 1 | (zero_pad as u32) << 24
| (alternate as u32) << 2 | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
| (zero_pad as u32) << 3 | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
| ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4 | (width.is_some() as u32) << 27
| ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5; | (precision.is_some() as u32) << 28
| align << 29
| 1 << 31; // Highest bit always set.
let flags = ctx.expr_u32(sp, flags); let flags = ctx.expr_u32(sp, flags);
let precision = make_count(ctx, sp, precision, argmap); let precision = make_count(ctx, sp, precision, argmap);
let width = make_count(ctx, sp, width, argmap); let width = make_count(ctx, sp, width, argmap);
@ -387,7 +389,7 @@ fn make_format_spec<'hir>(
hir::LangItem::FormatPlaceholder, hir::LangItem::FormatPlaceholder,
sym::new, 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) ctx.expr_call_mut(sp, format_placeholder_new, args)
} }

View file

@ -322,7 +322,6 @@ language_item_table! {
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
// Lang items needed for `format_args!()`. // 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; FormatArgument, sym::format_argument, format_argument, Target::Struct, GenericRequirement::None;
FormatArguments, sym::format_arguments, format_arguments, Target::Struct, GenericRequirement::None; FormatArguments, sym::format_arguments, format_arguments, Target::Struct, GenericRequirement::None;
FormatCount, sym::format_count, format_count, Target::Enum, GenericRequirement::None; FormatCount, sym::format_count, format_count, Target::Enum, GenericRequirement::None;

View file

@ -1003,7 +1003,6 @@ symbols! {
forbid, forbid,
forget, forget,
format, format,
format_alignment,
format_args, format_args,
format_args_capture, format_args_capture,
format_args_macro, format_args_macro,

View file

@ -86,7 +86,7 @@ where
true => flt2dec::Sign::MinusPlus, 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) float_to_decimal_common_exact(fmt, num, sign, precision)
} else { } else {
let min_precision = 0; let min_precision = 0;
@ -162,7 +162,7 @@ where
true => flt2dec::Sign::MinusPlus, 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 // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper) float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
} else { } else {
@ -180,7 +180,7 @@ where
true => flt2dec::Sign::MinusPlus, 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 {:?} // this behavior of {:.PREC?} predates exponential formatting for {:?}
float_to_decimal_common_exact(fmt, num, sign, precision) float_to_decimal_common_exact(fmt, num, sign, precision)
} else { } else {

View file

@ -33,19 +33,6 @@ pub enum Alignment {
Center, Center,
} }
#[doc(hidden)]
#[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")]
impl From<rt::Alignment> for Option<Alignment> {
fn from(value: rt::Alignment) -> Self {
match value {
rt::Alignment::Left => Some(Alignment::Left),
rt::Alignment::Right => Some(Alignment::Right),
rt::Alignment::Center => Some(Alignment::Center),
rt::Alignment::Unknown => None,
}
}
}
#[stable(feature = "debug_builders", since = "1.2.0")] #[stable(feature = "debug_builders", since = "1.2.0")]
pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
#[unstable(feature = "debug_closure_helpers", issue = "117729")] #[unstable(feature = "debug_closure_helpers", issue = "117729")]
@ -291,11 +278,52 @@ pub enum DebugAsHex {
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub struct FormattingOptions { pub struct FormattingOptions {
/// Flags, with the following bit fields:
///
/// ```text
/// 31 30 29 28 27 26 25 24 23 22 21 20 0
/// ┌───┬───────┬───┬───┬───┬───┬───┬───┬───┬───┬──────────────────────────────────┐
/// │ 1 │ align │ p │ w │ X?│ x?│'0'│ # │ - │ + │ fill │
/// └───┴───────┴───┴───┴───┴───┴───┴───┴───┴───┴──────────────────────────────────┘
/// │ │ │ │ └─┬───────────────────┘ └─┬──────────────────────────────┘
/// │ │ │ │ │ └─ The fill character (21 bits char).
/// │ │ │ │ └─ The debug upper/lower hex, zero pad, alternate, and plus/minus flags.
/// │ │ │ └─ Whether a width is set. (The value is stored separately.)
/// │ │ └─ Whether a precision is set. (The value is stored separately.)
/// │ ├─ 0: Align left. (<)
/// │ ├─ 1: Align right. (>)
/// │ ├─ 2: Align center. (^)
/// │ └─ 3: Alignment not set. (default)
/// └─ Always set.
/// This makes it possible to distinguish formatting flags from
/// a &str size when stored in (the upper bits of) the same field.
/// (fmt::Arguments will make use of this property in the future.)
/// ```
// Note: This could use a special niche type with range 0x8000_0000..=0xfdd0ffff.
// It's unclear if that's useful, though.
flags: u32, flags: u32,
fill: char, /// Width if width flag (bit 27) above is set. Otherwise, always 0.
align: Option<Alignment>, width: u16,
width: Option<u16>, /// Precision if precision flag (bit 28) above is set. Otherwise, always 0.
precision: Option<u16>, 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 { impl FormattingOptions {
@ -311,7 +339,11 @@ impl FormattingOptions {
/// - no [`DebugAsHex`] output mode. /// - no [`DebugAsHex`] output mode.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn new() -> Self { 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). /// Sets or removes the sign (the `+` or the `-` flag).
@ -324,13 +356,12 @@ impl FormattingOptions {
/// - `-`: Currently not used /// - `-`: Currently not used
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self { pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self {
self.flags = let sign = match sign {
self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); None => 0,
match sign { Some(Sign::Plus) => flags::SIGN_PLUS_FLAG,
None => {} Some(Sign::Minus) => flags::SIGN_MINUS_FLAG,
Some(Sign::Plus) => self.flags |= 1 << rt::Flag::SignPlus as u32, };
Some(Sign::Minus) => self.flags |= 1 << rt::Flag::SignMinus as u32, self.flags = self.flags & !(flags::SIGN_PLUS_FLAG | flags::SIGN_MINUS_FLAG) | sign;
}
self self
} }
/// Sets or unsets the `0` flag. /// Sets or unsets the `0` flag.
@ -339,9 +370,9 @@ impl FormattingOptions {
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub 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 { if sign_aware_zero_pad {
self.flags |= 1 << rt::Flag::SignAwareZeroPad as u32 self.flags |= flags::SIGN_AWARE_ZERO_PAD_FLAG;
} else { } else {
self.flags &= !(1 << rt::Flag::SignAwareZeroPad as u32) self.flags &= !flags::SIGN_AWARE_ZERO_PAD_FLAG;
} }
self self
} }
@ -356,9 +387,9 @@ impl FormattingOptions {
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub fn alternate(&mut self, alternate: bool) -> &mut Self { pub fn alternate(&mut self, alternate: bool) -> &mut Self {
if alternate { if alternate {
self.flags |= 1 << rt::Flag::Alternate as u32 self.flags |= flags::ALTERNATE_FLAG;
} else { } else {
self.flags &= !(1 << rt::Flag::Alternate as u32) self.flags &= !flags::ALTERNATE_FLAG;
} }
self self
} }
@ -370,7 +401,7 @@ impl FormattingOptions {
/// printed around it. /// printed around it.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub fn fill(&mut self, fill: char) -> &mut Self { pub fn fill(&mut self, fill: char) -> &mut Self {
self.fill = fill; self.flags = self.flags & (u32::MAX << 21) | fill as u32;
self self
} }
/// Sets or removes the alignment. /// Sets or removes the alignment.
@ -379,7 +410,13 @@ impl FormattingOptions {
/// positioned if it is smaller than the width of the formatter. /// positioned if it is smaller than the width of the formatter.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub fn align(&mut self, align: Option<Alignment>) -> &mut Self { pub fn align(&mut self, align: Option<Alignment>) -> &mut Self {
self.align = align; let align: u32 = match align {
Some(Alignment::Left) => flags::ALIGN_LEFT,
Some(Alignment::Right) => flags::ALIGN_RIGHT,
Some(Alignment::Center) => flags::ALIGN_CENTER,
None => flags::ALIGN_UNKNOWN,
};
self.flags = self.flags & !flags::ALIGN_BITS | align;
self self
} }
/// Sets or removes the width. /// Sets or removes the width.
@ -390,7 +427,13 @@ impl FormattingOptions {
/// will be used to take up the required space. /// will be used to take up the required space.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub fn width(&mut self, width: Option<u16>) -> &mut Self { pub fn width(&mut self, width: Option<u16>) -> &mut Self {
if let Some(width) = width {
self.flags |= flags::WIDTH_FLAG;
self.width = width; self.width = width;
} else {
self.flags &= !flags::WIDTH_FLAG;
self.width = 0;
}
self self
} }
/// Sets or removes the precision. /// Sets or removes the precision.
@ -404,77 +447,85 @@ impl FormattingOptions {
/// decimal point should be printed. /// decimal point should be printed.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub fn precision(&mut self, precision: Option<u16>) -> &mut Self { pub fn precision(&mut self, precision: Option<u16>) -> &mut Self {
if let Some(precision) = precision {
self.flags |= flags::PRECISION_FLAG;
self.precision = precision; self.precision = precision;
} else {
self.flags &= !flags::PRECISION_FLAG;
self.precision = 0;
}
self self
} }
/// Specifies whether the [`Debug`] trait should use lower-/upper-case /// Specifies whether the [`Debug`] trait should use lower-/upper-case
/// hexadecimal or normal integers /// hexadecimal or normal integers
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self { pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self {
self.flags = self.flags let debug_as_hex = match debug_as_hex {
& !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); None => 0,
match debug_as_hex { Some(DebugAsHex::Lower) => flags::DEBUG_LOWER_HEX_FLAG,
None => {} Some(DebugAsHex::Upper) => flags::DEBUG_UPPER_HEX_FLAG,
Some(DebugAsHex::Upper) => self.flags |= 1 << rt::Flag::DebugUpperHex as u32, };
Some(DebugAsHex::Lower) => self.flags |= 1 << rt::Flag::DebugLowerHex as u32, self.flags = self.flags & !(flags::DEBUG_LOWER_HEX_FLAG | flags::DEBUG_UPPER_HEX_FLAG)
} | debug_as_hex;
self self
} }
/// Returns the current sign (the `+` or the `-` flag). /// Returns the current sign (the `+` or the `-` flag).
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn get_sign(&self) -> Option<Sign> { pub const fn get_sign(&self) -> Option<Sign> {
const SIGN_PLUS_BITFIELD: u32 = 1 << rt::Flag::SignPlus as u32; if self.flags & flags::SIGN_PLUS_FLAG != 0 {
const SIGN_MINUS_BITFIELD: u32 = 1 << rt::Flag::SignMinus as u32; Some(Sign::Plus)
match self.flags & ((1 << rt::Flag::SignPlus as u32) | (1 << rt::Flag::SignMinus as u32)) { } else if self.flags & flags::SIGN_MINUS_FLAG != 0 {
SIGN_PLUS_BITFIELD => Some(Sign::Plus), Some(Sign::Minus)
SIGN_MINUS_BITFIELD => Some(Sign::Minus), } else {
0 => None, None
_ => panic!("Invalid sign bits set in flags"),
} }
} }
/// Returns the current `0` flag. /// Returns the current `0` flag.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn get_sign_aware_zero_pad(&self) -> bool { 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. /// Returns the current `#` flag.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn get_alternate(&self) -> bool { 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. /// Returns the current fill character.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn get_fill(&self) -> char { 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. /// Returns the current alignment.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn get_align(&self) -> Option<Alignment> { pub const fn get_align(&self) -> Option<Alignment> {
self.align match self.flags & flags::ALIGN_BITS {
flags::ALIGN_LEFT => Some(Alignment::Left),
flags::ALIGN_RIGHT => Some(Alignment::Right),
flags::ALIGN_CENTER => Some(Alignment::Center),
_ => None,
}
} }
/// Returns the current width. /// Returns the current width.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn get_width(&self) -> Option<u16> { pub const fn get_width(&self) -> Option<u16> {
self.width if self.flags & flags::WIDTH_FLAG != 0 { Some(self.width) } else { None }
} }
/// Returns the current precision. /// Returns the current precision.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn get_precision(&self) -> Option<u16> { pub const fn get_precision(&self) -> Option<u16> {
self.precision if self.flags & flags::PRECISION_FLAG != 0 { Some(self.precision) } else { None }
} }
/// Returns the current precision. /// Returns the current precision.
#[unstable(feature = "formatting_options", issue = "118117")] #[unstable(feature = "formatting_options", issue = "118117")]
pub const fn get_debug_as_hex(&self) -> Option<DebugAsHex> { pub const fn get_debug_as_hex(&self) -> Option<DebugAsHex> {
const DEBUG_UPPER_BITFIELD: u32 = 1 << rt::Flag::DebugUpperHex as u32; if self.flags & flags::DEBUG_LOWER_HEX_FLAG != 0 {
const DEBUG_LOWER_BITFIELD: u32 = 1 << rt::Flag::DebugLowerHex as u32; Some(DebugAsHex::Lower)
match self.flags } else if self.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 {
& ((1 << rt::Flag::DebugUpperHex as u32) | (1 << rt::Flag::DebugLowerHex as u32)) Some(DebugAsHex::Upper)
{ } else {
DEBUG_UPPER_BITFIELD => Some(DebugAsHex::Upper), None
DEBUG_LOWER_BITFIELD => Some(DebugAsHex::Lower),
0 => None,
_ => panic!("Invalid hex debug bits set in flags"),
} }
} }
@ -485,27 +536,6 @@ impl FormattingOptions {
pub 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 } 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")] #[unstable(feature = "formatting_options", issue = "118117")]
@ -1479,15 +1509,25 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
} }
unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result {
fmt.options.fill = arg.fill; let (width, precision) =
fmt.options.align = arg.align.into();
fmt.options.flags = arg.flags;
// SAFETY: arg and args come from the same Arguments, // SAFETY: arg and args come from the same Arguments,
// which guarantees the indexes are always within bounds. // which guarantees the indexes are always within bounds.
unsafe { unsafe { (getcount(args, &arg.width), getcount(args, &arg.precision)) };
fmt.options.width = getcount(args, &arg.width);
fmt.options.precision = getcount(args, &arg.precision); #[cfg(bootstrap)]
} let options =
*FormattingOptions { flags: flags::ALWAYS_SET | arg.flags << 21, width: 0, precision: 0 }
.align(match arg.align {
rt::Alignment::Left => Some(Alignment::Left),
rt::Alignment::Right => Some(Alignment::Right),
rt::Alignment::Center => Some(Alignment::Center),
rt::Alignment::Unknown => None,
})
.fill(arg.fill)
.width(width)
.precision(precision);
#[cfg(not(bootstrap))]
let options = FormattingOptions { flags: arg.flags, width, precision };
// Extract the correct argument // Extract the correct argument
debug_assert!(arg.position < args.len()); debug_assert!(arg.position < args.len());
@ -1495,17 +1535,18 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume
// which guarantees its index is always within bounds. // which guarantees its index is always within bounds.
let value = unsafe { args.get_unchecked(arg.position) }; let value = unsafe { args.get_unchecked(arg.position) };
// Set all the formatting options.
fmt.options = options;
// Then actually do some printing // Then actually do some printing
// SAFETY: this is a placeholder argument. // SAFETY: this is a placeholder argument.
unsafe { value.fmt(fmt) } unsafe { value.fmt(fmt) }
} }
#[cfg(bootstrap)]
unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<u16> { unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<u16> {
match *cnt { match *cnt {
#[cfg(bootstrap)]
rt::Count::Is(n) => Some(n as u16), rt::Count::Is(n) => Some(n as u16),
#[cfg(not(bootstrap))]
rt::Count::Is(n) => Some(n),
rt::Count::Implied => None, rt::Count::Implied => None,
rt::Count::Param(i) => { rt::Count::Param(i) => {
debug_assert!(i < args.len()); debug_assert!(i < args.len());
@ -1516,6 +1557,20 @@ unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<u16> {
} }
} }
#[cfg(not(bootstrap))]
unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> u16 {
match *cnt {
rt::Count::Is(n) => n,
rt::Count::Implied => 0,
rt::Count::Param(i) => {
debug_assert!(i < args.len());
// SAFETY: cnt and args come from the same Arguments,
// which guarantees this index is always within bounds.
unsafe { args.get_unchecked(i).as_u16().unwrap_unchecked() }
}
}
}
/// Padding after the end of something. Returned by `Formatter::padding`. /// Padding after the end of something. Returned by `Formatter::padding`.
#[must_use = "don't forget to write the post padding"] #[must_use = "don't forget to write the post padding"]
pub(crate) struct PostPadding { pub(crate) struct PostPadding {
@ -1629,42 +1684,30 @@ impl<'a> Formatter<'a> {
} }
// The `width` field is more of a `min-width` parameter at this point. // The `width` field is more of a `min-width` parameter at this point.
match self.options.width { let min = self.options.width;
// If there's no minimum length requirements then we can just if width >= usize::from(min) {
// write the bytes. // We're over the minimum width, so then we can just write the bytes.
None => {
write_prefix(self, sign, prefix)?; write_prefix(self, sign, prefix)?;
self.buf.write_str(buf) self.buf.write_str(buf)
} } else if self.sign_aware_zero_pad() {
// 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)
}
// The sign and prefix goes before the padding if the fill character // The sign and prefix goes before the padding if the fill character
// is zero // is zero
Some(min) if self.sign_aware_zero_pad() => { let old_options = self.options;
let old_fill = crate::mem::replace(&mut self.options.fill, '0'); self.options.fill('0').align(Some(Alignment::Right));
let old_align =
crate::mem::replace(&mut self.options.align, Some(Alignment::Right));
write_prefix(self, sign, prefix)?; write_prefix(self, sign, prefix)?;
let post_padding = self.padding(min - width as u16, Alignment::Right)?; let post_padding = self.padding(min - width as u16, Alignment::Right)?;
self.buf.write_str(buf)?; self.buf.write_str(buf)?;
post_padding.write(self)?; post_padding.write(self)?;
self.options.fill = old_fill; self.options = old_options;
self.options.align = old_align;
Ok(()) Ok(())
} } else {
// Otherwise, the sign and prefix goes after the padding // Otherwise, the sign and prefix goes after the padding
Some(min) => {
let post_padding = self.padding(min - width as u16, Alignment::Right)?; let post_padding = self.padding(min - width as u16, Alignment::Right)?;
write_prefix(self, sign, prefix)?; write_prefix(self, sign, prefix)?;
self.buf.write_str(buf)?; self.buf.write_str(buf)?;
post_padding.write(self) post_padding.write(self)
} }
} }
}
/// Takes a string slice and emits it to the internal buffer after applying /// Takes a string slice and emits it to the internal buffer after applying
/// the relevant formatting flags specified. /// the relevant formatting flags specified.
@ -1698,13 +1741,13 @@ impl<'a> Formatter<'a> {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn pad(&mut self, s: &str) -> Result { pub fn pad(&mut self, s: &str) -> Result {
// Make sure there's a fast path up front. // 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); return self.buf.write_str(s);
} }
// The `precision` field can be interpreted as a maximum width for the // The `precision` field can be interpreted as a maximum width for the
// string being formatted. // string being formatted.
let (s, char_count) = if let Some(max_char_count) = self.options.precision { let (s, char_count) = if let Some(max_char_count) = self.options.get_precision() {
let mut iter = s.char_indices(); let mut iter = s.char_indices();
let remaining = match iter.advance_by(usize::from(max_char_count)) { let remaining = match iter.advance_by(usize::from(max_char_count)) {
Ok(()) => 0, Ok(()) => 0,
@ -1720,12 +1763,11 @@ impl<'a> Formatter<'a> {
}; };
// The `width` field is more of a minimum width parameter at this point. // The `width` field is more of a minimum width parameter at this point.
if let Some(width) = self.options.width if char_count < usize::from(self.options.width) {
&& char_count < usize::from(width)
{
// If we're under the minimum width, then fill up the minimum width // If we're under the minimum width, then fill up the minimum width
// with the specified string + some alignment. // with the specified string + some alignment.
let post_padding = self.padding(width - char_count as u16, Alignment::Left)?; let post_padding =
self.padding(self.options.width - char_count as u16, Alignment::Left)?;
self.buf.write_str(s)?; self.buf.write_str(s)?;
post_padding.write(self) post_padding.write(self)
} else { } else {
@ -1744,19 +1786,20 @@ impl<'a> Formatter<'a> {
padding: u16, padding: u16,
default: Alignment, default: Alignment,
) -> result::Result<PostPadding, Error> { ) -> result::Result<PostPadding, Error> {
let align = self.align().unwrap_or(default); let align = self.options.get_align().unwrap_or(default);
let fill = self.options.get_fill();
let (pre_pad, post_pad) = match align { let padding_left = match align {
Alignment::Left => (0, padding), Alignment::Left => 0,
Alignment::Right => (padding, 0), Alignment::Right => padding,
Alignment::Center => (padding / 2, (padding + 1) / 2), Alignment::Center => padding / 2,
}; };
for _ in 0..pre_pad { for _ in 0..padding_left {
self.buf.write_char(self.options.fill)?; 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. /// Takes the formatted parts and applies the padding.
@ -1768,12 +1811,16 @@ impl<'a> Formatter<'a> {
/// ///
/// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8.
unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { 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 // for the sign-aware zero padding, we render the sign first and
// behave as if we had no sign from the beginning. // behave as if we had no sign from the beginning.
let mut formatted = formatted.clone(); let mut formatted = formatted.clone();
let old_fill = self.options.fill; let mut width = self.options.width;
let old_align = self.options.align; let old_options = self.options;
if self.sign_aware_zero_pad() { if self.sign_aware_zero_pad() {
// a sign always goes first // a sign always goes first
let sign = formatted.sign; let sign = formatted.sign;
@ -1782,8 +1829,7 @@ impl<'a> Formatter<'a> {
// remove the sign from the formatted parts // remove the sign from the formatted parts
formatted.sign = ""; formatted.sign = "";
width = width.saturating_sub(sign.len() as u16); width = width.saturating_sub(sign.len() as u16);
self.options.fill = '0'; self.options.fill('0').align(Some(Alignment::Right));
self.options.align = Some(Alignment::Right);
} }
// remaining parts go through the ordinary padding process. // remaining parts go through the ordinary padding process.
@ -1800,13 +1846,8 @@ impl<'a> Formatter<'a> {
} }
post_padding.write(self) post_padding.write(self)
}; };
self.options.fill = old_fill; self.options = old_options;
self.options.align = old_align;
ret ret
} else {
// this is the common case and we take a shortcut
// SAFETY: Per the precondition.
unsafe { self.write_formatted_parts(formatted) }
} }
} }
@ -1927,7 +1968,9 @@ impl<'a> Formatter<'a> {
or `sign_aware_zero_pad` methods instead" or `sign_aware_zero_pad` methods instead"
)] )]
pub fn flags(&self) -> u32 { 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. /// Returns the character used as 'fill' whenever there is alignment.
@ -1960,7 +2003,7 @@ impl<'a> Formatter<'a> {
#[must_use] #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")] #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn fill(&self) -> char { pub fn fill(&self) -> char {
self.options.fill self.options.get_fill()
} }
/// Returns a flag indicating what form of alignment was requested. /// Returns a flag indicating what form of alignment was requested.
@ -1995,7 +2038,7 @@ impl<'a> Formatter<'a> {
#[must_use] #[must_use]
#[stable(feature = "fmt_flags_align", since = "1.28.0")] #[stable(feature = "fmt_flags_align", since = "1.28.0")]
pub fn align(&self) -> Option<Alignment> { pub fn align(&self) -> Option<Alignment> {
self.options.align self.options.get_align()
} }
/// Returns the optionally specified integer width that the output should be. /// Returns the optionally specified integer width that the output should be.
@ -2025,7 +2068,11 @@ impl<'a> Formatter<'a> {
#[must_use] #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")] #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn width(&self) -> Option<usize> { pub fn width(&self) -> Option<usize> {
self.options.width.map(|x| x as usize) if self.options.flags & flags::WIDTH_FLAG == 0 {
None
} else {
Some(self.options.width as usize)
}
} }
/// Returns the optionally specified precision for numeric types. /// Returns the optionally specified precision for numeric types.
@ -2056,7 +2103,11 @@ impl<'a> Formatter<'a> {
#[must_use] #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")] #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn precision(&self) -> Option<usize> { pub fn precision(&self) -> Option<usize> {
self.options.precision.map(|x| x as usize) if self.options.flags & flags::PRECISION_FLAG == 0 {
None
} else {
Some(self.options.precision as usize)
}
} }
/// Determines if the `+` flag was specified. /// Determines if the `+` flag was specified.
@ -2088,7 +2139,7 @@ impl<'a> Formatter<'a> {
#[must_use] #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")] #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_plus(&self) -> bool { 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. /// Determines if the `-` flag was specified.
@ -2117,7 +2168,7 @@ impl<'a> Formatter<'a> {
#[must_use] #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")] #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_minus(&self) -> bool { 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. /// Determines if the `#` flag was specified.
@ -2145,7 +2196,7 @@ impl<'a> Formatter<'a> {
#[must_use] #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")] #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn alternate(&self) -> bool { 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. /// Determines if the `0` flag was specified.
@ -2171,17 +2222,16 @@ impl<'a> Formatter<'a> {
#[must_use] #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")] #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_aware_zero_pad(&self) -> bool { 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. // FIXME: Decide what public API we want for these two flags.
// https://github.com/rust-lang/rust/issues/48584 // https://github.com/rust-lang/rust/issues/48584
fn debug_lower_hex(&self) -> bool { 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 { 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 /// Creates a [`DebugStruct`] builder designed to assist with creation of
@ -2761,7 +2811,7 @@ impl Debug for char {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl Display for char { impl Display for char {
fn fmt(&self, f: &mut Formatter<'_>) -> Result { 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) f.write_char(*self)
} else { } else {
f.pad(self.encode_utf8(&mut [0; MAX_LEN_UTF8])) f.pad(self.encode_utf8(&mut [0; MAX_LEN_UTF8]))
@ -2792,26 +2842,24 @@ impl<T: ?Sized> Pointer for *const T {
/// ///
/// [problematic]: https://github.com/rust-lang/rust/issues/95489 /// [problematic]: https://github.com/rust-lang/rust/issues/95489
pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result { pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result {
let old_width = f.options.width; let old_options = f.options;
let old_flags = f.options.flags;
// The alternate flag is already treated by LowerHex as being special- // 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 // 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 // or not to zero extend, and then unconditionally set it to get the
// prefix. // prefix.
if f.alternate() { if f.options.get_alternate() {
f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); f.options.sign_aware_zero_pad(true);
if f.options.width.is_none() { if f.options.get_width().is_none() {
f.options.width = Some((usize::BITS / 4) as u16 + 2); 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); let ret = LowerHex::fmt(&ptr_addr, f);
f.options.width = old_width; f.options = old_options;
f.options.flags = old_flags;
ret ret
} }

View file

@ -11,7 +11,9 @@ use crate::ptr::NonNull;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Placeholder { pub struct Placeholder {
pub position: usize, pub position: usize,
#[cfg(bootstrap)]
pub fill: char, pub fill: char,
#[cfg(bootstrap)]
pub align: Alignment, pub align: Alignment,
pub flags: u32, pub flags: u32,
pub precision: Count, pub precision: Count,
@ -19,6 +21,7 @@ pub struct Placeholder {
} }
impl Placeholder { impl Placeholder {
#[cfg(bootstrap)]
#[inline] #[inline]
pub const fn new( pub const fn new(
position: usize, position: usize,
@ -30,8 +33,15 @@ impl Placeholder {
) -> Self { ) -> Self {
Self { position, fill, align, flags, precision, width } 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"] #[lang = "format_alignment"]
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
pub enum Alignment { pub enum Alignment {
@ -58,17 +68,6 @@ pub enum Count {
Implied, 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)] #[derive(Copy, Clone)]
enum ArgumentType<'a> { enum ArgumentType<'a> {
Placeholder { Placeholder {

View file

@ -81,6 +81,7 @@ fn formatting_options_ctor() {
} }
#[test] #[test]
#[allow(deprecated)]
fn formatting_options_flags() { fn formatting_options_flags() {
use core::fmt::*; use core::fmt::*;
for sign in [None, Some(Sign::Plus), Some(Sign::Minus)] { for sign in [None, Some(Sign::Plus), Some(Sign::Minus)] {
@ -98,6 +99,25 @@ fn formatting_options_flags() {
assert_eq!(formatting_options.get_alternate(), alternate); 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_sign_aware_zero_pad(), sign_aware_zero_pad);
assert_eq!(formatting_options.get_debug_as_hex(), debug_as_hex); assert_eq!(formatting_options.get_debug_as_hex(), debug_as_hex);
let mut output = String::new();
let fmt = Formatter::new(&mut output, formatting_options);
assert_eq!(fmt.options(), formatting_options);
assert_eq!(fmt.sign_minus(), sign == Some(Sign::Minus));
assert_eq!(fmt.sign_plus(), sign == Some(Sign::Plus));
assert_eq!(fmt.alternate(), alternate);
assert_eq!(fmt.sign_aware_zero_pad(), sign_aware_zero_pad);
// The flags method is deprecated.
// This checks compatibility with older versions of Rust.
assert_eq!(fmt.flags() & 1 != 0, sign == Some(Sign::Plus));
assert_eq!(fmt.flags() & 2 != 0, sign == Some(Sign::Minus));
assert_eq!(fmt.flags() & 4 != 0, alternate);
assert_eq!(fmt.flags() & 8 != 0, sign_aware_zero_pad);
assert_eq!(fmt.flags() & 16 != 0, debug_as_hex == Some(DebugAsHex::Lower));
assert_eq!(fmt.flags() & 32 != 0, debug_as_hex == Some(DebugAsHex::Upper));
assert_eq!(fmt.flags() & 0xFFFF_FFC0, 0);
} }
} }
} }

View file

@ -29,16 +29,10 @@
debug precision => _8; debug precision => _8;
let _8: usize; let _8: usize;
scope 5 (inlined Formatter::<'_>::precision) { scope 5 (inlined Formatter::<'_>::precision) {
let mut _22: std::option::Option<u16>; let mut _22: u32;
scope 6 (inlined Option::<u16>::map::<usize, {closure@Formatter<'_>::precision::{closure#0}}>) { let mut _23: u32;
let mut _23: isize; let mut _24: usize;
let _24: u16; let mut _25: u16;
let mut _25: usize;
scope 7 {
scope 8 (inlined Formatter::<'_>::precision::{closure#0}) {
}
}
}
} }
} }
} }
@ -53,7 +47,7 @@
StorageLive(_20); StorageLive(_20);
StorageLive(_21); StorageLive(_21);
_21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); _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); StorageDead(_21);
_4 = Ne(move _20, const 0_u32); _4 = Ne(move _20, const 0_u32);
StorageDead(_20); StorageDead(_20);
@ -75,12 +69,12 @@
bb3: { bb3: {
StorageLive(_6); StorageLive(_6);
StorageLive(_24);
StorageLive(_22); StorageLive(_22);
_22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option<u16>);
StorageLive(_23); StorageLive(_23);
_23 = discriminant(_22); _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG);
StorageDead(_23);
switchInt(move _22) -> [0: bb10, otherwise: bb11];
} }
bb4: { bb4: {
@ -148,30 +142,31 @@
} }
bb9: { bb9: {
StorageDead(_23);
StorageDead(_22);
StorageDead(_24);
_7 = discriminant(_6); _7 = discriminant(_6);
switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12];
} }
bb10: { bb10: {
unreachable; StorageDead(_22);
}
bb11: {
_6 = const Option::<usize>::None; _6 = const Option::<usize>::None;
goto -> bb9; goto -> bb9;
} }
bb12: { bb11: {
_24 = move ((_22 as Some).0: u16); StorageDead(_22);
StorageLive(_24);
StorageLive(_25); StorageLive(_25);
_25 = copy _24 as usize (IntToInt); _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16);
_6 = Option::<usize>::Some(move _25); _24 = move _25 as usize (IntToInt);
StorageDead(_25); StorageDead(_25);
_6 = Option::<usize>::Some(move _24);
StorageDead(_24);
goto -> bb9; goto -> bb9;
} }
bb12: {
unreachable;
}
} }
ALLOC0 (size: 8, align: 4) { ALLOC0 (size: 8, align: 4) {

View file

@ -29,16 +29,10 @@
debug precision => _8; debug precision => _8;
let _8: usize; let _8: usize;
scope 5 (inlined Formatter::<'_>::precision) { scope 5 (inlined Formatter::<'_>::precision) {
let mut _22: std::option::Option<u16>; let mut _22: u32;
scope 6 (inlined Option::<u16>::map::<usize, {closure@Formatter<'_>::precision::{closure#0}}>) { let mut _23: u32;
let mut _23: isize; let mut _24: usize;
let _24: u16; let mut _25: u16;
let mut _25: usize;
scope 7 {
scope 8 (inlined Formatter::<'_>::precision::{closure#0}) {
}
}
}
} }
} }
} }
@ -53,7 +47,7 @@
StorageLive(_20); StorageLive(_20);
StorageLive(_21); StorageLive(_21);
_21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); _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); StorageDead(_21);
_4 = Ne(move _20, const 0_u32); _4 = Ne(move _20, const 0_u32);
StorageDead(_20); StorageDead(_20);
@ -75,12 +69,12 @@
bb3: { bb3: {
StorageLive(_6); StorageLive(_6);
StorageLive(_24);
StorageLive(_22); StorageLive(_22);
_22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option<u16>);
StorageLive(_23); StorageLive(_23);
_23 = discriminant(_22); _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG);
StorageDead(_23);
switchInt(move _22) -> [0: bb10, otherwise: bb11];
} }
bb4: { bb4: {
@ -148,30 +142,31 @@
} }
bb9: { bb9: {
StorageDead(_23);
StorageDead(_22);
StorageDead(_24);
_7 = discriminant(_6); _7 = discriminant(_6);
switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12];
} }
bb10: { bb10: {
unreachable; StorageDead(_22);
}
bb11: {
_6 = const Option::<usize>::None; _6 = const Option::<usize>::None;
goto -> bb9; goto -> bb9;
} }
bb12: { bb11: {
_24 = move ((_22 as Some).0: u16); StorageDead(_22);
StorageLive(_24);
StorageLive(_25); StorageLive(_25);
_25 = copy _24 as usize (IntToInt); _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16);
_6 = Option::<usize>::Some(move _25); _24 = move _25 as usize (IntToInt);
StorageDead(_25); StorageDead(_25);
_6 = Option::<usize>::Some(move _24);
StorageDead(_24);
goto -> bb9; goto -> bb9;
} }
bb12: {
unreachable;
}
} }
ALLOC0 (size: 8, align: 4) { ALLOC0 (size: 8, align: 4) {

View file

@ -29,16 +29,10 @@
debug precision => _8; debug precision => _8;
let _8: usize; let _8: usize;
scope 5 (inlined Formatter::<'_>::precision) { scope 5 (inlined Formatter::<'_>::precision) {
let mut _22: std::option::Option<u16>; let mut _22: u32;
scope 6 (inlined Option::<u16>::map::<usize, {closure@Formatter<'_>::precision::{closure#0}}>) { let mut _23: u32;
let mut _23: isize; let mut _24: usize;
let _24: u16; let mut _25: u16;
let mut _25: usize;
scope 7 {
scope 8 (inlined Formatter::<'_>::precision::{closure#0}) {
}
}
}
} }
} }
} }
@ -53,7 +47,7 @@
StorageLive(_20); StorageLive(_20);
StorageLive(_21); StorageLive(_21);
_21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); _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); StorageDead(_21);
_4 = Ne(move _20, const 0_u32); _4 = Ne(move _20, const 0_u32);
StorageDead(_20); StorageDead(_20);
@ -75,12 +69,12 @@
bb3: { bb3: {
StorageLive(_6); StorageLive(_6);
StorageLive(_24);
StorageLive(_22); StorageLive(_22);
_22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option<u16>);
StorageLive(_23); StorageLive(_23);
_23 = discriminant(_22); _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG);
StorageDead(_23);
switchInt(move _22) -> [0: bb10, otherwise: bb11];
} }
bb4: { bb4: {
@ -148,30 +142,31 @@
} }
bb9: { bb9: {
StorageDead(_23);
StorageDead(_22);
StorageDead(_24);
_7 = discriminant(_6); _7 = discriminant(_6);
switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12];
} }
bb10: { bb10: {
unreachable; StorageDead(_22);
}
bb11: {
_6 = const Option::<usize>::None; _6 = const Option::<usize>::None;
goto -> bb9; goto -> bb9;
} }
bb12: { bb11: {
_24 = move ((_22 as Some).0: u16); StorageDead(_22);
StorageLive(_24);
StorageLive(_25); StorageLive(_25);
_25 = copy _24 as usize (IntToInt); _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16);
_6 = Option::<usize>::Some(move _25); _24 = move _25 as usize (IntToInt);
StorageDead(_25); StorageDead(_25);
_6 = Option::<usize>::Some(move _24);
StorageDead(_24);
goto -> bb9; goto -> bb9;
} }
bb12: {
unreachable;
}
} }
ALLOC0 (size: 16, align: 8) { ALLOC0 (size: 16, align: 8) {

View file

@ -29,16 +29,10 @@
debug precision => _8; debug precision => _8;
let _8: usize; let _8: usize;
scope 5 (inlined Formatter::<'_>::precision) { scope 5 (inlined Formatter::<'_>::precision) {
let mut _22: std::option::Option<u16>; let mut _22: u32;
scope 6 (inlined Option::<u16>::map::<usize, {closure@Formatter<'_>::precision::{closure#0}}>) { let mut _23: u32;
let mut _23: isize; let mut _24: usize;
let _24: u16; let mut _25: u16;
let mut _25: usize;
scope 7 {
scope 8 (inlined Formatter::<'_>::precision::{closure#0}) {
}
}
}
} }
} }
} }
@ -53,7 +47,7 @@
StorageLive(_20); StorageLive(_20);
StorageLive(_21); StorageLive(_21);
_21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); _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); StorageDead(_21);
_4 = Ne(move _20, const 0_u32); _4 = Ne(move _20, const 0_u32);
StorageDead(_20); StorageDead(_20);
@ -75,12 +69,12 @@
bb3: { bb3: {
StorageLive(_6); StorageLive(_6);
StorageLive(_24);
StorageLive(_22); StorageLive(_22);
_22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option<u16>);
StorageLive(_23); StorageLive(_23);
_23 = discriminant(_22); _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG);
StorageDead(_23);
switchInt(move _22) -> [0: bb10, otherwise: bb11];
} }
bb4: { bb4: {
@ -148,30 +142,31 @@
} }
bb9: { bb9: {
StorageDead(_23);
StorageDead(_22);
StorageDead(_24);
_7 = discriminant(_6); _7 = discriminant(_6);
switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb12];
} }
bb10: { bb10: {
unreachable; StorageDead(_22);
}
bb11: {
_6 = const Option::<usize>::None; _6 = const Option::<usize>::None;
goto -> bb9; goto -> bb9;
} }
bb12: { bb11: {
_24 = move ((_22 as Some).0: u16); StorageDead(_22);
StorageLive(_24);
StorageLive(_25); StorageLive(_25);
_25 = copy _24 as usize (IntToInt); _25 = copy (((*_1).0: std::fmt::FormattingOptions).2: u16);
_6 = Option::<usize>::Some(move _25); _24 = move _25 as usize (IntToInt);
StorageDead(_25); StorageDead(_25);
_6 = Option::<usize>::Some(move _24);
StorageDead(_24);
goto -> bb9; goto -> bb9;
} }
bb12: {
unreachable;
}
} }
ALLOC0 (size: 16, align: 8) { ALLOC0 (size: 16, align: 8) {