From 6e912a98ccab2f0c930df7afd78f32f8f97c232a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 12 Feb 2025 16:59:13 +0100 Subject: [PATCH 01/17] Use u16 for fmt width and precision. --- compiler/rustc_ast/src/format.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 11 +++++ compiler/rustc_ast_lowering/src/format.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 18 ++++---- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/fmt/float.rs | 12 +++--- library/core/src/fmt/mod.rs | 49 ++++++++++++---------- library/core/src/fmt/rt.rs | 13 ++++-- library/core/src/time.rs | 3 +- library/coretests/tests/num/flt2dec/mod.rs | 2 +- 10 files changed, 68 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index b93846c1fe6f3..b611ddea1d9f1 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -266,7 +266,7 @@ pub enum FormatAlignment { #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` - Literal(usize), + Literal(u16), /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. Argument(FormatArgPosition), } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index af53c7ec21572..757e1dbd54b1a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2151,6 +2151,17 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(sp, hir::ExprKind::Lit(lit)) } + pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> { + let lit = self.arena.alloc(hir::Lit { + span: sp, + node: ast::LitKind::Int( + u128::from(value).into(), + ast::LitIntType::Unsigned(ast::UintTy::U16), + ), + }); + 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)) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 07b94dbc2aebd..faa47274f96ce 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -292,7 +292,7 @@ fn make_count<'hir>( hir::LangItem::FormatCount, sym::Is, )); - let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]); + let value = ctx.arena.alloc_from_iter([ctx.expr_u16(sp, *n)]); ctx.expr_call_mut(sp, count_is, value) } Some(FormatCount::Argument(arg)) => { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 3b985621b5772..e05cc6d29d84f 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -190,7 +190,7 @@ pub enum DebugHex { #[derive(Copy, Clone, Debug, PartialEq)] pub enum Count<'a> { /// The count is specified explicitly. - CountIs(usize), + CountIs(u16), /// The count is specified by the argument with the given name. CountIsName(&'a str, InnerSpan), /// The count is specified by the argument at the given index. @@ -565,7 +565,7 @@ impl<'a> Parser<'a> { /// consuming a macro argument, `None` if it's the case. fn position(&mut self) -> Option> { if let Some(i) = self.integer() { - Some(ArgumentIs(i)) + Some(ArgumentIs(i.into())) } else { match self.cur.peek() { Some(&(lo, c)) if rustc_lexer::is_id_start(c) => { @@ -771,7 +771,7 @@ impl<'a> Parser<'a> { /// width. fn count(&mut self, start: usize) -> Count<'a> { if let Some(i) = self.integer() { - if self.consume('$') { CountIsParam(i) } else { CountIs(i) } + if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) } } else { let tmp = self.cur.clone(); let word = self.word(); @@ -822,15 +822,15 @@ impl<'a> Parser<'a> { word } - fn integer(&mut self) -> Option { - let mut cur: usize = 0; + fn integer(&mut self) -> Option { + let mut cur: u16 = 0; let mut found = false; let mut overflow = false; let start = self.current_pos(); while let Some(&(_, c)) = self.cur.peek() { if let Some(i) = c.to_digit(10) { let (tmp, mul_overflow) = cur.overflowing_mul(10); - let (tmp, add_overflow) = tmp.overflowing_add(i as usize); + let (tmp, add_overflow) = tmp.overflowing_add(i as u16); if mul_overflow || add_overflow { overflow = true; } @@ -847,11 +847,11 @@ impl<'a> Parser<'a> { let overflowed_int = &self.input[start..end]; self.err( format!( - "integer `{}` does not fit into the type `usize` whose range is `0..={}`", + "integer `{}` does not fit into the type `u16` whose range is `0..={}`", overflowed_int, - usize::MAX + u16::MAX ), - "integer out of range for `usize`", + "integer out of range for `u16`", self.span(start, end), ); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d4d435d9b7467..bce4e242e08aa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1012,6 +1012,7 @@ symbols! { from_residual, from_size_align_unchecked, from_str_method, + from_u16, from_usize, from_yeet, fs_create_dir, diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 3f10158193d76..4a43c12be9aaa 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -29,7 +29,7 @@ fn float_to_decimal_common_exact( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, ) -> Result where T: flt2dec::DecodableFloat, @@ -40,7 +40,7 @@ where flt2dec::strategy::grisu::format_exact, *num, sign, - precision, + precision.into(), &mut buf, &mut parts, ); @@ -55,7 +55,7 @@ fn float_to_decimal_common_shortest( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, ) -> Result where T: flt2dec::DecodableFloat, @@ -68,7 +68,7 @@ where flt2dec::strategy::grisu::format_shortest, *num, sign, - precision, + precision.into(), &mut buf, &mut parts, ); @@ -101,7 +101,7 @@ fn float_to_exponential_common_exact( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, upper: bool, ) -> Result where @@ -113,7 +113,7 @@ where flt2dec::strategy::grisu::format_exact, *num, sign, - precision, + precision.into(), upper, &mut buf, &mut parts, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 764e7fff33ec7..b8eb77c52c558 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -294,8 +294,8 @@ pub struct FormattingOptions { flags: u32, fill: char, align: Option, - width: Option, - precision: Option, + width: Option, + precision: Option, } impl FormattingOptions { @@ -389,7 +389,7 @@ impl FormattingOptions { /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn width(&mut self, width: Option) -> &mut Self { + pub fn width(&mut self, width: Option) -> &mut Self { self.width = width; self } @@ -403,7 +403,7 @@ impl FormattingOptions { /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn precision(&mut self, precision: Option) -> &mut Self { + pub fn precision(&mut self, precision: Option) -> &mut Self { self.precision = precision; self } @@ -455,12 +455,12 @@ impl FormattingOptions { } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn get_width(&self) -> Option { + pub const fn get_width(&self) -> Option { self.width } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn get_precision(&self) -> Option { + pub const fn get_precision(&self) -> Option { self.precision } /// Returns the current precision. @@ -1499,15 +1499,18 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume unsafe { value.fmt(fmt) } } -unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { +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()); // SAFETY: cnt and args come from the same Arguments, // which guarantees this index is always within bounds. - unsafe { args.get_unchecked(i).as_usize() } + unsafe { args.get_unchecked(i).as_u16() } } } } @@ -1516,11 +1519,11 @@ unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option #[must_use = "don't forget to write the post padding"] pub(crate) struct PostPadding { fill: char, - padding: usize, + padding: u16, } impl PostPadding { - fn new(fill: char, padding: usize) -> PostPadding { + fn new(fill: char, padding: u16) -> PostPadding { PostPadding { fill, padding } } @@ -1634,7 +1637,7 @@ impl<'a> Formatter<'a> { } // Check if we're over the minimum width, if so then we can also // just write the bytes. - Some(min) if width >= min => { + Some(min) if width >= usize::from(min) => { write_prefix(self, sign, prefix)?; self.buf.write_str(buf) } @@ -1645,7 +1648,7 @@ impl<'a> Formatter<'a> { 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, Alignment::Right)?; + 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; @@ -1654,7 +1657,7 @@ impl<'a> Formatter<'a> { } // Otherwise, the sign and prefix goes after the padding Some(min) => { - let post_padding = self.padding(min - width, Alignment::Right)?; + 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) @@ -1703,7 +1706,7 @@ impl<'a> Formatter<'a> { // 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. - if let Some((i, _)) = s.char_indices().nth(max) { + if let Some((i, _)) = s.char_indices().nth(usize::from(max)) { // LLVM here can't prove that `..i` won't panic `&s[..i]`, but // we know that it can't panic. Use `get` + `unwrap_or` to avoid // `unsafe` and otherwise don't emit any panic-related code @@ -1724,14 +1727,14 @@ impl<'a> Formatter<'a> { 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 >= width { + 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, align)?; + let post_padding = self.padding(width - chars_count as u16, align)?; self.buf.write_str(s)?; post_padding.write(self) } @@ -1745,7 +1748,7 @@ impl<'a> Formatter<'a> { /// thing that is being padded. pub(crate) fn padding( &mut self, - padding: usize, + padding: u16, default: Alignment, ) -> result::Result { let align = self.align().unwrap_or(default); @@ -1785,19 +1788,19 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; - width = width.saturating_sub(sign.len()); + width = width.saturating_sub(sign.len() as u16); self.options.fill = '0'; self.options.align = Some(Alignment::Right); } // remaining parts go through the ordinary padding process. let len = formatted.len(); - let ret = if width <= len { + let ret = if usize::from(width) <= len { // no padding // SAFETY: Per the precondition. unsafe { self.write_formatted_parts(&formatted) } } else { - let post_padding = self.padding(width - len, Alignment::Right)?; + let post_padding = self.padding(width - len as u16, Alignment::Right)?; // SAFETY: Per the precondition. unsafe { self.write_formatted_parts(&formatted)?; @@ -2029,7 +2032,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.options.width + self.options.width.map(|x| x as usize) } /// Returns the optionally specified precision for numeric types. @@ -2060,7 +2063,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.options.precision + self.options.precision.map(|x| x as usize) } /// Determines if the `+` flag was specified. @@ -2800,7 +2803,7 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); if f.options.width.is_none() { - f.options.width = Some((usize::BITS / 4) as usize + 2); + f.options.width = Some((usize::BITS / 4) as u16 + 2); } } f.options.flags |= 1 << (rt::Flag::Alternate as u32); diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 85d089a079082..cb908adc1cbaf 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -47,7 +47,11 @@ pub enum Alignment { #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value + #[cfg(bootstrap)] Is(usize), + /// Specified with a literal number, stores the value + #[cfg(not(bootstrap))] + Is(u16), /// Specified using `$` and `*` syntaxes, stores the index into `args` Param(usize), /// Not specified @@ -74,7 +78,7 @@ enum ArgumentType<'a> { formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result, _lifetime: PhantomData<&'a ()>, }, - Count(usize), + Count(u16), } /// This struct represents a generic "argument" which is taken by format_args!(). @@ -151,7 +155,10 @@ impl Argument<'_> { } #[inline] pub const fn from_usize(x: &usize) -> Argument<'_> { - Argument { ty: ArgumentType::Count(*x) } + if *x > u16::MAX as usize { + panic!("Formatting argument out of range"); + }; + Argument { ty: ArgumentType::Count(*x as u16) } } /// Format this placeholder argument. @@ -181,7 +188,7 @@ impl Argument<'_> { } #[inline] - pub(super) const fn as_usize(&self) -> Option { + pub(super) const fn as_u16(&self) -> Option { match self.ty { ArgumentType::Count(count) => Some(count), ArgumentType::Placeholder { .. } => None, diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 22bd46c567eaa..acb4beeab061d 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1375,7 +1375,8 @@ impl fmt::Debug for Duration { } else { // We need to add padding. Use the `Formatter::padding` helper function. let default_align = fmt::Alignment::Left; - let post_padding = f.padding(requested_w - actual_w, default_align)?; + let post_padding = + f.padding((requested_w - actual_w) as u16, default_align)?; emit_without_padding(f)?; post_padding.write(f) } diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs index 6041923117c2a..6e74cc91c5b27 100644 --- a/library/coretests/tests/num/flt2dec/mod.rs +++ b/library/coretests/tests/num/flt2dec/mod.rs @@ -577,7 +577,7 @@ where } // very large output - assert_eq!(to_string(f, 1.1, Minus, 80000), format!("1.1{:0>79999}", "")); + assert_eq!(to_string(f, 1.1, Minus, 50000), format!("1.1{:0>49999}", "")); } pub fn to_shortest_exp_str_test(mut f_: F) From 64ea7d10d36ad3472a9ca16f695df20985be1424 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 12 Feb 2025 17:33:05 +0100 Subject: [PATCH 02/17] Update tests. --- library/coretests/tests/num/flt2dec/mod.rs | 28 +-- ...nential_common.GVN.32bit.panic-abort.diff} | 45 ++++- ...ential_common.GVN.32bit.panic-unwind.diff} | 45 ++++- ...onential_common.GVN.64bit.panic-abort.diff | 180 ++++++++++++++++++ ...nential_common.GVN.64bit.panic-unwind.diff | 180 ++++++++++++++++++ tests/mir-opt/funky_arms.rs | 1 + 6 files changed, 459 insertions(+), 20 deletions(-) rename tests/mir-opt/{funky_arms.float_to_exponential_common.GVN.panic-abort.diff => funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff} (73%) rename tests/mir-opt/{funky_arms.float_to_exponential_common.GVN.panic-unwind.diff => funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff} (73%) create mode 100644 tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff create mode 100644 tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs index 6e74cc91c5b27..c64bb0a30720a 100644 --- a/library/coretests/tests/num/flt2dec/mod.rs +++ b/library/coretests/tests/num/flt2dec/mod.rs @@ -914,22 +914,22 @@ where ); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", "")); + assert_eq!(to_string(f, 0.0, Minus, 50000, false), format!("0.{:0>49999}e0", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 50000, false), format!("1.{:0>49999}e1", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 50000, false), format!("1.{:0>49999}e0", "")); assert_eq!( - to_string(f, 1.0e-1, Minus, 80000, false), + to_string(f, 1.0e-1, Minus, 50000, false), format!( - "1.000000000000000055511151231257827021181583404541015625{:0>79945}\ + "1.000000000000000055511151231257827021181583404541015625{:0>49945}\ e-1", "" ) ); assert_eq!( - to_string(f, 1.0e-20, Minus, 80000, false), + to_string(f, 1.0e-20, Minus, 50000, false), format!( "9.999999999999999451532714542095716517295037027873924471077157760\ - 66783064379706047475337982177734375{:0>79901}e-21", + 66783064379706047475337982177734375{:0>49901}e-21", "" ) ); @@ -1150,18 +1150,18 @@ where ); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000), format!("0.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000), format!("10.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000), format!("1.{:0>80000}", "")); + assert_eq!(to_string(f, 0.0, Minus, 50000), format!("0.{:0>50000}", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 50000), format!("10.{:0>50000}", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 50000), format!("1.{:0>50000}", "")); assert_eq!( - to_string(f, 1.0e-1, Minus, 80000), - format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "") + to_string(f, 1.0e-1, Minus, 50000), + format!("0.1000000000000000055511151231257827021181583404541015625{:0>49945}", "") ); assert_eq!( - to_string(f, 1.0e-20, Minus, 80000), + to_string(f, 1.0e-20, Minus, 50000), format!( "0.0000000000000000000099999999999999994515327145420957165172950370\ - 2787392447107715776066783064379706047475337982177734375{:0>79881}", + 2787392447107715776066783064379706047475337982177734375{:0>49881}", "" ) ); diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff similarity index 73% rename from tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff rename to tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff index a1be927e1c04a..45fc7365d8d6c 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff @@ -29,6 +29,16 @@ 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}) { + } + } + } } } } @@ -65,9 +75,12 @@ bb3: { StorageLive(_6); - _6 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); - _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; + 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]; } bb4: { @@ -135,7 +148,33 @@ } bb9: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_24); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + } + + bb10: { unreachable; } + + bb11: { + _6 = const Option::::None; + goto -> bb9; + } + + bb12: { + _24 = move ((_22 as Some).0: u16); + StorageLive(_25); + _25 = copy _24 as usize (IntToInt); + _6 = Option::::Some(move _25); + StorageDead(_25); + goto -> bb9; + } + } + + ALLOC0 (size: 8, align: 4) { + 00 00 00 00 __ __ __ __ │ ....░░░░ } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff similarity index 73% rename from tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff rename to tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff index 87ab71feb2faa..578d2c2194b0e 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff @@ -29,6 +29,16 @@ 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}) { + } + } + } } } } @@ -65,9 +75,12 @@ bb3: { StorageLive(_6); - _6 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); - _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; + 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]; } bb4: { @@ -135,7 +148,33 @@ } bb9: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_24); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + } + + bb10: { unreachable; } + + bb11: { + _6 = const Option::::None; + goto -> bb9; + } + + bb12: { + _24 = move ((_22 as Some).0: u16); + StorageLive(_25); + _25 = copy _24 as usize (IntToInt); + _6 = Option::::Some(move _25); + StorageDead(_25); + goto -> bb9; + } + } + + ALLOC0 (size: 8, align: 4) { + 00 00 00 00 __ __ __ __ │ ....░░░░ } 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 new file mode 100644 index 0000000000000..5f0f7d6cc74fb --- /dev/null +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff @@ -0,0 +1,180 @@ +- // MIR for `float_to_exponential_common` before GVN ++ // MIR for `float_to_exponential_common` after GVN + + fn float_to_exponential_common(_1: &mut Formatter<'_>, _2: &T, _3: bool) -> Result<(), std::fmt::Error> { + debug fmt => _1; + debug num => _2; + debug upper => _3; + let mut _0: std::result::Result<(), std::fmt::Error>; + let _4: bool; + let mut _6: std::option::Option; + let mut _7: isize; + let mut _9: &mut std::fmt::Formatter<'_>; + let mut _10: &T; + let mut _11: core::num::flt2dec::Sign; + let mut _12: u32; + let mut _13: u32; + let mut _14: usize; + let mut _15: bool; + let mut _16: &mut std::fmt::Formatter<'_>; + let mut _17: &T; + let mut _18: core::num::flt2dec::Sign; + let mut _19: bool; + scope 1 { + debug force_sign => _4; + let _5: core::num::flt2dec::Sign; + scope 2 { + debug sign => _5; + scope 3 { + 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}) { + } + } + } + } + } + } + } + scope 4 (inlined Formatter::<'_>::sign_plus) { + let mut _20: u32; + let mut _21: u32; + } + + bb0: { + StorageLive(_4); + StorageLive(_20); + StorageLive(_21); + _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _20 = BitAnd(move _21, const 1_u32); + StorageDead(_21); + _4 = Ne(move _20, const 0_u32); + StorageDead(_20); + StorageLive(_5); + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { +- _5 = MinusPlus; ++ _5 = const MinusPlus; + goto -> bb3; + } + + bb2: { +- _5 = core::num::flt2dec::Sign::Minus; ++ _5 = const core::num::flt2dec::Sign::Minus; + goto -> bb3; + } + + 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]; + } + + bb4: { +- StorageLive(_8); ++ nop; + _8 = copy ((_6 as Some).0: usize); + StorageLive(_9); + _9 = copy _1; + StorageLive(_10); + _10 = copy _2; + StorageLive(_11); + _11 = copy _5; + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + _14 = copy _8; +- _13 = move _14 as u32 (IntToInt); ++ _13 = copy _8 as u32 (IntToInt); + StorageDead(_14); + _12 = Add(move _13, const 1_u32); + StorageDead(_13); + StorageLive(_15); + _15 = copy _3; +- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind unreachable]; ++ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _11, move _12, copy _3) -> [return: bb5, unwind unreachable]; + } + + bb5: { + StorageDead(_15); + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); +- StorageDead(_8); ++ nop; + goto -> bb8; + } + + bb6: { + StorageLive(_16); + _16 = copy _1; + StorageLive(_17); + _17 = copy _2; + StorageLive(_18); + _18 = copy _5; + StorageLive(_19); + _19 = copy _3; +- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind unreachable]; ++ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _18, copy _3) -> [return: bb7, unwind unreachable]; + } + + bb7: { + StorageDead(_19); + StorageDead(_18); + StorageDead(_17); + StorageDead(_16); + goto -> bb8; + } + + bb8: { + StorageDead(_5); + StorageDead(_4); + StorageDead(_6); + return; + } + + bb9: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_24); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + } + + bb10: { + unreachable; + } + + bb11: { + _6 = const Option::::None; + goto -> bb9; + } + + bb12: { + _24 = move ((_22 as Some).0: u16); + StorageLive(_25); + _25 = copy _24 as usize (IntToInt); + _6 = Option::::Some(move _25); + StorageDead(_25); + goto -> bb9; + } + } + + ALLOC0 (size: 16, align: 8) { + 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ + } + 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 new file mode 100644 index 0000000000000..10cc46a8b8285 --- /dev/null +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff @@ -0,0 +1,180 @@ +- // MIR for `float_to_exponential_common` before GVN ++ // MIR for `float_to_exponential_common` after GVN + + fn float_to_exponential_common(_1: &mut Formatter<'_>, _2: &T, _3: bool) -> Result<(), std::fmt::Error> { + debug fmt => _1; + debug num => _2; + debug upper => _3; + let mut _0: std::result::Result<(), std::fmt::Error>; + let _4: bool; + let mut _6: std::option::Option; + let mut _7: isize; + let mut _9: &mut std::fmt::Formatter<'_>; + let mut _10: &T; + let mut _11: core::num::flt2dec::Sign; + let mut _12: u32; + let mut _13: u32; + let mut _14: usize; + let mut _15: bool; + let mut _16: &mut std::fmt::Formatter<'_>; + let mut _17: &T; + let mut _18: core::num::flt2dec::Sign; + let mut _19: bool; + scope 1 { + debug force_sign => _4; + let _5: core::num::flt2dec::Sign; + scope 2 { + debug sign => _5; + scope 3 { + 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}) { + } + } + } + } + } + } + } + scope 4 (inlined Formatter::<'_>::sign_plus) { + let mut _20: u32; + let mut _21: u32; + } + + bb0: { + StorageLive(_4); + StorageLive(_20); + StorageLive(_21); + _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _20 = BitAnd(move _21, const 1_u32); + StorageDead(_21); + _4 = Ne(move _20, const 0_u32); + StorageDead(_20); + StorageLive(_5); + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { +- _5 = MinusPlus; ++ _5 = const MinusPlus; + goto -> bb3; + } + + bb2: { +- _5 = core::num::flt2dec::Sign::Minus; ++ _5 = const core::num::flt2dec::Sign::Minus; + goto -> bb3; + } + + 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]; + } + + bb4: { +- StorageLive(_8); ++ nop; + _8 = copy ((_6 as Some).0: usize); + StorageLive(_9); + _9 = copy _1; + StorageLive(_10); + _10 = copy _2; + StorageLive(_11); + _11 = copy _5; + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + _14 = copy _8; +- _13 = move _14 as u32 (IntToInt); ++ _13 = copy _8 as u32 (IntToInt); + StorageDead(_14); + _12 = Add(move _13, const 1_u32); + StorageDead(_13); + StorageLive(_15); + _15 = copy _3; +- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind continue]; ++ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _11, move _12, copy _3) -> [return: bb5, unwind continue]; + } + + bb5: { + StorageDead(_15); + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); +- StorageDead(_8); ++ nop; + goto -> bb8; + } + + bb6: { + StorageLive(_16); + _16 = copy _1; + StorageLive(_17); + _17 = copy _2; + StorageLive(_18); + _18 = copy _5; + StorageLive(_19); + _19 = copy _3; +- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind continue]; ++ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _18, copy _3) -> [return: bb7, unwind continue]; + } + + bb7: { + StorageDead(_19); + StorageDead(_18); + StorageDead(_17); + StorageDead(_16); + goto -> bb8; + } + + bb8: { + StorageDead(_5); + StorageDead(_4); + StorageDead(_6); + return; + } + + bb9: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_24); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + } + + bb10: { + unreachable; + } + + bb11: { + _6 = const Option::::None; + goto -> bb9; + } + + bb12: { + _24 = move ((_22 as Some).0: u16); + StorageLive(_25); + _25 = copy _24 as usize (IntToInt); + _6 = Option::::Some(move _25); + StorageDead(_25); + goto -> bb9; + } + } + + ALLOC0 (size: 16, align: 8) { + 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ + } + diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs index fc3691049eb4a..403a22ebed320 100644 --- a/tests/mir-opt/funky_arms.rs +++ b/tests/mir-opt/funky_arms.rs @@ -1,5 +1,6 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// EMIT_MIR_FOR_EACH_BIT_WIDTH #![feature(flt2dec)] From abe9c7048f624fa73e97b0a69e5b852ba97a3568 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 12 Feb 2025 18:17:28 +0100 Subject: [PATCH 03/17] Fix rust-analyzer for 16-bit fmt width and precision. --- src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index 28c824fd31d73..24badc52f25ac 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -137,7 +137,7 @@ pub enum FormatAlignment { #[derive(Clone, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` - Literal(usize), + Literal(u16), /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. Argument(FormatArgPosition), } From d5ab078fd712b6538e5eb814da1fb244a49e2552 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 19 Feb 2025 23:56:16 +0100 Subject: [PATCH 04/17] 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 | 418 ++++++++++-------- 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, 354 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 34c0837b25a52..d48470626092b 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 bce4e242e08aa..41bb22a568c45 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -987,7 +987,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 b8eb77c52c558..0d562cbcd286f 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,25 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { } unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { - fmt.options.fill = arg.fill; - fmt.options.align = arg.align.into(); - fmt.options.flags = arg.flags; - // SAFETY: arg and args come from the same Arguments, - // which guarantees the indexes are always within bounds. - unsafe { - fmt.options.width = getcount(args, &arg.width); - fmt.options.precision = getcount(args, &arg.precision); - } + let (width, precision) = + // SAFETY: arg and args come from the same Arguments, + // which guarantees the indexes are always within bounds. + unsafe { (getcount(args, &arg.width), getcount(args, &arg.precision)) }; + + #[cfg(bootstrap)] + let options = + *FormattingOptions { flags: flags::ALWAYS_SET | arg.flags << 21, width: 0, precision: 0 } + .align(match arg.align { + rt::Alignment::Left => Some(Alignment::Left), + rt::Alignment::Right => Some(Alignment::Right), + rt::Alignment::Center => Some(Alignment::Center), + rt::Alignment::Unknown => None, + }) + .fill(arg.fill) + .width(width) + .precision(precision); + #[cfg(not(bootstrap))] + let options = FormattingOptions { flags: arg.flags, width, precision }; // Extract the correct argument debug_assert!(arg.position < args.len()); @@ -1494,17 +1532,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 +1554,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 +1681,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 +1738,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 +1760,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 +1791,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 +1816,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 +1834,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 +1851,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 +1973,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 +2008,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 +2043,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 +2073,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 +2108,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 +2144,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 +2173,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 +2201,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 +2227,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 +2816,7 @@ impl Debug for char { #[stable(feature = "rust1", since = "1.0.0")] impl Display for char { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - if f.options.width.is_none() && f.options.precision.is_none() { + if f.options.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; MAX_LEN_UTF8])) @@ -2792,26 +2840,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) { From de8bc3fedfb8321674fc7c50f0a49faaac72914f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 00:35:52 +0100 Subject: [PATCH 05/17] Make crash test 129109 independent from format_args!(). --- tests/crashes/129109.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/crashes/129109.rs b/tests/crashes/129109.rs index 0db53b98a7112..993023c4b045d 100644 --- a/tests/crashes/129109.rs +++ b/tests/crashes/129109.rs @@ -6,5 +6,7 @@ extern "C" { } fn main() { - println!("C", unsafe { &symbol }); + match &unsafe { &symbol } { + _x => {} + } } From 2e50dc1c8492f0197edabb55c0aa094fc8e69c20 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 00:35:52 +0100 Subject: [PATCH 06/17] Make crash test 131507 independent from format_args!(). --- tests/crashes/131507.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/crashes/131507.rs b/tests/crashes/131507.rs index 05b5e76bed7d6..03059e77825a4 100644 --- a/tests/crashes/131507.rs +++ b/tests/crashes/131507.rs @@ -6,5 +6,5 @@ fn brick() where for T: Copy, { - || format_args!(""); + || Some::<&[()]>(&[]); } From fb9770b3e43180e423435df2fceb407f6f034fca Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 00:36:59 +0100 Subject: [PATCH 07/17] Refactor fmt::Arguments to just two pointers in size. --- compiler/rustc_ast/src/format.rs | 7 + compiler/rustc_ast_lowering/messages.ftl | 3 + compiler/rustc_ast_lowering/src/errors.rs | 7 + compiler/rustc_ast_lowering/src/expr.rs | 26 +- compiler/rustc_ast_lowering/src/format.rs | 517 ++++++++++++---------- compiler/rustc_hir/src/lang_items.rs | 5 +- compiler/rustc_span/src/symbol.rs | 8 +- library/core/src/fmt/mod.rs | 385 +++++++++++----- library/core/src/fmt/rt.rs | 118 ++++- library/core/src/panicking.rs | 24 +- 10 files changed, 708 insertions(+), 392 deletions(-) diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index b611ddea1d9f1..b227961f9aa7d 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -160,6 +160,13 @@ impl FormatArgumentKind { &Self::Captured(id) => Some(id), } } + + pub fn is_captured(&self) -> bool { + match self { + Self::Captured(_) => true, + _ => false, + } + } } #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 1b91c33742d8b..bab94eb4d9c1f 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -175,6 +175,9 @@ ast_lowering_template_modifier = template modifier ast_lowering_this_not_async = this is not `async` +ast_lowering_too_many_format_arguments = + too many arguments used in format string + ast_lowering_underscore_array_length_unstable = using `_` for array lengths is unstable diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index f31e2db051d81..f21b331471242 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -467,3 +467,10 @@ pub(crate) struct UseConstGenericArg { #[suggestion_part(code = "{other_args}")] pub call_args: Span, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_too_many_format_arguments)] +pub(crate) struct TooManyFormatArguments { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d967772c93bfd..1840153556ca3 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2129,12 +2129,12 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]))) } - pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + pub(super) fn expr_u64(&mut self, sp: Span, value: u64) -> hir::Expr<'hir> { let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Int( - (value as u128).into(), - ast::LitIntType::Unsigned(ast::UintTy::Usize), + u128::from(value).into(), + ast::LitIntType::Unsigned(ast::UintTy::U64), ), }); self.expr(sp, hir::ExprKind::Lit(lit)) @@ -2151,12 +2151,12 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(sp, hir::ExprKind::Lit(lit)) } - pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> { + pub(super) fn expr_usize(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> { let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Int( u128::from(value).into(), - ast::LitIntType::Unsigned(ast::UintTy::U16), + ast::LitIntType::Unsigned(ast::UintTy::Usize), ), }); self.expr(sp, hir::ExprKind::Lit(lit)) @@ -2287,6 +2287,22 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(b.span, hir::ExprKind::Block(b, None)) } + pub(super) fn expr_unsafe_block( + &mut self, + span: Span, + expr: &'hir hir::Expr<'hir>, + ) -> hir::Expr<'hir> { + let hir_id = self.next_id(); + self.expr_block(self.arena.alloc(hir::Block { + stmts: &[], + expr: Some(expr), + hir_id, + rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated), + span, + targeted_by_break: false, + })) + } + pub(super) fn expr_array_ref( &mut self, span: Span, diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 343895984ca42..2adc56b216636 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -1,14 +1,15 @@ -use core::ops::ControlFlow; use std::borrow::Cow; +use std::ops::ControlFlow; use rustc_ast::visit::Visitor; use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_session::config::FmtDebug; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use super::LoweringContext; +use super::errors::TooManyFormatArguments; impl<'hir> LoweringContext<'_, 'hir> { pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> { @@ -84,28 +85,31 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut was_inlined = vec![false; fmt.arguments.all_args().len()]; let mut inlined_anything = false; - for i in 0..fmt.template.len() { - let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] else { continue }; - let Ok(arg_index) = placeholder.argument.index else { continue }; + let mut i = 0; - let mut literal = None; - - if let FormatTrait::Display = placeholder.format_trait + while i < fmt.template.len() { + if let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] + && let Ok(arg_index) = placeholder.argument.index + && let FormatTrait::Display = placeholder.format_trait && placeholder.format_options == Default::default() && let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs() && let ExprKind::Lit(lit) = arg.kind + && let Some(literal) = self.try_inline_lit(lit) { - literal = self.try_inline_lit(lit); - } - - if let Some(literal) = literal { // Now we need to mutate the outer FormatArgs. // If this is the first time, this clones the outer FormatArgs. let fmt = fmt.to_mut(); // Replace the placeholder with the literal. - fmt.template[i] = FormatArgsPiece::Literal(literal); + if literal.is_empty() { + fmt.template.remove(i); + } else { + fmt.template[i] = FormatArgsPiece::Literal(literal); + i += 1; + } was_inlined[arg_index] = true; inlined_anything = true; + } else { + i += 1; } } @@ -221,6 +225,7 @@ fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> { enum ArgumentType { Format(FormatTrait), Usize, + Constant(u16), } /// Generate a hir expression representing an argument to a format_args invocation. @@ -254,103 +259,49 @@ fn make_argument<'hir>( Format(Binary) => sym::new_binary, Format(LowerHex) => sym::new_lower_hex, Format(UpperHex) => sym::new_upper_hex, - Usize => sym::from_usize, + Usize | Constant(_) => sym::from_usize, }, )); ctx.expr_call_mut(sp, new_fn, std::slice::from_ref(arg)) } -/// Generate a hir expression for a format_args Count. +/// Generate a hir expression for a format_piece. /// /// Generates: /// /// ```text -/// ::Is(…) -/// ``` -/// -/// or -/// -/// ```text -/// ::Param(…) -/// ``` -/// -/// or -/// -/// ```text -/// ::Implied +/// ::…(…) /// ``` -fn make_count<'hir>( +fn make_piece<'hir>( ctx: &mut LoweringContext<'_, 'hir>, + constructor: Symbol, + expr: hir::Expr<'hir>, sp: Span, - count: &Option, - argmap: &mut FxIndexMap<(usize, ArgumentType), Option>, ) -> hir::Expr<'hir> { - match count { - Some(FormatCount::Literal(n)) => { - let count_is = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - sp, - hir::LangItem::FormatCount, - sym::Is, - )); - let value = ctx.arena.alloc_from_iter([ctx.expr_u16(sp, *n)]); - ctx.expr_call_mut(sp, count_is, value) - } - Some(FormatCount::Argument(arg)) => { - if let Ok(arg_index) = arg.index { - let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize), arg.span); - let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - sp, - hir::LangItem::FormatCount, - sym::Param, - )); - let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, i)]); - ctx.expr_call_mut(sp, count_param, value) - } else { - ctx.expr( - sp, - hir::ExprKind::Err( - ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count"), - ), - ) - } - } - None => ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatCount, sym::Implied), - } + let new_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatPiece, + constructor, + )); + let new_args = ctx.arena.alloc_from_iter([expr]); + ctx.expr(sp, hir::ExprKind::Call(new_fn, new_args)) } -/// Generate a hir expression for a format_args placeholder specification. -/// -/// Generates -/// -/// ```text -/// ::…, // alignment -/// …u32, // flags -/// , // width -/// , // precision -/// ) -/// ``` -fn make_format_spec<'hir>( - ctx: &mut LoweringContext<'_, 'hir>, - sp: Span, +/// Generate the 64 bit descriptor for a format_args placeholder specification. +// This needs to match the constants in library/core/src/fmt/rt.rs! +fn make_format_spec( placeholder: &FormatPlaceholder, argmap: &mut FxIndexMap<(usize, ArgumentType), Option>, -) -> hir::Expr<'hir> { - let position = match placeholder.argument.index { - Ok(arg_index) => { - let (i, _) = argmap.insert_full( - (arg_index, ArgumentType::Format(placeholder.format_trait)), - placeholder.span, - ); - ctx.expr_usize(sp, i) - } - Err(_) => ctx.expr( - sp, - hir::ExprKind::Err(ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count")), - ), - }; +) -> u64 { + let position = argmap + .insert_full( + ( + placeholder.argument.index.unwrap_or(usize::MAX), + ArgumentType::Format(placeholder.format_trait), + ), + placeholder.span, + ) + .0 as u64; let &FormatOptions { ref width, ref precision, @@ -362,14 +313,12 @@ fn make_format_spec<'hir>( debug_hex, } = &placeholder.format_options; 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 @@ -380,17 +329,39 @@ fn make_format_spec<'hir>( | (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); - let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - sp, - hir::LangItem::FormatPlaceholder, - sym::new, - )); - let args = ctx.arena.alloc_from_iter([position, flags, precision, width]); - ctx.expr_call_mut(sp, format_placeholder_new, args) + | 1 << 31; + let (width_indirect, width) = make_count(width, argmap); + let (precision_indirect, precision) = make_count(precision, argmap); + (flags as u64) << 32 + | (precision_indirect as u64) << 31 + | (width_indirect as u64) << 30 + | precision << 20 + | width << 10 + | position +} + +fn make_count( + count: &Option, + argmap: &mut FxIndexMap<(usize, ArgumentType), Option>, +) -> (bool, u64) { + match count { + None => (false, 0), + &Some(FormatCount::Literal(n)) => { + if n < 1 << 10 { + (false, n as u64) + } else { + // Too big. Upgrade to an argument. + let index = + argmap.insert_full((usize::MAX, ArgumentType::Constant(n)), None).0 as u64; + (true, index) + } + } + Some(FormatCount::Argument(arg)) => ( + true, + argmap.insert_full((arg.index.unwrap_or(usize::MAX), ArgumentType::Usize), arg.span).0 + as u64, + ), + } } fn expand_format_args<'hir>( @@ -399,82 +370,143 @@ fn expand_format_args<'hir>( fmt: &FormatArgs, allow_const: bool, ) -> hir::ExprKind<'hir> { + // // Create a list of all _unique_ (argument, format trait) combinations. + // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] + // + // We use usize::MAX for arguments that don't exist, because that can never be a valid index + // into the arguments array. + let mut argmap = FxIndexMap::default(); + + // Generate: + // + // ``` + // &[ + // Piece { i: 4 }, + // Piece { p: "meow" as *const str as *const u8 }, + // Piece { i: 0xE000_0020_0000_0002 }, + // …, + // Piece { i: 0 }, + // ] + // ``` + let mut pieces = Vec::new(); + let mut incomplete_lit = String::new(); - let lit_pieces = - ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| { - match piece { - &FormatArgsPiece::Literal(s) => { - // Coalesce adjacent literal pieces. - if let Some(FormatArgsPiece::Literal(_)) = fmt.template.get(i + 1) { - incomplete_lit.push_str(s.as_str()); - None - } else if !incomplete_lit.is_empty() { - incomplete_lit.push_str(s.as_str()); - let s = Symbol::intern(&incomplete_lit); - incomplete_lit.clear(); - Some(ctx.expr_str(fmt.span, s)) - } else { - Some(ctx.expr_str(fmt.span, s)) - } + + let default_options = 0xE000_0020_0000_0000; + let mut implicit_arg_index = 0; + + for (i, piece) in fmt.template.iter().enumerate() { + match piece { + &FormatArgsPiece::Literal(sym) => { + assert!(!sym.is_empty()); + // Coalesce adjacent literal pieces. + if let Some(FormatArgsPiece::Literal(_)) = fmt.template.get(i + 1) { + incomplete_lit.push_str(sym.as_str()); + continue; } - &FormatArgsPiece::Placeholder(_) => { - // Inject empty string before placeholders when not already preceded by a literal piece. - if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) { - Some(ctx.expr_str(fmt.span, kw::Empty)) - } else { - None + let (sym, len) = if incomplete_lit.is_empty() { + (sym, sym.as_str().len()) + } else { + incomplete_lit.push_str(sym.as_str()); + let sym = Symbol::intern(&incomplete_lit); + let len = incomplete_lit.len(); + incomplete_lit.clear(); + (sym, len) + }; + + // ``` + // Piece::num(4), + // ``` + let i = if ctx.tcx.sess.target.pointer_width >= 64 { + ctx.expr_u64(fmt.span, len as u64) + } else { + ctx.expr_u32(fmt.span, len as u32) + }; + pieces.push(make_piece(ctx, sym::num, i, macsp)); + + // ``` + // Piece::str("meow"), + // ``` + let s = ctx.expr_str(fmt.span, sym); + pieces.push(make_piece(ctx, sym::str, s, macsp)); + } + FormatArgsPiece::Placeholder(ref p) => { + // ``` + // Piece::num(0xE000_0020_0000_0000), + // ``` + // Or, on <64 bit platforms: + // ``` + // Piece::num(0xE000_0020), + // Piece::num(0x0000_0000), + // ``` + + let bits = make_format_spec(p, &mut argmap); + + // If this placeholder uses the next argument index, is surrounded by literal string + // pieces, and uses default formatting options, then we can skip it, as this kind of + // placeholder is implied by two consequtive string pieces. + if bits == default_options + implicit_arg_index { + if let (Some(FormatArgsPiece::Literal(_)), Some(FormatArgsPiece::Literal(_))) = + (fmt.template.get(i.wrapping_sub(1)), fmt.template.get(i + 1)) + { + implicit_arg_index += 1; + continue; } } - } - })); - let lit_pieces = ctx.expr_array_ref(fmt.span, lit_pieces); - // Whether we'll use the `Arguments::new_v1_formatted` form (true), - // or the `Arguments::new_v1` form (false). - let mut use_format_options = false; + if ctx.tcx.sess.target.pointer_width >= 64 { + let bits = ctx.expr_u64(fmt.span, bits); + pieces.push(make_piece(ctx, sym::num, bits, macsp)); + } else { + let high = ctx.expr_u32(fmt.span, (bits >> 32) as u32); + let low = ctx.expr_u32(fmt.span, bits as u32); + pieces.push(make_piece(ctx, sym::num, high, macsp)); + pieces.push(make_piece(ctx, sym::num, low, macsp)); + } - // Create a list of all _unique_ (argument, format trait) combinations. - // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] - let mut argmap = FxIndexMap::default(); - for piece in &fmt.template { - let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; - if placeholder.format_options != Default::default() { - // Can't use basic form if there's any formatting options. - use_format_options = true; - } - if let Ok(index) = placeholder.argument.index { - if argmap - .insert((index, ArgumentType::Format(placeholder.format_trait)), placeholder.span) - .is_some() - { - // Duplicate (argument, format trait) combination, - // which we'll only put once in the args array. - use_format_options = true; + implicit_arg_index = (bits & 0x3FF) + 1; } } } - let format_options = use_format_options.then(|| { - // Generate: - // &[format_spec_0, format_spec_1, format_spec_2] - let elements = ctx.arena.alloc_from_iter(fmt.template.iter().filter_map(|piece| { - let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; - Some(make_format_spec(ctx, macsp, placeholder, &mut argmap)) - })); - ctx.expr_array_ref(macsp, elements) - }); + assert!(incomplete_lit.is_empty()); + + // Zero terminator. + // + // ``` + // Piece::num(0), + // ``` + let zero = ctx.expr_u64(fmt.span, 0); + pieces.push(make_piece(ctx, sym::num, zero, macsp)); + + // ``` + // unsafe { ::new(&[pieces…]) } + // ``` + let template_new = + ctx.expr_lang_item_type_relative(macsp, hir::LangItem::FormatTemplate, sym::new); + let pieces = ctx.expr_array_ref(fmt.span, ctx.arena.alloc_from_iter(pieces)); + let template = ctx.expr( + macsp, + hir::ExprKind::Call(ctx.arena.alloc(template_new), ctx.arena.alloc_from_iter([pieces])), + ); + let template = ctx.expr_unsafe_block(macsp, ctx.arena.alloc(template)); + + // Ensure all argument indexes actually fit in 10 bits, as we truncated them to 10 bits before. + if argmap.len() >= 1 << 10 { + ctx.dcx().emit_err(TooManyFormatArguments { span: fmt.span }); + } let arguments = fmt.arguments.all_args(); if allow_const && arguments.is_empty() && argmap.is_empty() { // Generate: - // ::new_const(lit_pieces) + // ::new_const(template) let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( macsp, hir::LangItem::FormatArguments, sym::new_const, )); - let new_args = ctx.arena.alloc_from_iter([lit_pieces]); + let new_args = ctx.arena.alloc_from_iter([template]); return hir::ExprKind::Call(new, new_args); } @@ -485,11 +517,19 @@ fn expand_format_args<'hir>( // // This is an optimization, speeding up compilation about 1-2% in some cases. // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609 - let use_simple_array = argmap.len() == arguments.len() - && argmap.iter().enumerate().all(|(i, (&(j, _), _))| i == j) + let use_simple_array = argmap + .iter() + // Don't care about non-arguments. + .filter(|(&(arg, _), _)| arg != usize::MAX) + .enumerate() + // Don't care about captured arguments, as their expression has no side effects. + .filter(|(_, (&(arg, _), _))| !arguments[arg].kind.is_captured()) + // Check that the argument indexes are used one by one in order. + .all(|(i, (&(arg, _), _))| i == arg) + // And check that none except possibly the first argument have a yield point. && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr)); - let args = if arguments.is_empty() { + let args = if argmap.is_empty() && arguments.is_empty() { // Generate: // &::none() // @@ -520,22 +560,37 @@ fn expand_format_args<'hir>( // ::new_debug(&arg2), // … // ] - let elements = ctx.arena.alloc_from_iter(arguments.iter().zip(argmap).map( - |(arg, ((_, ty), placeholder_span))| { - let placeholder_span = - placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); - let arg_span = match arg.kind { - FormatArgumentKind::Captured(_) => placeholder_span, - _ => arg.expr.span.with_ctxt(macsp.ctxt()), - }; - let arg = ctx.lower_expr(&arg.expr); - let ref_arg = ctx.arena.alloc(ctx.expr( - arg_span, - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), - )); - make_argument(ctx, placeholder_span, ref_arg, ty) - }, - )); + let elements = + ctx.arena.alloc_from_iter(argmap.iter().map(|(&(arg_index, ty), placeholder_span)| { + if let ArgumentType::Constant(c) = ty { + let arg = ctx.arena.alloc(ctx.expr_usize(macsp, c)); + let arg = ctx.arena.alloc(ctx.expr( + macsp, + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), + )); + make_argument(ctx, macsp, arg, ty) + } else if let Some(arg) = arguments.get(arg_index) { + let placeholder_span = + placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); + let arg_span = match arg.kind { + FormatArgumentKind::Captured(_) => placeholder_span, + _ => arg.expr.span.with_ctxt(macsp.ctxt()), + }; + let arg = ctx.lower_expr(&arg.expr); + let ref_arg = ctx.arena.alloc(ctx.expr( + arg_span, + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), + )); + make_argument(ctx, placeholder_span, ref_arg, ty) + } else { + ctx.expr( + macsp, + hir::ExprKind::Err( + ctx.dcx().span_delayed_bug(macsp, "missing format_args argument"), + ), + ) + } + })); ctx.expr_array_ref(macsp, elements) } else { // Generate: @@ -551,22 +606,37 @@ fn expand_format_args<'hir>( let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); let args = ctx.arena.alloc_from_iter(argmap.iter().map( |(&(arg_index, ty), &placeholder_span)| { - let arg = &arguments[arg_index]; - let placeholder_span = - placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); - let arg_span = match arg.kind { - FormatArgumentKind::Captured(_) => placeholder_span, - _ => arg.expr.span.with_ctxt(macsp.ctxt()), - }; - let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id); - let arg = ctx.arena.alloc(ctx.expr( - arg_span, - hir::ExprKind::Field( - args_ident_expr, - Ident::new(sym::integer(arg_index), macsp), - ), - )); - make_argument(ctx, placeholder_span, arg, ty) + if let ArgumentType::Constant(c) = ty { + let arg = ctx.arena.alloc(ctx.expr_usize(macsp, c)); + let arg = ctx.arena.alloc(ctx.expr( + macsp, + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), + )); + make_argument(ctx, macsp, arg, ty) + } else if let Some(arg) = arguments.get(arg_index) { + let placeholder_span = + placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); + let arg_span = match arg.kind { + FormatArgumentKind::Captured(_) => placeholder_span, + _ => arg.expr.span.with_ctxt(macsp.ctxt()), + }; + let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id); + let arg = ctx.arena.alloc(ctx.expr( + arg_span, + hir::ExprKind::Field( + args_ident_expr, + Ident::new(sym::integer(arg_index), macsp), + ), + )); + make_argument(ctx, placeholder_span, arg, ty) + } else { + ctx.expr( + macsp, + hir::ExprKind::Err( + ctx.dcx().span_delayed_bug(macsp, "missing format_args argument"), + ), + ) + } }, )); let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| { @@ -591,50 +661,15 @@ fn expand_format_args<'hir>( ) }; - if let Some(format_options) = format_options { - // Generate: - // ::new_v1_formatted( - // lit_pieces, - // args, - // format_options, - // unsafe { ::core::fmt::UnsafeArg::new() } - // ) - let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - macsp, - hir::LangItem::FormatArguments, - sym::new_v1_formatted, - )); - let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - macsp, - hir::LangItem::FormatUnsafeArg, - sym::new, - )); - let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]); - let hir_id = ctx.next_id(); - let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block { - stmts: &[], - expr: Some(unsafe_arg_new_call), - hir_id, - rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated), - span: macsp, - targeted_by_break: false, - })); - let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]); - hir::ExprKind::Call(new_v1_formatted, args) - } else { - // Generate: - // ::new_v1( - // lit_pieces, - // args, - // ) - let new_v1 = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - macsp, - hir::LangItem::FormatArguments, - sym::new_v1, - )); - let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]); - hir::ExprKind::Call(new_v1, new_args) - } + // Generate: + // ::new(template, args) + let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + macsp, + hir::LangItem::FormatArguments, + sym::new, + )); + let new_args = ctx.arena.alloc_from_iter([template, args]); + hir::ExprKind::Call(new, new_args) } fn may_contain_yield_point(e: &ast::Expr) -> bool { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index d48470626092b..77101322b8f02 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -323,9 +323,8 @@ language_item_table! { // Lang items needed for `format_args!()`. 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; - FormatPlaceholder, sym::format_placeholder, format_placeholder, Target::Struct, GenericRequirement::None; - FormatUnsafeArg, sym::format_unsafe_arg, format_unsafe_arg, Target::Struct, GenericRequirement::None; + FormatPiece, sym::format_piece, format_piece, Target::Union, GenericRequirement::None; + FormatTemplate, sym::format_template, format_template, Target::Struct, GenericRequirement::None; ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 41bb22a568c45..16f93373f9062 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -245,7 +245,7 @@ symbols! { HashMapEntry, HashSet, Hasher, - Implied, + IMPLIED, InCleanup, IndexOutput, Input, @@ -993,10 +993,9 @@ symbols! { format_args_nl, format_argument, format_arguments, - format_count, format_macro, - format_placeholder, - format_unsafe_arg, + format_piece, + format_template, freeze, freeze_impls, freg, @@ -1434,6 +1433,7 @@ symbols! { not, notable_trait, note, + num, object_safe_for_dispatch, of, off, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 0d562cbcd286f..8e8e9defa5186 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -7,6 +7,8 @@ use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8}; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; +#[cfg(not(bootstrap))] +use crate::ptr::NonNull; use crate::{iter, mem, result, str}; mod builders; @@ -297,7 +299,7 @@ pub struct FormattingOptions { /// └─ 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.) + /// (fmt::Arguments makes use of this property.) /// ``` flags: u32, /// Width if width flag (bit 27) above is set. Otherwise, always 0. @@ -583,6 +585,83 @@ impl<'a> Formatter<'a> { } } +/// Bootstrap only. +#[cfg(bootstrap)] +#[lang = "format_arguments"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Copy, Clone)] +pub struct Arguments<'a> { + pieces: &'a [&'static str], + fmt: Option<&'a [rt::Placeholder]>, + args: &'a [rt::Argument<'a>], +} + +#[cfg(bootstrap)] +#[doc(hidden)] +#[unstable(feature = "fmt_internals", issue = "none")] +impl<'a> Arguments<'a> { + #[inline] + pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { + const { assert!(N <= 1) }; + Arguments { pieces, fmt: None, args: &[] } + } + + #[inline] + pub const fn new_v1( + pieces: &'a [&'static str; P], + args: &'a [rt::Argument<'a>; A], + ) -> Arguments<'a> { + const { assert!(P >= A && P <= A + 1, "invalid args") } + Arguments { pieces, fmt: None, args } + } + + #[inline] + pub const fn new_v1_formatted( + pieces: &'a [&'static str], + args: &'a [rt::Argument<'a>], + fmt: &'a [rt::Placeholder], + _unsafe_arg: rt::UnsafeArg, + ) -> Arguments<'a> { + Arguments { pieces, fmt: Some(fmt), args } + } + + #[inline] + pub fn estimated_capacity(&self) -> usize { + let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum(); + + if self.args.is_empty() { + pieces_length + } else if !self.pieces.is_empty() && self.pieces[0].is_empty() && pieces_length < 16 { + 0 + } else { + pieces_length.checked_mul(2).unwrap_or(0) + } + } + + #[stable(feature = "fmt_as_str", since = "1.52.0")] + #[rustc_const_stable(feature = "const_arguments_as_str", since = "1.84.0")] + #[must_use] + #[inline] + pub const fn as_str(&self) -> Option<&'static str> { + match (self.pieces, self.args) { + ([], []) => Some(""), + ([s], []) => Some(s), + _ => None, + } + } + + // These two methods are used in library/core/src/panicking.rs to create a + // `fmt::Arguments` for a `&'static str`. + #[inline] + pub(crate) const fn pieces_for_str(s: &'static str) -> [&'static str; 1] { + [s] + } + #[inline] + pub(crate) const unsafe fn from_pieces(p: &'a [&'static str; 1]) -> Self { + Self::new_const(p) + } +} + /// This structure represents a safely precompiled version of a format string /// and its arguments. This cannot be generated at runtime because it cannot /// safely be done, so no constructors are given and the fields are private @@ -605,57 +684,31 @@ impl<'a> Formatter<'a> { /// ``` /// /// [`format()`]: ../../std/fmt/fn.format.html +#[cfg(not(bootstrap))] #[lang = "format_arguments"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone)] pub struct Arguments<'a> { - // Format string pieces to print. - pieces: &'a [&'static str], - - // Placeholder specs, or `None` if all specs are default (as in "{}{}"). - fmt: Option<&'a [rt::Placeholder]>, - - // Dynamic arguments for interpolation, to be interleaved with string - // pieces. (Every argument is preceded by a string piece.) - args: &'a [rt::Argument<'a>], + template: rt::Template<'a>, + args: NonNull>, } /// Used by the format_args!() macro to create a fmt::Arguments object. +#[cfg(not(bootstrap))] #[doc(hidden)] #[unstable(feature = "fmt_internals", issue = "none")] impl<'a> Arguments<'a> { #[inline] - pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { - const { assert!(N <= 1) }; - Arguments { pieces, fmt: None, args: &[] } + pub const fn new_const(template: rt::Template<'a>) -> Arguments<'a> { + Arguments { template, args: NonNull::dangling() } } - /// When using the format_args!() macro, this function is used to generate the - /// Arguments structure. #[inline] - pub const fn new_v1( - pieces: &'a [&'static str; P], - args: &'a [rt::Argument<'a>; A], + pub const fn new( + template: rt::Template<'a>, + args: &'a [rt::Argument<'a>; N], ) -> Arguments<'a> { - const { assert!(P >= A && P <= A + 1, "invalid args") } - Arguments { pieces, fmt: None, args } - } - - /// Specifies nonstandard formatting parameters. - /// - /// An `rt::UnsafeArg` is required because the following invariants must be held - /// in order for this function to be safe: - /// 1. The `pieces` slice must be at least as long as `fmt`. - /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. - /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. - #[inline] - pub const fn new_v1_formatted( - pieces: &'a [&'static str], - args: &'a [rt::Argument<'a>], - fmt: &'a [rt::Placeholder], - _unsafe_arg: rt::UnsafeArg, - ) -> Arguments<'a> { - Arguments { pieces, fmt: Some(fmt), args } + Arguments { template, args: NonNull::from_ref(args).cast() } } /// Estimates the length of the formatted text. @@ -664,22 +717,66 @@ impl<'a> Arguments<'a> { /// when using `format!`. Note: this is neither the lower nor upper bound. #[inline] pub fn estimated_capacity(&self) -> usize { - let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum(); + // Iterate over the template, counting the length of literal pieces. + let mut length = 0usize; + let mut starts_with_placeholder = false; + let mut template = self.template; + let mut has_placeholders = false; + loop { + // SAFETY: We can assume the template is valid. + unsafe { + let n = template.next().i; + if n == 0 { + // End of template. + break; + } else if n <= isize::MAX as _ { + // Literal string piece. + if length != 0 { + // More than one literal string piece means we have placeholders. + has_placeholders = true; + } + length += n as usize; + let _ptr = template.next(); // Skip the string pointer. + } else { + // Placeholder piece. + if length == 0 { + starts_with_placeholder = true; + } + has_placeholders = true; + #[cfg(not(target_pointer_width = "64"))] + let _ = template.next(); // Skip second half of placeholder. + } + } + } - if self.args.is_empty() { - pieces_length - } else if !self.pieces.is_empty() && self.pieces[0].is_empty() && pieces_length < 16 { - // If the format string starts with an argument, + if !has_placeholders { + // If the template has no placeholders, we know the length exactly. + length + } else if starts_with_placeholder && length < 16 { + // If the format string starts with a placeholder, // don't preallocate anything, unless length - // of pieces is significant. + // of literal pieces is significant. 0 } else { - // There are some arguments, so any additional push + // There are some placeholders, so any additional push // will reallocate the string. To avoid that, // we're "pre-doubling" the capacity here. - pieces_length.checked_mul(2).unwrap_or(0) + length.wrapping_mul(2) } } + + // These two methods are used in library/core/src/panicking.rs to create a + // `fmt::Arguments` for a `&'static str`. + #[inline] + pub(crate) const fn pieces_for_str(s: &'static str) -> [rt::Piece; 3] { + [rt::Piece { i: s.len() as _ }, rt::Piece::str(s), rt::Piece { i: 0 }] + } + /// Safety: Only call this with the result of `pieces_for_str`. + #[inline] + pub(crate) const unsafe fn from_pieces(p: &'a [rt::Piece; 3]) -> Self { + // SAFETY: Guaranteed by caller. + Self::new_const(unsafe { rt::Template::new(p) }) + } } impl<'a> Arguments<'a> { @@ -725,16 +822,33 @@ impl<'a> Arguments<'a> { /// assert_eq!(format_args!("").as_str(), Some("")); /// assert_eq!(format_args!("{:?}", std::env::current_dir()).as_str(), None); /// ``` + #[cfg(not(bootstrap))] #[stable(feature = "fmt_as_str", since = "1.52.0")] #[rustc_const_stable(feature = "const_arguments_as_str", since = "1.84.0")] #[must_use] #[inline] pub const fn as_str(&self) -> Option<&'static str> { - match (self.pieces, self.args) { - ([], []) => Some(""), - ([s], []) => Some(s), - _ => None, + let mut template = self.template; + // SAFETY: We can assume the template is valid. + let n = unsafe { template.next().i }; + if n == 0 { + // The template is empty. + return Some(""); + } + if n <= isize::MAX as _ { + // Template starts with a string piece. + // SAFETY: We can assume the template is valid. + unsafe { + let ptr = template.next().p; + if template.next().i == 0 { + // The template has only one piece. + return Some(str::from_utf8_unchecked(crate::slice::from_raw_parts( + ptr, n as usize, + ))); + } + } } + None } /// Same as [`Arguments::as_str`], but will only return `Some(s)` if it can be determined at compile time. @@ -1424,37 +1538,8 @@ pub trait UpperExp { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } -/// Takes an output stream and an `Arguments` struct that can be precompiled with -/// the `format_args!` macro. -/// -/// The arguments will be formatted according to the specified format string -/// into the output stream provided. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::fmt; -/// -/// let mut output = String::new(); -/// fmt::write(&mut output, format_args!("Hello {}!", "world")) -/// .expect("Error occurred while trying to write in String"); -/// assert_eq!(output, "Hello world!"); -/// ``` -/// -/// Please note that using [`write!`] might be preferable. Example: -/// -/// ``` -/// use std::fmt::Write; -/// -/// let mut output = String::new(); -/// write!(&mut output, "Hello {}!", "world") -/// .expect("Error occurred while trying to write in String"); -/// assert_eq!(output, "Hello world!"); -/// ``` -/// -/// [`write!`]: crate::write! +/// Bootstrap only +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { let mut formatter = Formatter::new(output, FormattingOptions::new()); @@ -1505,14 +1590,14 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { Ok(()) } +#[cfg(bootstrap)] unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { 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 = + fmt.options = *FormattingOptions { flags: flags::ALWAYS_SET | arg.flags << 21, width: 0, precision: 0 } .align(match arg.align { rt::Alignment::Left => Some(Alignment::Left), @@ -1523,17 +1608,13 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume .fill(arg.fill) .width(width) .precision(precision); - #[cfg(not(bootstrap))] - let options = FormattingOptions { flags: arg.flags, width, precision }; + let position = arg.position as usize; // Extract the correct argument - debug_assert!(arg.position < args.len()); + debug_assert!(position < args.len()); // SAFETY: arg and args come from the same Arguments, // which guarantees its index is always within bounds. - let value = unsafe { args.get_unchecked(arg.position) }; - - // Set all the formatting options. - fmt.options = options; + let value = unsafe { args.get_unchecked(position) }; // Then actually do some printing // SAFETY: this is a placeholder argument. @@ -1554,16 +1635,99 @@ unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { } } +/// Takes an output stream and an `Arguments` struct that can be precompiled with +/// the `format_args!` macro. +/// +/// The arguments will be formatted according to the specified format string +/// into the output stream provided. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::fmt; +/// +/// let mut output = String::new(); +/// fmt::write(&mut output, format_args!("Hello {}!", "world")) +/// .expect("Error occurred while trying to write in String"); +/// assert_eq!(output, "Hello world!"); +/// ``` +/// +/// Please note that using [`write!`] might be preferable. Example: +/// +/// ``` +/// use std::fmt::Write; +/// +/// let mut output = String::new(); +/// write!(&mut output, "Hello {}!", "world") +/// .expect("Error occurred while trying to write in String"); +/// assert_eq!(output, "Hello world!"); +/// ``` +/// +/// [`write!`]: crate::write! #[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() } +#[stable(feature = "rust1", since = "1.0.0")] +pub fn write(output: &mut dyn Write, fmt: Arguments<'_>) -> Result { + let mut template = fmt.template; + let args = fmt.args; + + let mut last_piece_was_str = false; + let mut implicit_arg_index = 0; + + loop { + // SAFETY: We can assume the template is valid. + let n = unsafe { template.next().i }; + if n == 0 { + // End of template. + return Ok(()); + } else if n <= isize::MAX as _ { + // Literal string piece. + if last_piece_was_str { + // Two consecutive string pieces means we need to insert + // an implicit argument with default options. + let options = FormattingOptions::new(); + // SAFETY: We can assume the template only refers to arguments that exist. + let arg = unsafe { *args.add(implicit_arg_index).as_ref() }; + implicit_arg_index += 1; + // SAFETY: We can assume the placeholders match the arguments. + unsafe { arg.fmt(&mut Formatter::new(output, options)) }?; + } + // SAFETY: We can assume the strings in the template are valid. + let s = unsafe { crate::str::from_raw_parts(template.next().p, n as usize) }; + output.write_str(s)?; + last_piece_was_str = true; + } else { + // Placeholder piece. + #[cfg(target_pointer_width = "64")] + let (high, low) = ((n >> 32) as u32, n as u32); + #[cfg(not(target_pointer_width = "64"))] + // SAFETY: We can assume the template is valid. + let (high, low) = (n as u32, unsafe { template.next().i } as u32); + let arg_index = (low & 0x3FF) as usize; + let mut width = (low >> 10 & 0x3FF) as u16; + let mut precision = (low >> 20 & 0x3FF) as u16; + if low & 1 << 30 != 0 { + // Dynamic width from a usize argument. + // SAFETY: We can assume the template only refers to arguments that exist. + unsafe { + width = args.add(width as usize).as_ref().as_u16().unwrap_unchecked(); + } + } + if low & 1 << 31 != 0 { + // Dynamic precision from a usize argument. + // SAFETY: We can assume the template only refers to arguments that exist. + unsafe { + precision = args.add(precision as usize).as_ref().as_u16().unwrap_unchecked(); + } + } + let options = FormattingOptions { flags: high, width, precision }; + // SAFETY: We can assume the template only refers to arguments that exist. + let arg = unsafe { *args.add(arg_index).as_ref() }; + // SAFETY: We can assume the placeholders match the arguments. + unsafe { arg.fmt(&mut Formatter::new(output, options)) }?; + last_piece_was_str = false; + implicit_arg_index = arg_index + 1; } } } @@ -1738,7 +1902,7 @@ 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.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { + if self.options.flags & (rt::WIDTH_FLAG | rt::PRECISION_FLAG) == 0 { return self.buf.write_str(s); } // The `precision` field can be interpreted as a `max-width` for the @@ -1973,9 +2137,8 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead" )] pub fn flags(&self) -> u32 { - // 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 + // Shift out the fill character from the flags field. + self.options.flags >> 21 } /// Returns the character used as 'fill' whenever there is alignment. @@ -2073,7 +2236,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - if self.options.flags & flags::WIDTH_FLAG == 0 { + if self.options.flags & rt::WIDTH_FLAG == 0 { None } else { Some(self.options.width as usize) @@ -2108,7 +2271,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - if self.options.flags & flags::PRECISION_FLAG == 0 { + if self.options.flags & rt::PRECISION_FLAG == 0 { None } else { Some(self.options.precision as usize) @@ -2144,7 +2307,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.options.flags & flags::SIGN_PLUS_FLAG != 0 + self.options.flags & rt::SIGN_PLUS_FLAG != 0 } /// Determines if the `-` flag was specified. @@ -2173,7 +2336,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.options.flags & flags::SIGN_MINUS_FLAG != 0 + self.options.flags & rt::SIGN_MINUS_FLAG != 0 } /// Determines if the `#` flag was specified. @@ -2201,7 +2364,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.options.flags & flags::ALTERNATE_FLAG != 0 + self.options.flags & rt::ALTERNATE_FLAG != 0 } /// Determines if the `0` flag was specified. @@ -2227,16 +2390,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 & flags::SIGN_AWARE_ZERO_PAD_FLAG != 0 + self.options.flags & rt::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 & flags::DEBUG_LOWER_HEX_FLAG != 0 + self.options.flags & rt::DEBUG_LOWER_HEX_FLAG != 0 } fn debug_upper_hex(&self) -> bool { - self.options.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 + self.options.flags & rt::DEBUG_UPPER_HEX_FLAG != 0 } /// Creates a [`DebugStruct`] builder designed to assist with creation of @@ -2816,7 +2979,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.flags & (flags::WIDTH_FLAG | flags::PRECISION_FLAG) == 0 { + if f.options.flags & (rt::WIDTH_FLAG | rt::PRECISION_FLAG) == 0 { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; MAX_LEN_UTF8])) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index f6d5d2746b29e..0d7bc225507cb 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -5,23 +5,101 @@ use super::*; use crate::hint::unreachable_unchecked; +use crate::marker::PhantomData; use crate::ptr::NonNull; +#[cfg(not(bootstrap))] +#[lang = "format_template"] +#[derive(Copy, Clone)] +pub struct Template<'a> { + pub(super) pieces: NonNull, + lifetime: PhantomData<&'a rt::Piece>, +} + +#[cfg(not(bootstrap))] +unsafe impl Send for Template<'_> {} +#[cfg(not(bootstrap))] +unsafe impl Sync for Template<'_> {} + +#[cfg(not(bootstrap))] +impl<'a> Template<'a> { + #[inline] + pub const unsafe fn new(pieces: &'a [rt::Piece; N]) -> Self { + Self { pieces: NonNull::from_ref(pieces).cast(), lifetime: PhantomData } + } + + #[inline] + pub const unsafe fn next(&mut self) -> Piece { + // SAFETY: Guaranteed by caller. + unsafe { + let piece = *self.pieces.as_ref(); + self.pieces = self.pieces.add(1); + piece + } + } +} + +#[cfg(not(bootstrap))] +#[lang = "format_piece"] +#[derive(Copy, Clone)] +pub union Piece { + #[cfg(target_pointer_width = "64")] + pub i: u64, + #[cfg(not(target_pointer_width = "64"))] + pub i: u32, + pub p: *const u8, +} + +#[cfg(not(bootstrap))] +unsafe impl Send for Piece {} +#[cfg(not(bootstrap))] +unsafe impl Sync for Piece {} + +// These are marked as #[stable] because of #[rustc_promotable] and #[rustc_const_stable]. +// With #[rustc_const_unstable], many format_args!() invocations would result in errors. +// +// There is still no way to use these on stable, because Piece itself is #[unstable] and not +// reachable through any public path. (format_args!()'s expansion uses it as a lang item.) +#[cfg(not(bootstrap))] +impl Piece { + #[rustc_promotable] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const fn str(s: &'static str) -> Self { + Self { p: s as *const str as *const u8 } + } + + #[cfg(target_pointer_width = "64")] + #[rustc_promotable] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const fn num(i: u64) -> Self { + Self { i } + } + + #[cfg(not(target_pointer_width = "64"))] + #[rustc_promotable] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const fn num(i: u32) -> Self { + Self { i } + } +} + +#[cfg(bootstrap)] #[lang = "format_placeholder"] #[derive(Copy, Clone)] pub struct Placeholder { pub position: usize, - #[cfg(bootstrap)] pub fill: char, - #[cfg(bootstrap)] pub align: Alignment, pub flags: u32, pub precision: Count, pub width: Count, } +#[cfg(bootstrap)] impl Placeholder { - #[cfg(bootstrap)] #[inline] pub const fn new( position: usize, @@ -33,12 +111,6 @@ 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)] @@ -53,21 +125,34 @@ pub enum Alignment { /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) /// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. +#[cfg(bootstrap)] #[lang = "format_count"] #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value - #[cfg(bootstrap)] Is(usize), - /// Specified with a literal number, stores the value - #[cfg(not(bootstrap))] - Is(u16), /// Specified using `$` and `*` syntaxes, stores the index into `args` Param(usize), /// Not specified Implied, } +// This needs to match with compiler/rustc_ast_lowering/src/format.rs. +pub const SIGN_PLUS_FLAG: u32 = 1 << 21; +pub const SIGN_MINUS_FLAG: u32 = 1 << 22; +pub const ALTERNATE_FLAG: u32 = 1 << 23; +pub const SIGN_AWARE_ZERO_PAD_FLAG: u32 = 1 << 24; +pub const DEBUG_LOWER_HEX_FLAG: u32 = 1 << 25; +pub const DEBUG_UPPER_HEX_FLAG: u32 = 1 << 26; +pub const WIDTH_FLAG: u32 = 1 << 27; +pub const PRECISION_FLAG: u32 = 1 << 28; +pub const ALIGN_BITS: u32 = 0b11 << 29; +pub const ALIGN_LEFT: u32 = 0 << 29; +pub const ALIGN_RIGHT: u32 = 1 << 29; +pub const ALIGN_CENTER: u32 = 2 << 29; +pub const ALIGN_UNKNOWN: u32 = 3 << 29; +pub const ALWAYS_SET: u32 = 1 << 31; + #[derive(Copy, Clone)] enum ArgumentType<'a> { Placeholder { @@ -210,17 +295,14 @@ impl Argument<'_> { } } -/// This struct represents the unsafety of constructing an `Arguments`. -/// It exists, rather than an unsafe function, in order to simplify the expansion -/// of `format_args!(..)` and reduce the scope of the `unsafe` block. +#[cfg(bootstrap)] #[lang = "format_unsafe_arg"] pub struct UnsafeArg { _private: (), } +#[cfg(bootstrap)] impl UnsafeArg { - /// See documentation where `UnsafeArg` is required to know when it is safe to - /// create and use `UnsafeArg`. #[inline] pub const unsafe fn new() -> Self { Self { _private: () } diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index d36e677d21a18..3b438fd515cfb 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -142,7 +142,8 @@ pub const fn panic(expr: &'static str) -> ! { // payload without any allocation or copying. Shorter-lived strings would become invalid as // stack frames get popped during unwinding, and couldn't be directly referenced from the // payload. - panic_fmt(fmt::Arguments::new_const(&[expr])); + // SAFETY: This is the correct way to make a `fmt::Arguments` from a string literal. + panic_fmt(unsafe { fmt::Arguments::from_pieces(&fmt::Arguments::pieces_for_str(expr)) }); } // We generate functions for usage by compiler-generated assertions. @@ -169,13 +170,8 @@ macro_rules! panic_const { #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = stringify!($lang)] pub const fn $lang() -> ! { - // Use Arguments::new_const instead of format_args!("{expr}") to potentially - // reduce size overhead. The format_args! macro uses str's Display trait to - // write expr, which calls Formatter::pad, which must accommodate string - // truncation and padding (even though none is used here). Using - // Arguments::new_const may allow the compiler to omit Formatter::pad from the - // output binary, saving up to a few kilobytes. - panic_fmt(fmt::Arguments::new_const(&[$message])); + // SAFETY: This is the correct way to make a `fmt::Arguments` from a string literal. + panic_fmt(unsafe { fmt::Arguments::from_pieces(&fmt::Arguments::pieces_for_str($message)) }); } )+ } @@ -215,7 +211,11 @@ panic_const! { #[rustc_nounwind] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_nounwind(expr: &'static str) -> ! { - panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false); + panic_nounwind_fmt( + // SAFETY: This is the correct way to make a `fmt::Arguments` from a string literal. + unsafe { fmt::Arguments::from_pieces(&fmt::Arguments::pieces_for_str(expr)) }, + /* force_no_backtrace */ false, + ); } /// Like `panic_nounwind`, but also inhibits showing a backtrace. @@ -223,7 +223,11 @@ pub const fn panic_nounwind(expr: &'static str) -> ! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[rustc_nounwind] pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { - panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true); + panic_nounwind_fmt( + // SAFETY: This is the correct way to make a `fmt::Arguments` from a string literal. + unsafe { fmt::Arguments::from_pieces(&fmt::Arguments::pieces_for_str(expr)) }, + /* force_no_backtrace */ true, + ); } #[track_caller] From 0df965f2474f790c78b74de77b3c26fde302be13 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 00:37:27 +0100 Subject: [PATCH 08/17] Update tests. --- tests/coverage/closure.cov-map | 20 +- ...onential_common.GVN.32bit.panic-abort.diff | 4 +- ...nential_common.GVN.32bit.panic-unwind.diff | 4 +- ...onential_common.GVN.64bit.panic-abort.diff | 4 +- ...nential_common.GVN.64bit.panic-unwind.diff | 4 +- .../mir-opt/gvn.slices.GVN.panic-unwind.diff | 12 +- ...mes.foo.ScalarReplacementOfAggregates.diff | 173 ++++++++++-------- tests/pretty/issue-4264.pp | 20 +- .../ui/unpretty/flattened-format-args.stdout | 7 +- 9 files changed, 139 insertions(+), 109 deletions(-) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index fa20c8cf6d789..843f9892e053c 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -96,16 +96,14 @@ Number of file 0 mappings: 3 Highest counter ID seen: c1 Function name: closure::main::{closure#15} -Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] +Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, bb, 01, 09, 03, 1b, 05, 03, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 187, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) -- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 187, 9) to (start + 3, 27) +- Code(Counter(1)) at (prev + 3, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) @@ -125,16 +123,14 @@ Number of file 0 mappings: 3 Highest counter ID seen: c1 Function name: closure::main::{closure#17} -Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] +Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, cd, 01, 09, 03, 1b, 05, 03, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 205, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) -- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 205, 9) to (start + 3, 27) +- Code(Counter(1)) at (prev + 3, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) 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 6baa902b6f4bd..554672b8d508a 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 @@ -47,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); + _20 = BitAnd(move _21, const core::fmt::rt::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -72,7 +72,7 @@ StorageLive(_22); StorageLive(_23); _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + _22 = BitAnd(move _23, const core::fmt::rt::PRECISION_FLAG); StorageDead(_23); switchInt(move _22) -> [0: bb10, otherwise: bb11]; } 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 36540e038654f..ffb5bceb9c8c8 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 @@ -47,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); + _20 = BitAnd(move _21, const core::fmt::rt::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -72,7 +72,7 @@ StorageLive(_22); StorageLive(_23); _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + _22 = BitAnd(move _23, const core::fmt::rt::PRECISION_FLAG); StorageDead(_23); switchInt(move _22) -> [0: bb10, otherwise: bb11]; } 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 41c350f3eaeb5..110c74af7b135 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 @@ -47,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); + _20 = BitAnd(move _21, const core::fmt::rt::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -72,7 +72,7 @@ StorageLive(_22); StorageLive(_23); _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + _22 = BitAnd(move _23, const core::fmt::rt::PRECISION_FLAG); StorageDead(_23); switchInt(move _22) -> [0: bb10, otherwise: bb11]; } 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 b839bf81eaf45..bbf79405b803b 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 @@ -47,7 +47,7 @@ StorageLive(_20); StorageLive(_21); _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG); + _20 = BitAnd(move _21, const core::fmt::rt::SIGN_PLUS_FLAG); StorageDead(_21); _4 = Ne(move _20, const 0_u32); StorageDead(_20); @@ -72,7 +72,7 @@ StorageLive(_22); StorageLive(_23); _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); - _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); + _22 = BitAnd(move _23, const core::fmt::rt::PRECISION_FLAG); StorageDead(_23); switchInt(move _22) -> [0: bb10, otherwise: bb11]; } diff --git a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff index 8572f538c0ff7..0c1eb661edf58 100644 --- a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff @@ -202,9 +202,10 @@ + _27 = &(*_12); _26 = &(*_27); StorageLive(_28); - _28 = Option::>::None; +- _28 = Option::>::None; - _22 = assert_failed::<*const u8, *const u8>(move _23, move _24, move _26, move _28) -> unwind continue; -+ _22 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _24, move _26, move _28) -> unwind continue; ++ _28 = const Option::>::None; ++ _22 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _24, move _26, const Option::>::None) -> unwind continue; } bb7: { @@ -299,9 +300,12 @@ + _53 = &(*_38); _52 = &(*_53); StorageLive(_54); - _54 = Option::>::None; +- _54 = Option::>::None; - _48 = assert_failed::<*const u8, *const u8>(move _49, move _50, move _52, move _54) -> unwind continue; -+ _48 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _50, move _52, move _54) -> unwind continue; ++ _54 = const Option::>::None; ++ _48 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _50, move _52, const Option::>::None) -> unwind continue; } } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index a1df868cde051..659fc8a3df288 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -11,28 +11,35 @@ let _9: (); let _10: (); let mut _11: std::fmt::Arguments<'_>; - let mut _12: &[&str; 3]; - let _13: &[&str; 3]; - let _14: [&str; 3]; - let mut _15: &[core::fmt::rt::Argument<'_>; 2]; - let _16: &[core::fmt::rt::Argument<'_>; 2]; - let _17: [core::fmt::rt::Argument<'_>; 2]; - let mut _18: core::fmt::rt::Argument<'_>; - let mut _19: &std::boxed::Box; - let _20: &std::boxed::Box; - let mut _21: core::fmt::rt::Argument<'_>; - let mut _22: &u32; - let _23: &u32; - let mut _25: bool; - let mut _26: isize; - let mut _27: isize; - let mut _28: isize; -+ let _29: std::result::Result, ::Err>; -+ let _30: u32; + let mut _12: core::fmt::rt::Template<'_>; + let mut _13: &[core::fmt::rt::Piece; 6]; + let _14: &[core::fmt::rt::Piece; 6]; + let _15: [core::fmt::rt::Piece; 6]; + let mut _16: core::fmt::rt::Piece; + let mut _17: core::fmt::rt::Piece; + let mut _18: core::fmt::rt::Piece; + let mut _19: core::fmt::rt::Piece; + let mut _20: core::fmt::rt::Piece; + let mut _21: core::fmt::rt::Piece; + let mut _22: &[core::fmt::rt::Argument<'_>; 2]; + let _23: &[core::fmt::rt::Argument<'_>; 2]; + let _24: [core::fmt::rt::Argument<'_>; 2]; + let mut _25: core::fmt::rt::Argument<'_>; + let mut _26: &std::boxed::Box; + let _27: &std::boxed::Box; + let mut _28: core::fmt::rt::Argument<'_>; + let mut _29: &u32; + let _30: &u32; + let mut _32: bool; + let mut _33: isize; + let mut _34: isize; + let mut _35: isize; ++ let _36: std::result::Result, ::Err>; ++ let _37: u32; scope 1 { - debug foo => _1; -+ debug ((foo: Foo).0: std::result::Result, ::Err>) => _29; -+ debug ((foo: Foo).1: u32) => _30; ++ debug ((foo: Foo).0: std::result::Result, ::Err>) => _36; ++ debug ((foo: Foo).1: u32) => _37; let _5: std::result::Result, ::Err>; scope 2 { debug x => _5; @@ -42,17 +49,17 @@ scope 4 { debug x => _8; let _8: std::boxed::Box; - let mut _24: &[&str; 3]; + let mut _31: &[core::fmt::rt::Piece; 6]; } } } } bb0: { - _25 = const false; + _32 = const false; - StorageLive(_1); -+ StorageLive(_29); -+ StorageLive(_30); ++ StorageLive(_36); ++ StorageLive(_37); + nop; StorageLive(_2); StorageLive(_3); @@ -66,120 +73,126 @@ _2 = Result::, ::Err>::Ok(move _3); StorageDead(_3); - _1 = Foo:: { x: move _2, y: const 7_u32 }; -+ _29 = move _2; -+ _30 = const 7_u32; ++ _36 = move _2; ++ _37 = const 7_u32; + nop; StorageDead(_2); StorageLive(_5); - _25 = const true; + _32 = const true; - _5 = move (_1.0: std::result::Result, ::Err>); -+ _5 = move _29; ++ _5 = move _36; StorageLive(_6); - _6 = copy (_1.1: u32); -+ _6 = copy _30; ++ _6 = copy _37; _7 = discriminant(_5); - switchInt(move _7) -> [0: bb2, otherwise: bb7]; + switchInt(move _7) -> [0: bb2, otherwise: bb8]; } bb2: { StorageLive(_8); - _25 = const false; + _32 = const false; _8 = move ((_5 as Ok).0: std::boxed::Box); StorageLive(_9); StorageLive(_10); StorageLive(_11); StorageLive(_12); StorageLive(_13); - _24 = const foo::::promoted[0]; - _13 = &(*_24); - _12 = &(*_13); - StorageLive(_15); - StorageLive(_16); - StorageLive(_17); - StorageLive(_18); - StorageLive(_19); - StorageLive(_20); - _20 = &_8; - _19 = &(*_20); - _18 = core::fmt::rt::Argument::<'_>::new_display::>(move _19) -> [return: bb3, unwind unreachable]; + StorageLive(_14); + _31 = const foo::::promoted[0]; + _14 = &(*_31); + _13 = &(*_14); + _12 = core::fmt::rt::Template::<'_>::new::<6>(move _13) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_19); - StorageLive(_21); + StorageDead(_13); StorageLive(_22); StorageLive(_23); - _23 = &_6; - _22 = &(*_23); - _21 = core::fmt::rt::Argument::<'_>::new_display::(move _22) -> [return: bb4, unwind unreachable]; + StorageLive(_24); + StorageLive(_25); + StorageLive(_26); + StorageLive(_27); + _27 = &_8; + _26 = &(*_27); + _25 = core::fmt::rt::Argument::<'_>::new_display::>(move _26) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_22); - _17 = [move _18, move _21]; - StorageDead(_21); - StorageDead(_18); - _16 = &_17; - _15 = &(*_16); - _11 = Arguments::<'_>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable]; + StorageDead(_26); + StorageLive(_28); + StorageLive(_29); + StorageLive(_30); + _30 = &_6; + _29 = &(*_30); + _28 = core::fmt::rt::Argument::<'_>::new_display::(move _29) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_15); - StorageDead(_12); - _10 = _eprint(move _11) -> [return: bb6, unwind unreachable]; + StorageDead(_29); + _24 = [move _25, move _28]; + StorageDead(_28); + StorageDead(_25); + _23 = &_24; + _22 = &(*_23); + _11 = Arguments::<'_>::new::<2>(move _12, move _22) -> [return: bb6, unwind unreachable]; } bb6: { + StorageDead(_22); + StorageDead(_12); + _10 = _eprint(move _11) -> [return: bb7, unwind unreachable]; + } + + bb7: { StorageDead(_11); + StorageDead(_30); + StorageDead(_27); + StorageDead(_24); StorageDead(_23); - StorageDead(_20); - StorageDead(_17); - StorageDead(_16); - StorageDead(_13); + StorageDead(_14); StorageDead(_10); _9 = const (); StorageDead(_9); _0 = const (); - drop(_8) -> [return: bb8, unwind unreachable]; + drop(_8) -> [return: bb9, unwind unreachable]; } - bb7: { + bb8: { _0 = const (); - goto -> bb9; + goto -> bb10; } - bb8: { + bb9: { StorageDead(_8); - goto -> bb9; + goto -> bb10; } - bb9: { + bb10: { StorageDead(_6); - _26 = discriminant(_5); - switchInt(move _26) -> [0: bb11, otherwise: bb13]; + _33 = discriminant(_5); + switchInt(move _33) -> [0: bb12, otherwise: bb14]; } - bb10: { - _25 = const false; + bb11: { + _32 = const false; StorageDead(_5); - StorageDead(_1); -+ StorageDead(_29); -+ StorageDead(_30); ++ StorageDead(_36); ++ StorageDead(_37); + nop; return; } - bb11: { - switchInt(copy _25) -> [0: bb10, otherwise: bb12]; - } - bb12: { - drop(((_5 as Ok).0: std::boxed::Box)) -> [return: bb10, unwind unreachable]; + switchInt(copy _32) -> [0: bb11, otherwise: bb13]; } bb13: { - drop(_5) -> [return: bb10, unwind unreachable]; + drop(((_5 as Ok).0: std::boxed::Box)) -> [return: bb11, unwind unreachable]; + } + + bb14: { + drop(_5) -> [return: bb11, unwind unreachable]; } } diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index fa958d9f1e8f8..83c746c207d45 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -35,9 +35,23 @@ ((::alloc::fmt::format as for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const as - fn(&[&'static str; 1]) -> Arguments<'_> {Arguments::<'_>::new_const::<1>})((&([("test" - as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>)) - as String); + fn(core::fmt::rt::Template<'_>) -> Arguments<'_> {Arguments::<'_>::new_const})((unsafe + { + ((format_template::new as + unsafe fn(&[core::fmt::rt::Piece; 3]) -> core::fmt::rt::Template<'_> {core::fmt::rt::Template::<'_>::new::<3>})((&([((format_piece::num + as + fn(u64) -> core::fmt::rt::Piece {core::fmt::rt::Piece::num})((4u64 + as u64)) as core::fmt::rt::Piece), + ((format_piece::str as + fn(&'static str) -> core::fmt::rt::Piece {core::fmt::rt::Piece::str})(("test" + as &str)) as core::fmt::rt::Piece), + ((format_piece::num as + fn(u64) -> core::fmt::rt::Piece {core::fmt::rt::Piece::num})((0u64 + as u64)) as core::fmt::rt::Piece)] as + [core::fmt::rt::Piece; 3]) as &[core::fmt::rt::Piece; 3])) + as core::fmt::rt::Template<'_>) + } as core::fmt::rt::Template<'_>)) as Arguments<'_>)) as + String); (res as String) } as String)) as String); } as ()) diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout index 2de1cdd96b5b7..0846e94e2ed43 100644 --- a/tests/ui/unpretty/flattened-format-args.stdout +++ b/tests/ui/unpretty/flattened-format-args.stdout @@ -9,7 +9,10 @@ fn main() { let x = 1; // Should flatten to println!("a 123 b {x} xyz\n"): { - ::std::io::_print(format_arguments::new_v1(&["a 123 b ", " xyz\n"], - &[format_argument::new_display(&x)])); + ::std::io::_print(format_arguments::new(unsafe { + format_template::new(&[format_piece::num(8u64), + format_piece::str("a 123 b "), format_piece::num(5u64), + format_piece::str(" xyz\n"), format_piece::num(0u64)]) + }, &[format_argument::new_display(&x)])); }; } From fcef7606e293f832cf9f687b3e6d916d85756a2b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 13:02:03 +0100 Subject: [PATCH 09/17] Fix lowering captured format args more than once. --- compiler/rustc_ast_lowering/src/format.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 2adc56b216636..fb0cd03f14bf9 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -522,8 +522,6 @@ fn expand_format_args<'hir>( // Don't care about non-arguments. .filter(|(&(arg, _), _)| arg != usize::MAX) .enumerate() - // Don't care about captured arguments, as their expression has no side effects. - .filter(|(_, (&(arg, _), _))| !arguments[arg].kind.is_captured()) // Check that the argument indexes are used one by one in order. .all(|(i, (&(arg, _), _))| i == arg) // And check that none except possibly the first argument have a yield point. From 3a5fb6929d1b7f5456e17aa9c1730d5495992f41 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 13:09:30 +0100 Subject: [PATCH 10/17] Fix format_args!() for 32-bit. --- compiler/rustc_ast_lowering/src/format.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index fb0cd03f14bf9..4a013b3ecb524 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -476,7 +476,11 @@ fn expand_format_args<'hir>( // ``` // Piece::num(0), // ``` - let zero = ctx.expr_u64(fmt.span, 0); + let zero = if ctx.tcx.sess.target.pointer_width >= 64 { + ctx.expr_u64(fmt.span, 0) + } else { + ctx.expr_u32(fmt.span, 0) + }; pieces.push(make_piece(ctx, sym::num, zero, macsp)); // ``` From 2956a7d9f7c4148dfe8a27e85219857e22f1ac80 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 15:20:45 +0100 Subject: [PATCH 11/17] Use `usize` in format_args!() and have expansion for 16-bit. --- compiler/rustc_ast_lowering/src/expr.rs | 24 +------------ compiler/rustc_ast_lowering/src/format.rs | 42 ++++++++++++++--------- library/core/src/fmt/mod.rs | 17 +++++++-- library/core/src/fmt/rt.rs | 16 ++------- 4 files changed, 42 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1840153556ca3..325e25727ed64 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2129,29 +2129,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]))) } - pub(super) fn expr_u64(&mut self, sp: Span, value: u64) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { - span: sp, - node: ast::LitKind::Int( - u128::from(value).into(), - ast::LitIntType::Unsigned(ast::UintTy::U64), - ), - }); - self.expr(sp, hir::ExprKind::Lit(lit)) - } - - pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { - span: sp, - node: ast::LitKind::Int( - u128::from(value).into(), - ast::LitIntType::Unsigned(ast::UintTy::U32), - ), - }); - self.expr(sp, hir::ExprKind::Lit(lit)) - } - - pub(super) fn expr_usize(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> { + pub(super) fn expr_usize(&mut self, sp: Span, value: u64) -> hir::Expr<'hir> { let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Int( diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 4a013b3ecb524..217f9b326bb26 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -417,11 +417,7 @@ fn expand_format_args<'hir>( // ``` // Piece::num(4), // ``` - let i = if ctx.tcx.sess.target.pointer_width >= 64 { - ctx.expr_u64(fmt.span, len as u64) - } else { - ctx.expr_u32(fmt.span, len as u32) - }; + let i = ctx.expr_usize(macsp, len as u64); pieces.push(make_piece(ctx, sym::num, i, macsp)); // ``` @@ -434,11 +430,18 @@ fn expand_format_args<'hir>( // ``` // Piece::num(0xE000_0020_0000_0000), // ``` - // Or, on <64 bit platforms: + // Or, on 32 bit platforms: // ``` // Piece::num(0xE000_0020), // Piece::num(0x0000_0000), // ``` + // Or, on 16 bit platforms: + // ``` + // Piece::num(0xE000), + // Piece::num(0x0020), + // Piece::num(0x0000), + // Piece::num(0x0000), + // ``` let bits = make_format_spec(p, &mut argmap); @@ -455,13 +458,22 @@ fn expand_format_args<'hir>( } if ctx.tcx.sess.target.pointer_width >= 64 { - let bits = ctx.expr_u64(fmt.span, bits); + let bits = ctx.expr_usize(macsp, bits); pieces.push(make_piece(ctx, sym::num, bits, macsp)); - } else { - let high = ctx.expr_u32(fmt.span, (bits >> 32) as u32); - let low = ctx.expr_u32(fmt.span, bits as u32); + } else if ctx.tcx.sess.target.pointer_width >= 32 { + let high = ctx.expr_usize(macsp, bits >> 32); + let low = ctx.expr_usize(macsp, bits & 0xFFFF_FFFF); pieces.push(make_piece(ctx, sym::num, high, macsp)); pieces.push(make_piece(ctx, sym::num, low, macsp)); + } else { + let w1 = ctx.expr_usize(macsp, bits >> 48); + let w2 = ctx.expr_usize(macsp, bits >> 32 & 0xFFFF); + let w3 = ctx.expr_usize(macsp, bits >> 16 & 0xFFFF); + let w4 = ctx.expr_usize(macsp, bits & 0xFFFF); + pieces.push(make_piece(ctx, sym::num, w1, macsp)); + pieces.push(make_piece(ctx, sym::num, w2, macsp)); + pieces.push(make_piece(ctx, sym::num, w3, macsp)); + pieces.push(make_piece(ctx, sym::num, w4, macsp)); } implicit_arg_index = (bits & 0x3FF) + 1; @@ -476,11 +488,7 @@ fn expand_format_args<'hir>( // ``` // Piece::num(0), // ``` - let zero = if ctx.tcx.sess.target.pointer_width >= 64 { - ctx.expr_u64(fmt.span, 0) - } else { - ctx.expr_u32(fmt.span, 0) - }; + let zero = ctx.expr_usize(macsp, 0); pieces.push(make_piece(ctx, sym::num, zero, macsp)); // ``` @@ -565,7 +573,7 @@ fn expand_format_args<'hir>( let elements = ctx.arena.alloc_from_iter(argmap.iter().map(|(&(arg_index, ty), placeholder_span)| { if let ArgumentType::Constant(c) = ty { - let arg = ctx.arena.alloc(ctx.expr_usize(macsp, c)); + let arg = ctx.arena.alloc(ctx.expr_usize(macsp, c.into())); let arg = ctx.arena.alloc(ctx.expr( macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), @@ -609,7 +617,7 @@ fn expand_format_args<'hir>( let args = ctx.arena.alloc_from_iter(argmap.iter().map( |(&(arg_index, ty), &placeholder_span)| { if let ArgumentType::Constant(c) = ty { - let arg = ctx.arena.alloc(ctx.expr_usize(macsp, c)); + let arg = ctx.arena.alloc(ctx.expr_usize(macsp, c.into())); let arg = ctx.arena.alloc(ctx.expr( macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 8e8e9defa5186..4d1b707c92a40 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -743,8 +743,11 @@ impl<'a> Arguments<'a> { starts_with_placeholder = true; } has_placeholders = true; - #[cfg(not(target_pointer_width = "64"))] - let _ = template.next(); // Skip second half of placeholder. + // Skip remainder of placeholder: + #[cfg(target_pointer_width = "32")] + let _ = template.next(); + #[cfg(target_pointer_width = "16")] + let _ = (template.next(), template.next(), template.next()); } } } @@ -1701,9 +1704,17 @@ pub fn write(output: &mut dyn Write, fmt: Arguments<'_>) -> Result { // Placeholder piece. #[cfg(target_pointer_width = "64")] let (high, low) = ((n >> 32) as u32, n as u32); - #[cfg(not(target_pointer_width = "64"))] + #[cfg(target_pointer_width = "32")] // SAFETY: We can assume the template is valid. let (high, low) = (n as u32, unsafe { template.next().i } as u32); + #[cfg(target_pointer_width = "16")] + // SAFETY: We can assume the template is valid. + let (high, low) = unsafe { + ( + (n as u32) << 16 | template.next().i as u32, + (template.next().i as u32) << 16 | template.next().i as u32, + ) + }; let arg_index = (low & 0x3FF) as usize; let mut width = (low >> 10 & 0x3FF) as u16; let mut precision = (low >> 20 & 0x3FF) as u16; diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 0d7bc225507cb..63ca1e2293686 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -43,10 +43,7 @@ impl<'a> Template<'a> { #[lang = "format_piece"] #[derive(Copy, Clone)] pub union Piece { - #[cfg(target_pointer_width = "64")] - pub i: u64, - #[cfg(not(target_pointer_width = "64"))] - pub i: u32, + pub i: usize, pub p: *const u8, } @@ -69,19 +66,10 @@ impl Piece { Self { p: s as *const str as *const u8 } } - #[cfg(target_pointer_width = "64")] #[rustc_promotable] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] - pub const fn num(i: u64) -> Self { - Self { i } - } - - #[cfg(not(target_pointer_width = "64"))] - #[rustc_promotable] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "rust1", since = "1.0.0")] - pub const fn num(i: u32) -> Self { + pub const fn num(i: usize) -> Self { Self { i } } } From f286669fc8dd76e544e67e4df71af1ed340d2056 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 15:21:28 +0100 Subject: [PATCH 12/17] Update [un]pretty tests. --- tests/pretty/issue-4264.pp | 8 ++++---- tests/ui/unpretty/flattened-format-args.stdout | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index 83c746c207d45..2d03d7f216f34 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -40,14 +40,14 @@ ((format_template::new as unsafe fn(&[core::fmt::rt::Piece; 3]) -> core::fmt::rt::Template<'_> {core::fmt::rt::Template::<'_>::new::<3>})((&([((format_piece::num as - fn(u64) -> core::fmt::rt::Piece {core::fmt::rt::Piece::num})((4u64 - as u64)) as core::fmt::rt::Piece), + fn(usize) -> core::fmt::rt::Piece {core::fmt::rt::Piece::num})((4usize + as usize)) as core::fmt::rt::Piece), ((format_piece::str as fn(&'static str) -> core::fmt::rt::Piece {core::fmt::rt::Piece::str})(("test" as &str)) as core::fmt::rt::Piece), ((format_piece::num as - fn(u64) -> core::fmt::rt::Piece {core::fmt::rt::Piece::num})((0u64 - as u64)) as core::fmt::rt::Piece)] as + fn(usize) -> core::fmt::rt::Piece {core::fmt::rt::Piece::num})((0usize + as usize)) as core::fmt::rt::Piece)] as [core::fmt::rt::Piece; 3]) as &[core::fmt::rt::Piece; 3])) as core::fmt::rt::Template<'_>) } as core::fmt::rt::Template<'_>)) as Arguments<'_>)) as diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout index 0846e94e2ed43..ef21b84ff1380 100644 --- a/tests/ui/unpretty/flattened-format-args.stdout +++ b/tests/ui/unpretty/flattened-format-args.stdout @@ -10,9 +10,9 @@ fn main() { // Should flatten to println!("a 123 b {x} xyz\n"): { ::std::io::_print(format_arguments::new(unsafe { - format_template::new(&[format_piece::num(8u64), - format_piece::str("a 123 b "), format_piece::num(5u64), - format_piece::str(" xyz\n"), format_piece::num(0u64)]) + format_template::new(&[format_piece::num(8usize), + format_piece::str("a 123 b "), format_piece::num(5usize), + format_piece::str(" xyz\n"), format_piece::num(0usize)]) }, &[format_argument::new_display(&x)])); }; } From c9ba28861748a1388d565469004c0ef8e3d89d4a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 15:25:10 +0100 Subject: [PATCH 13/17] Bless mir-opt tests. --- tests/mir-opt/gvn.slices.GVN.panic-abort.diff | 12 +- ...mes.foo.ScalarReplacementOfAggregates.diff | 109 +++++++++--------- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff index 43efcbdfb1e4b..1dff4eb529888 100644 --- a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff @@ -202,9 +202,10 @@ + _27 = &(*_12); _26 = &(*_27); StorageLive(_28); - _28 = Option::>::None; +- _28 = Option::>::None; - _22 = assert_failed::<*const u8, *const u8>(move _23, move _24, move _26, move _28) -> unwind unreachable; -+ _22 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _24, move _26, move _28) -> unwind unreachable; ++ _28 = const Option::>::None; ++ _22 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _24, move _26, const Option::>::None) -> unwind unreachable; } bb7: { @@ -299,9 +300,12 @@ + _53 = &(*_38); _52 = &(*_53); StorageLive(_54); - _54 = Option::>::None; +- _54 = Option::>::None; - _48 = assert_failed::<*const u8, *const u8>(move _49, move _50, move _52, move _54) -> unwind unreachable; -+ _48 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _50, move _52, move _54) -> unwind unreachable; ++ _54 = const Option::>::None; ++ _48 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _50, move _52, const Option::>::None) -> unwind unreachable; } } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index 659fc8a3df288..32ca9c0f7e1d4 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -12,34 +12,35 @@ let _10: (); let mut _11: std::fmt::Arguments<'_>; let mut _12: core::fmt::rt::Template<'_>; - let mut _13: &[core::fmt::rt::Piece; 6]; - let _14: &[core::fmt::rt::Piece; 6]; - let _15: [core::fmt::rt::Piece; 6]; + let mut _13: &[core::fmt::rt::Piece; 7]; + let _14: &[core::fmt::rt::Piece; 7]; + let _15: [core::fmt::rt::Piece; 7]; let mut _16: core::fmt::rt::Piece; let mut _17: core::fmt::rt::Piece; let mut _18: core::fmt::rt::Piece; let mut _19: core::fmt::rt::Piece; let mut _20: core::fmt::rt::Piece; let mut _21: core::fmt::rt::Piece; - let mut _22: &[core::fmt::rt::Argument<'_>; 2]; - let _23: &[core::fmt::rt::Argument<'_>; 2]; - let _24: [core::fmt::rt::Argument<'_>; 2]; - let mut _25: core::fmt::rt::Argument<'_>; - let mut _26: &std::boxed::Box; - let _27: &std::boxed::Box; - let mut _28: core::fmt::rt::Argument<'_>; - let mut _29: &u32; - let _30: &u32; - let mut _32: bool; - let mut _33: isize; + let mut _22: core::fmt::rt::Piece; + let mut _23: &[core::fmt::rt::Argument<'_>; 2]; + let _24: &[core::fmt::rt::Argument<'_>; 2]; + let _25: [core::fmt::rt::Argument<'_>; 2]; + let mut _26: core::fmt::rt::Argument<'_>; + let mut _27: &std::boxed::Box; + let _28: &std::boxed::Box; + let mut _29: core::fmt::rt::Argument<'_>; + let mut _30: &u32; + let _31: &u32; + let mut _33: bool; let mut _34: isize; let mut _35: isize; -+ let _36: std::result::Result, ::Err>; -+ let _37: u32; + let mut _36: isize; ++ let _37: std::result::Result, ::Err>; ++ let _38: u32; scope 1 { - debug foo => _1; -+ debug ((foo: Foo).0: std::result::Result, ::Err>) => _36; -+ debug ((foo: Foo).1: u32) => _37; ++ debug ((foo: Foo).0: std::result::Result, ::Err>) => _37; ++ debug ((foo: Foo).1: u32) => _38; let _5: std::result::Result, ::Err>; scope 2 { debug x => _5; @@ -49,17 +50,17 @@ scope 4 { debug x => _8; let _8: std::boxed::Box; - let mut _31: &[core::fmt::rt::Piece; 6]; + let mut _32: &[core::fmt::rt::Piece; 7]; } } } } bb0: { - _32 = const false; + _33 = const false; - StorageLive(_1); -+ StorageLive(_36); + StorageLive(_37); ++ StorageLive(_38); + nop; StorageLive(_2); StorageLive(_3); @@ -73,24 +74,24 @@ _2 = Result::, ::Err>::Ok(move _3); StorageDead(_3); - _1 = Foo:: { x: move _2, y: const 7_u32 }; -+ _36 = move _2; -+ _37 = const 7_u32; ++ _37 = move _2; ++ _38 = const 7_u32; + nop; StorageDead(_2); StorageLive(_5); - _32 = const true; + _33 = const true; - _5 = move (_1.0: std::result::Result, ::Err>); -+ _5 = move _36; ++ _5 = move _37; StorageLive(_6); - _6 = copy (_1.1: u32); -+ _6 = copy _37; ++ _6 = copy _38; _7 = discriminant(_5); switchInt(move _7) -> [0: bb2, otherwise: bb8]; } bb2: { StorageLive(_8); - _32 = const false; + _33 = const false; _8 = move ((_5 as Ok).0: std::boxed::Box); StorageLive(_9); StorageLive(_10); @@ -98,57 +99,57 @@ StorageLive(_12); StorageLive(_13); StorageLive(_14); - _31 = const foo::::promoted[0]; - _14 = &(*_31); + _32 = const foo::::promoted[0]; + _14 = &(*_32); _13 = &(*_14); - _12 = core::fmt::rt::Template::<'_>::new::<6>(move _13) -> [return: bb3, unwind unreachable]; + _12 = core::fmt::rt::Template::<'_>::new::<7>(move _13) -> [return: bb3, unwind unreachable]; } bb3: { StorageDead(_13); - StorageLive(_22); StorageLive(_23); StorageLive(_24); StorageLive(_25); StorageLive(_26); StorageLive(_27); - _27 = &_8; - _26 = &(*_27); - _25 = core::fmt::rt::Argument::<'_>::new_display::>(move _26) -> [return: bb4, unwind unreachable]; + StorageLive(_28); + _28 = &_8; + _27 = &(*_28); + _26 = core::fmt::rt::Argument::<'_>::new_display::>(move _27) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_26); - StorageLive(_28); + StorageDead(_27); StorageLive(_29); StorageLive(_30); - _30 = &_6; - _29 = &(*_30); - _28 = core::fmt::rt::Argument::<'_>::new_display::(move _29) -> [return: bb5, unwind unreachable]; + StorageLive(_31); + _31 = &_6; + _30 = &(*_31); + _29 = core::fmt::rt::Argument::<'_>::new_display::(move _30) -> [return: bb5, unwind unreachable]; } bb5: { + StorageDead(_30); + _25 = [move _26, move _29]; StorageDead(_29); - _24 = [move _25, move _28]; - StorageDead(_28); - StorageDead(_25); - _23 = &_24; - _22 = &(*_23); - _11 = Arguments::<'_>::new::<2>(move _12, move _22) -> [return: bb6, unwind unreachable]; + StorageDead(_26); + _24 = &_25; + _23 = &(*_24); + _11 = Arguments::<'_>::new::<2>(move _12, move _23) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_22); + StorageDead(_23); StorageDead(_12); _10 = _eprint(move _11) -> [return: bb7, unwind unreachable]; } bb7: { StorageDead(_11); - StorageDead(_30); - StorageDead(_27); + StorageDead(_31); + StorageDead(_28); + StorageDead(_25); StorageDead(_24); - StorageDead(_23); StorageDead(_14); StorageDead(_10); _9 = const (); @@ -169,22 +170,22 @@ bb10: { StorageDead(_6); - _33 = discriminant(_5); - switchInt(move _33) -> [0: bb12, otherwise: bb14]; + _34 = discriminant(_5); + switchInt(move _34) -> [0: bb12, otherwise: bb14]; } bb11: { - _32 = const false; + _33 = const false; StorageDead(_5); - StorageDead(_1); -+ StorageDead(_36); + StorageDead(_37); ++ StorageDead(_38); + nop; return; } bb12: { - switchInt(copy _32) -> [0: bb11, otherwise: bb13]; + switchInt(copy _33) -> [0: bb11, otherwise: bb13]; } bb13: { From fba185340768e4f3cc5f4e116ecd351a92e4a1ed Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 15:25:46 +0100 Subject: [PATCH 14/17] Change span in format_args!() to make Clippy happy. --- compiler/rustc_ast_lowering/src/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 217f9b326bb26..e1f2d959925b7 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -496,7 +496,7 @@ fn expand_format_args<'hir>( // ``` let template_new = ctx.expr_lang_item_type_relative(macsp, hir::LangItem::FormatTemplate, sym::new); - let pieces = ctx.expr_array_ref(fmt.span, ctx.arena.alloc_from_iter(pieces)); + let pieces = ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(pieces)); let template = ctx.expr( macsp, hir::ExprKind::Call(ctx.arena.alloc(template_new), ctx.arena.alloc_from_iter([pieces])), From 6b2013c8cfe6808efea3316a1e47069d29f0dab9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 15:25:59 +0100 Subject: [PATCH 15/17] Update clippy tests. --- .../tests/ui/author/macro_in_closure.stdout | 58 ++++++++++++++----- .../tests/ui/author/macro_in_loop.stdout | 58 ++++++++++++++----- 2 files changed, 84 insertions(+), 32 deletions(-) diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout index 3186d0cbc276c..ebf154369b3f1 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout @@ -12,27 +12,53 @@ if let StmtKind::Let(local) = stmt.kind && args.len() == 1 && let ExprKind::Call(func1, args1) = args[0].kind && let ExprKind::Path(ref qpath1) = func1.kind - && match_qpath(qpath1, &["format_arguments", "new_v1"]) + && match_qpath(qpath1, &["format_arguments", "new"]) && args1.len() == 2 - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind + && let ExprKind::Block(block1, None) = args1[0].kind + && block1.stmts.is_empty() + && let Some(trailing_expr) = block1.expr + && let ExprKind::Call(func2, args2) = trailing_expr.kind + && let ExprKind::Path(ref qpath2) = func2.kind + && match_qpath(qpath2, &["format_template", "new"]) + && args2.len() == 1 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args2[0].kind && let ExprKind::Array(elements) = inner.kind - && elements.len() == 2 - && let ExprKind::Lit(ref lit) = elements[0].kind - && let LitKind::Str(s, _) = lit.node - && s.as_str() == "" - && let ExprKind::Lit(ref lit1) = elements[1].kind - && let LitKind::Str(s1, _) = lit1.node - && s1.as_str() == "\n" + && elements.len() == 4 + && let ExprKind::Call(func3, args3) = elements[0].kind + && let ExprKind::Path(ref qpath3) = func3.kind + && match_qpath(qpath3, &["format_piece", "num"]) + && args3.len() == 1 + && let ExprKind::Lit(ref lit) = args3[0].kind + && let LitKind::Int(16140901201934811136, LitIntType::Unsigned(UintTy::Usize)) = lit.node + && let ExprKind::Call(func4, args4) = elements[1].kind + && let ExprKind::Path(ref qpath4) = func4.kind + && match_qpath(qpath4, &["format_piece", "num"]) + && args4.len() == 1 + && let ExprKind::Lit(ref lit1) = args4[0].kind + && let LitKind::Int(1, LitIntType::Unsigned(UintTy::Usize)) = lit1.node + && let ExprKind::Call(func5, args5) = elements[2].kind + && let ExprKind::Path(ref qpath5) = func5.kind + && match_qpath(qpath5, &["format_piece", "str"]) + && args5.len() == 1 + && let ExprKind::Lit(ref lit2) = args5[0].kind + && let LitKind::Str(s, _) = lit2.node + && s.as_str() == "\n" + && let ExprKind::Call(func6, args6) = elements[3].kind + && let ExprKind::Path(ref qpath6) = func6.kind + && match_qpath(qpath6, &["format_piece", "num"]) + && args6.len() == 1 + && let ExprKind::Lit(ref lit3) = args6[0].kind + && let LitKind::Int(0, LitIntType::Unsigned(UintTy::Usize)) = lit3.node && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind && let ExprKind::Array(elements1) = inner1.kind && elements1.len() == 1 - && let ExprKind::Call(func2, args2) = elements1[0].kind - && let ExprKind::Path(ref qpath2) = func2.kind - && match_qpath(qpath2, &["format_argument", "new_display"]) - && args2.len() == 1 - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind - && let ExprKind::Path(ref qpath3) = inner2.kind - && match_qpath(qpath3, &["x"]) + && let ExprKind::Call(func7, args7) = elements1[0].kind + && let ExprKind::Path(ref qpath7) = func7.kind + && match_qpath(qpath7, &["format_argument", "new_display"]) + && args7.len() == 1 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args7[0].kind + && let ExprKind::Path(ref qpath8) = inner2.kind + && match_qpath(qpath8, &["x"]) && block.expr.is_none() && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "print_text" diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout index 3f9be297c33c5..4643f7fdf5214 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout @@ -22,27 +22,53 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && args.len() == 1 && let ExprKind::Call(func1, args1) = args[0].kind && let ExprKind::Path(ref qpath2) = func1.kind - && match_qpath(qpath2, &["format_arguments", "new_v1"]) + && match_qpath(qpath2, &["format_arguments", "new"]) && args1.len() == 2 - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind + && let ExprKind::Block(block2, None) = args1[0].kind + && block2.stmts.is_empty() + && let Some(trailing_expr) = block2.expr + && let ExprKind::Call(func2, args2) = trailing_expr.kind + && let ExprKind::Path(ref qpath3) = func2.kind + && match_qpath(qpath3, &["format_template", "new"]) + && args2.len() == 1 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args2[0].kind && let ExprKind::Array(elements) = inner.kind - && elements.len() == 2 - && let ExprKind::Lit(ref lit2) = elements[0].kind - && let LitKind::Str(s, _) = lit2.node - && s.as_str() == "" - && let ExprKind::Lit(ref lit3) = elements[1].kind - && let LitKind::Str(s1, _) = lit3.node - && s1.as_str() == "\n" + && elements.len() == 4 + && let ExprKind::Call(func3, args3) = elements[0].kind + && let ExprKind::Path(ref qpath4) = func3.kind + && match_qpath(qpath4, &["format_piece", "num"]) + && args3.len() == 1 + && let ExprKind::Lit(ref lit2) = args3[0].kind + && let LitKind::Int(16140901201934811136, LitIntType::Unsigned(UintTy::Usize)) = lit2.node + && let ExprKind::Call(func4, args4) = elements[1].kind + && let ExprKind::Path(ref qpath5) = func4.kind + && match_qpath(qpath5, &["format_piece", "num"]) + && args4.len() == 1 + && let ExprKind::Lit(ref lit3) = args4[0].kind + && let LitKind::Int(1, LitIntType::Unsigned(UintTy::Usize)) = lit3.node + && let ExprKind::Call(func5, args5) = elements[2].kind + && let ExprKind::Path(ref qpath6) = func5.kind + && match_qpath(qpath6, &["format_piece", "str"]) + && args5.len() == 1 + && let ExprKind::Lit(ref lit4) = args5[0].kind + && let LitKind::Str(s, _) = lit4.node + && s.as_str() == "\n" + && let ExprKind::Call(func6, args6) = elements[3].kind + && let ExprKind::Path(ref qpath7) = func6.kind + && match_qpath(qpath7, &["format_piece", "num"]) + && args6.len() == 1 + && let ExprKind::Lit(ref lit5) = args6[0].kind + && let LitKind::Int(0, LitIntType::Unsigned(UintTy::Usize)) = lit5.node && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind && let ExprKind::Array(elements1) = inner1.kind && elements1.len() == 1 - && let ExprKind::Call(func2, args2) = elements1[0].kind - && let ExprKind::Path(ref qpath3) = func2.kind - && match_qpath(qpath3, &["format_argument", "new_display"]) - && args2.len() == 1 - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind - && let ExprKind::Path(ref qpath4) = inner2.kind - && match_qpath(qpath4, &["i"]) + && let ExprKind::Call(func7, args7) = elements1[0].kind + && let ExprKind::Path(ref qpath8) = func7.kind + && match_qpath(qpath8, &["format_argument", "new_display"]) + && args7.len() == 1 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args7[0].kind + && let ExprKind::Path(ref qpath9) = inner2.kind + && match_qpath(qpath9, &["i"]) && block1.expr.is_none() && block.expr.is_none() { From 23248dd9869a04c634e736720356ba39ab16237d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 15:58:37 +0100 Subject: [PATCH 16/17] Bless ui tests. --- tests/ui/consts/recursive-const-in-impl.stderr | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ui/consts/recursive-const-in-impl.stderr b/tests/ui/consts/recursive-const-in-impl.stderr index 6175112c8cc0d..a00e4c0ca0887 100644 --- a/tests/ui/consts/recursive-const-in-impl.stderr +++ b/tests/ui/consts/recursive-const-in-impl.stderr @@ -1,11 +1,12 @@ error: queries overflow the depth limit! - --> $DIR/recursive-const-in-impl.rs:11:14 + --> $DIR/recursive-const-in-impl.rs:11:5 | LL | println!("{}", Thing::::X); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "14"]` attribute to your crate (`recursive_const_in_impl`) = note: query depth increased by 9 when simplifying constant for the type system `main::promoted[1]` + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error From d5fcc37519862146d0125b7d22dfde9e75c28161 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Feb 2025 16:49:50 +0100 Subject: [PATCH 17/17] Bless coverage tests. --- tests/coverage/assert.cov-map | 13 +- tests/coverage/bad_counter_ids.cov-map | 36 +++--- tests/coverage/closure_macro.cov-map | 12 +- tests/coverage/closure_macro_async.cov-map | 12 +- tests/coverage/issue-84561.cov-map | 140 +++++++++------------ 5 files changed, 86 insertions(+), 127 deletions(-) diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map index 903cccfe9cbce..24cf24bc9251d 100644 --- a/tests/coverage/assert.cov-map +++ b/tests/coverage/assert.cov-map @@ -26,15 +26,12 @@ Number of file 0 mappings: 9 Highest counter ID seen: c3 Function name: assert::might_fail_assert -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 02, 3e, 05, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 15) -- Code(Expression(0, Sub)) at (prev + 2, 37) to (start + 0, 61) - = (c0 - c1) -- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 62) +- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map index baac0073fcbec..6c9d8b5a0e004 100644 --- a/tests/coverage/bad_counter_ids.cov-map +++ b/tests/coverage/bad_counter_ids.cov-map @@ -9,14 +9,13 @@ Number of file 0 mappings: 2 Highest counter ID seen: c0 Function name: bad_counter_ids::eq_bad_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 29, 01, 02, 2c, 00, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 41, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 2, 32) to (start + 0, 43) -- Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 41, 1) to (start + 2, 44) +- Code(Zero) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good @@ -30,14 +29,13 @@ Number of file 0 mappings: 2 Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 01, 02, 2c, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15) -- Code(Zero) at (prev + 2, 32) to (start + 0, 43) -- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 44) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad @@ -51,14 +49,13 @@ Number of file 0 mappings: 2 Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 33, 01, 02, 2c, 00, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 2, 32) to (start + 0, 43) -- Code(Zero) at (prev + 1, 1) to (start + 0, 2) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 51, 1) to (start + 2, 44) +- Code(Zero) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::ne_good @@ -72,13 +69,12 @@ Number of file 0 mappings: 2 Highest counter ID seen: c0 Function name: bad_counter_ids::ne_good_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 1f, 01, 02, 2c, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 15) -- Code(Zero) at (prev + 2, 32) to (start + 0, 43) -- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 44) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index 653848dd6ffc7..6622afa9f09d1 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -25,20 +25,16 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: closure_macro::main::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 1f, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 -Number of expressions: 3 +Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) -- expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 +Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) -- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) +- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 31) = (c0 - c1) -- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30) - = (c0 - (c1 + c2)) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 1bd1460a147a2..82b8cd07e6d46 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -34,20 +34,16 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: closure_macro_async::test::{closure#0}::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 1f, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 -Number of expressions: 3 +Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) -- expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 +Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 20, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) -- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) +- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 31) = (c0 - c1) -- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30) - = (c0 - (c1 + c2)) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index c8f75cddcb5b9..c6952c7e61583 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -22,32 +22,27 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: issue_84561::test1 -Raw bytes (50): 0x[01, 01, 00, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 01, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 01, 01, 01, 00, 02] +Raw bytes (30): 0x[01, 01, 00, 05, 01, 9a, 01, 01, 01, 1f, 01, 02, 05, 00, 1f, 01, 01, 0d, 01, 1f, 01, 02, 05, 03, 1f, 01, 04, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 154, 1) to (start + 1, 11) -- Code(Counter(1)) at (prev + 1, 12) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) -- Code(Counter(2)) at (prev + 0, 12) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 13) to (start + 1, 11) -- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 11) -- Code(Counter(4)) at (prev + 3, 12) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) -Highest counter ID seen: c4 +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 154, 1) to (start + 1, 31) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 13) to (start + 1, 31) +- Code(Counter(0)) at (prev + 2, 5) to (start + 3, 31) +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: issue_84561::test2 -Raw bytes (20): 0x[01, 01, 00, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 01, 01, 01, 00, 02] +Raw bytes (15): 0x[01, 01, 00, 02, 01, b0, 01, 01, 01, 24, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 176, 1) to (start + 1, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35) -- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) -Highest counter ID seen: c1 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 176, 1) to (start + 1, 36) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c0 Function name: issue_84561::test2::call_print Raw bytes (10): 0x[01, 01, 00, 01, 01, a7, 01, 09, 02, 0a] @@ -59,38 +54,29 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: issue_84561::test3 -Raw bytes (315): 0x[01, 01, 1b, 1d, 21, 25, 29, 21, 25, 2d, 31, 21, 17, 25, 2d, 41, 45, 49, 4d, 51, 55, 33, 51, 49, 4d, 33, 37, 49, 4d, 51, 59, 55, 59, 55, 59, 47, 5d, 55, 59, 61, 65, 71, 75, 69, 6d, 69, 6d, 69, 6d, 63, 79, 71, 75, 79, 7d, 7d, 81, 01, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 09, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 11, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 19, 02, 05, 00, 1f, 1d, 01, 05, 00, 0f, 02, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 25, 03, 20, 00, 30, 29, 00, 33, 00, 41, 06, 00, 4b, 00, 5a, 0a, 01, 05, 00, 0f, 2d, 05, 09, 03, 10, 31, 05, 0d, 00, 1b, 0e, 02, 0d, 00, 1c, 12, 04, 09, 05, 06, 35, 06, 05, 03, 06, 39, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 41, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 1a, 05, 09, 03, 0a, 33, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 22, 03, 0d, 00, 1d, 26, 03, 09, 00, 13, 2e, 03, 0d, 00, 1d, 47, 03, 05, 00, 0f, 47, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 42, 02, 0d, 00, 13, 61, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 4a, 02, 0d, 00, 13, 63, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 71, 04, 0d, 00, 13, 5a, 02, 0d, 00, 17, 5a, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 5a, 02, 15, 00, 1b, 75, 04, 0d, 00, 13, 5e, 03, 09, 00, 19, 79, 02, 05, 00, 0f, 66, 03, 09, 00, 22, 7d, 02, 05, 00, 0f, 6a, 03, 09, 00, 2c, 81, 01, 02, 01, 00, 02] +Raw bytes (266): 0x[01, 01, 12, 25, 29, 21, 25, 2d, 31, 21, 13, 25, 2d, 41, 45, 49, 4d, 23, 51, 49, 4d, 55, 59, 55, 59, 33, 5d, 55, 59, 61, 65, 71, 75, 69, 6d, 69, 6d, 69, 6d, 2d, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 09, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 11, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 19, 02, 05, 00, 1f, 1d, 01, 05, 00, 31, 21, 01, 05, 03, 0f, 25, 03, 29, 00, 30, 29, 00, 33, 00, 41, 02, 00, 4b, 00, 5a, 06, 01, 05, 00, 0f, 2d, 08, 09, 00, 10, 31, 02, 0d, 00, 1b, 0a, 02, 0d, 00, 1c, 0e, 04, 09, 05, 06, 35, 06, 05, 03, 06, 39, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 41, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 16, 05, 09, 03, 0a, 23, 05, 08, 00, 0f, 51, 01, 09, 04, 0a, 1e, 06, 09, 04, 0a, 33, 06, 05, 00, 0f, 33, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 2e, 02, 0d, 00, 13, 61, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 36, 02, 0d, 00, 13, 3b, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 71, 04, 0d, 00, 13, 46, 02, 0d, 00, 17, 46, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 46, 02, 15, 00, 1b, 75, 04, 0d, 00, 13, 79, 05, 05, 04, 06, 7d, 05, 05, 04, 06, 81, 01, 05, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 27 -- expression 0 operands: lhs = Counter(7), rhs = Counter(8) -- expression 1 operands: lhs = Counter(9), rhs = Counter(10) -- expression 2 operands: lhs = Counter(8), rhs = Counter(9) -- expression 3 operands: lhs = Counter(11), rhs = Counter(12) -- expression 4 operands: lhs = Counter(8), rhs = Expression(5, Add) -- expression 5 operands: lhs = Counter(9), rhs = Counter(11) -- expression 6 operands: lhs = Counter(16), rhs = Counter(17) -- expression 7 operands: lhs = Counter(18), rhs = Counter(19) -- expression 8 operands: lhs = Counter(20), rhs = Counter(21) -- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(20) -- expression 10 operands: lhs = Counter(18), rhs = Counter(19) -- expression 11 operands: lhs = Expression(12, Add), rhs = Expression(13, Add) -- expression 12 operands: lhs = Counter(18), rhs = Counter(19) -- expression 13 operands: lhs = Counter(20), rhs = Counter(22) -- expression 14 operands: lhs = Counter(21), rhs = Counter(22) -- expression 15 operands: lhs = Counter(21), rhs = Counter(22) -- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(23) -- expression 17 operands: lhs = Counter(21), rhs = Counter(22) -- expression 18 operands: lhs = Counter(24), rhs = Counter(25) -- expression 19 operands: lhs = Counter(28), rhs = Counter(29) -- expression 20 operands: lhs = Counter(26), rhs = Counter(27) -- expression 21 operands: lhs = Counter(26), rhs = Counter(27) -- expression 22 operands: lhs = Counter(26), rhs = Counter(27) -- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(30) -- expression 24 operands: lhs = Counter(28), rhs = Counter(29) -- expression 25 operands: lhs = Counter(30), rhs = Counter(31) -- expression 26 operands: lhs = Counter(31), rhs = Counter(32) -Number of file 0 mappings: 51 +Number of expressions: 18 +- expression 0 operands: lhs = Counter(9), rhs = Counter(10) +- expression 1 operands: lhs = Counter(8), rhs = Counter(9) +- expression 2 operands: lhs = Counter(11), rhs = Counter(12) +- expression 3 operands: lhs = Counter(8), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(9), rhs = Counter(11) +- expression 5 operands: lhs = Counter(16), rhs = Counter(17) +- expression 6 operands: lhs = Counter(18), rhs = Counter(19) +- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(20) +- expression 8 operands: lhs = Counter(18), rhs = Counter(19) +- expression 9 operands: lhs = Counter(21), rhs = Counter(22) +- expression 10 operands: lhs = Counter(21), rhs = Counter(22) +- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(23) +- expression 12 operands: lhs = Counter(21), rhs = Counter(22) +- expression 13 operands: lhs = Counter(24), rhs = Counter(25) +- expression 14 operands: lhs = Counter(28), rhs = Counter(29) +- expression 15 operands: lhs = Counter(26), rhs = Counter(27) +- expression 16 operands: lhs = Counter(26), rhs = Counter(27) +- expression 17 operands: lhs = Counter(26), rhs = Counter(27) +Number of file 0 mappings: 45 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28) - Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28) - Code(Counter(2)) at (prev + 2, 5) to (start + 4, 31) @@ -98,70 +84,58 @@ Number of file 0 mappings: 51 - Code(Counter(4)) at (prev + 1, 5) to (start + 0, 31) - Code(Counter(5)) at (prev + 1, 9) to (start + 1, 28) - Code(Counter(6)) at (prev + 2, 5) to (start + 0, 31) -- Code(Counter(7)) at (prev + 1, 5) to (start + 0, 15) -- Code(Expression(0, Sub)) at (prev + 0, 32) to (start + 0, 48) - = (c7 - c8) +- Code(Counter(7)) at (prev + 1, 5) to (start + 0, 49) - Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15) -- Code(Counter(9)) at (prev + 3, 32) to (start + 0, 48) +- Code(Counter(9)) at (prev + 3, 41) to (start + 0, 48) - Code(Counter(10)) at (prev + 0, 51) to (start + 0, 65) -- Code(Expression(1, Sub)) at (prev + 0, 75) to (start + 0, 90) +- Code(Expression(0, Sub)) at (prev + 0, 75) to (start + 0, 90) = (c9 - c10) -- Code(Expression(2, Sub)) at (prev + 1, 5) to (start + 0, 15) +- Code(Expression(1, Sub)) at (prev + 1, 5) to (start + 0, 15) = (c8 - c9) -- Code(Counter(11)) at (prev + 5, 9) to (start + 3, 16) -- Code(Counter(12)) at (prev + 5, 13) to (start + 0, 27) -- Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 28) +- Code(Counter(11)) at (prev + 8, 9) to (start + 0, 16) +- Code(Counter(12)) at (prev + 2, 13) to (start + 0, 27) +- Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 28) = (c11 - c12) -- Code(Expression(4, Sub)) at (prev + 4, 9) to (start + 5, 6) +- Code(Expression(3, Sub)) at (prev + 4, 9) to (start + 5, 6) = (c8 - (c9 + c11)) - Code(Counter(13)) at (prev + 6, 5) to (start + 3, 6) - Code(Counter(14)) at (prev + 4, 5) to (start + 3, 6) - Code(Counter(15)) at (prev + 4, 9) to (start + 4, 6) - Code(Counter(16)) at (prev + 5, 8) to (start + 0, 15) - Code(Counter(17)) at (prev + 1, 9) to (start + 3, 10) -- Code(Expression(6, Sub)) at (prev + 5, 9) to (start + 3, 10) +- Code(Expression(5, Sub)) at (prev + 5, 9) to (start + 3, 10) = (c16 - c17) -- Code(Expression(12, Add)) at (prev + 5, 8) to (start + 0, 15) +- Code(Expression(8, Add)) at (prev + 5, 8) to (start + 0, 15) = (c18 + c19) -- Code(Counter(20)) at (prev + 1, 9) to (start + 0, 19) -- Code(Expression(8, Sub)) at (prev + 3, 13) to (start + 0, 29) - = (c20 - c21) -- Code(Expression(9, Sub)) at (prev + 3, 9) to (start + 0, 19) +- Code(Counter(20)) at (prev + 1, 9) to (start + 4, 10) +- Code(Expression(7, Sub)) at (prev + 6, 9) to (start + 4, 10) = ((c18 + c19) - c20) -- Code(Expression(11, Sub)) at (prev + 3, 13) to (start + 0, 29) - = ((c18 + c19) - (c20 + c22)) -- Code(Expression(17, Add)) at (prev + 3, 5) to (start + 0, 15) +- Code(Expression(12, Add)) at (prev + 6, 5) to (start + 0, 15) = (c21 + c22) -- Code(Expression(17, Add)) at (prev + 1, 12) to (start + 0, 19) +- Code(Expression(12, Add)) at (prev + 1, 12) to (start + 0, 19) = (c21 + c22) - Code(Counter(23)) at (prev + 1, 13) to (start + 0, 19) -- Code(Expression(16, Sub)) at (prev + 2, 13) to (start + 0, 19) +- Code(Expression(11, Sub)) at (prev + 2, 13) to (start + 0, 19) = ((c21 + c22) - c23) - Code(Counter(24)) at (prev + 4, 5) to (start + 2, 19) - Code(Counter(25)) at (prev + 3, 13) to (start + 0, 19) -- Code(Expression(18, Sub)) at (prev + 2, 13) to (start + 0, 19) +- Code(Expression(13, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c24 - c25) -- Code(Expression(24, Add)) at (prev + 3, 5) to (start + 0, 15) +- Code(Expression(14, Add)) at (prev + 3, 5) to (start + 0, 15) = (c28 + c29) - Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19) - Code(Counter(27)) at (prev + 1, 13) to (start + 3, 14) - Code(Counter(28)) at (prev + 4, 13) to (start + 0, 19) -- Code(Expression(22, Sub)) at (prev + 2, 13) to (start + 0, 23) +- Code(Expression(17, Sub)) at (prev + 2, 13) to (start + 0, 23) = (c26 - c27) -- Code(Expression(22, Sub)) at (prev + 1, 20) to (start + 0, 27) +- Code(Expression(17, Sub)) at (prev + 1, 20) to (start + 0, 27) = (c26 - c27) - Code(Zero) at (prev + 1, 21) to (start + 0, 27) -- Code(Expression(22, Sub)) at (prev + 2, 21) to (start + 0, 27) +- Code(Expression(17, Sub)) at (prev + 2, 21) to (start + 0, 27) = (c26 - c27) - Code(Counter(29)) at (prev + 4, 13) to (start + 0, 19) -- Code(Expression(23, Sub)) at (prev + 3, 9) to (start + 0, 25) - = ((c28 + c29) - c30) -- Code(Counter(30)) at (prev + 2, 5) to (start + 0, 15) -- Code(Expression(25, Sub)) at (prev + 3, 9) to (start + 0, 34) - = (c30 - c31) -- Code(Counter(31)) at (prev + 2, 5) to (start + 0, 15) -- Code(Expression(26, Sub)) at (prev + 3, 9) to (start + 0, 44) - = (c31 - c32) -- Code(Counter(32)) at (prev + 2, 1) to (start + 0, 2) +- Code(Counter(30)) at (prev + 5, 5) to (start + 4, 6) +- Code(Counter(31)) at (prev + 5, 5) to (start + 4, 6) +- Code(Counter(32)) at (prev + 5, 1) to (start + 0, 2) Highest counter ID seen: c32