about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMara Bos <m-ou.se@m-ou.se>2025-02-12 16:59:13 +0100
committerMara Bos <m-ou.se@m-ou.se>2025-03-10 12:20:05 +0100
commitfb9ce0297682a0c54fe374800c2a41cc666d9580 (patch)
tree3823aad2927922171871ea611d922bb2d8610636
parent2c6a12ec44d0426c8939123c2f2cf27d2217de13 (diff)
downloadrust-fb9ce0297682a0c54fe374800c2a41cc666d9580.tar.gz
rust-fb9ce0297682a0c54fe374800c2a41cc666d9580.zip
Limit formatting width and precision to 16 bits.
-rw-r--r--compiler/rustc_ast/src/format.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs11
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs2
-rw-r--r--compiler/rustc_parse_format/src/lib.rs18
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/fmt/float.rs12
-rw-r--r--library/core/src/fmt/mod.rs51
-rw-r--r--library/core/src/fmt/rt.rs13
-rw-r--r--library/core/src/time.rs3
-rw-r--r--library/coretests/tests/num/flt2dec/mod.rs2
10 files changed, 69 insertions, 46 deletions
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
index b93846c1fe6..b611ddea1d9 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 acf35b75e4d..0f175ea615f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -2152,6 +2152,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 07b94dbc2ae..faa47274f96 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 287bd8678da..5b8a2fe52d3 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -189,7 +189,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.
@@ -564,7 +564,7 @@ impl<'a> Parser<'a> {
     /// consuming a macro argument, `None` if it's the case.
     fn position(&mut self) -> Option<Position<'a>> {
         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) => {
@@ -770,7 +770,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();
@@ -821,15 +821,15 @@ impl<'a> Parser<'a> {
         word
     }
 
-    fn integer(&mut self) -> Option<usize> {
-        let mut cur: usize = 0;
+    fn integer(&mut self) -> Option<u16> {
+        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;
                 }
@@ -846,11 +846,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 9e7f5047eb3..8b701de3454 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1016,6 +1016,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 3f10158193d..4a43c12be9a 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<T>(
     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<T>(
     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<T>(
     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 3f60bb067d6..e0dc632df70 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<Alignment>,
-    width: Option<usize>,
-    precision: Option<usize>,
+    width: Option<u16>,
+    precision: Option<u16>,
 }
 
 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<usize>) -> &mut Self {
+    pub fn width(&mut self, width: Option<u16>) -> &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<usize>) -> &mut Self {
+    pub fn precision(&mut self, precision: Option<u16>) -> &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<usize> {
+    pub const fn get_width(&self) -> Option<u16> {
         self.width
     }
     /// Returns the current precision.
     #[unstable(feature = "formatting_options", issue = "118117")]
-    pub const fn get_precision(&self) -> Option<usize> {
+    pub const fn get_precision(&self) -> Option<u16> {
         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<usize> {
+unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<u16> {
     match *cnt {
+        #[cfg(bootstrap)]
+        rt::Count::Is(n) => Some(n as u16),
+        #[cfg(not(bootstrap))]
         rt::Count::Is(n) => Some(n),
         rt::Count::Implied => None,
         rt::Count::Param(i) => {
             debug_assert!(i < args.len());
             // 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<usize>
 #[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)
@@ -1702,14 +1705,14 @@ impl<'a> Formatter<'a> {
         // string being formatted.
         let (s, char_count) = if let Some(max_char_count) = self.options.precision {
             let mut iter = s.char_indices();
-            let remaining = match iter.advance_by(max_char_count) {
+            let remaining = match iter.advance_by(usize::from(max_char_count)) {
                 Ok(()) => 0,
                 Err(remaining) => remaining.get(),
             };
             // SAFETY: The offset of `.char_indices()` is guaranteed to be
             // in-bounds and between character boundaries.
             let truncated = unsafe { s.get_unchecked(..iter.offset()) };
-            (truncated, max_char_count - remaining)
+            (truncated, usize::from(max_char_count) - remaining)
         } else {
             // Use the optimized char counting algorithm for the full string.
             (s, s.chars().count())
@@ -1717,11 +1720,11 @@ impl<'a> Formatter<'a> {
 
         // The `width` field is more of a minimum width parameter at this point.
         if let Some(width) = self.options.width
-            && char_count < width
+            && char_count < usize::from(width)
         {
             // If we're under the minimum width, then fill up the minimum width
             // with the specified string + some alignment.
-            let post_padding = self.padding(width - char_count, Alignment::Left)?;
+            let post_padding = self.padding(width - char_count as u16, Alignment::Left)?;
             self.buf.write_str(s)?;
             post_padding.write(self)
         } else {
@@ -1737,7 +1740,7 @@ impl<'a> Formatter<'a> {
     /// thing that is being padded.
     pub(crate) fn padding(
         &mut self,
-        padding: usize,
+        padding: u16,
         default: Alignment,
     ) -> result::Result<PostPadding, Error> {
         let align = self.align().unwrap_or(default);
@@ -1777,19 +1780,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)?;
@@ -2021,7 +2024,7 @@ impl<'a> Formatter<'a> {
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn width(&self) -> Option<usize> {
-        self.options.width
+        self.options.width.map(|x| x as usize)
     }
 
     /// Returns the optionally specified precision for numeric types.
@@ -2052,7 +2055,7 @@ impl<'a> Formatter<'a> {
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn precision(&self) -> Option<usize> {
-        self.options.precision
+        self.options.precision.map(|x| x as usize)
     }
 
     /// Determines if the `+` flag was specified.
@@ -2792,7 +2795,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 85d089a0790..cb908adc1cb 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<usize> {
+    pub(super) const fn as_u16(&self) -> Option<u16> {
         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 8b211b442ea..37b5c1076fa 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -1377,7 +1377,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 6041923117c..6e74cc91c5b 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<F>(mut f_: F)