about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-18 08:44:01 +0000
committerbors <bors@rust-lang.org>2024-05-18 08:44:01 +0000
commit1c90b9fe6eac122b4d3965913b3615f47751a4d3 (patch)
treef18822d80aba5f4a47965ce7ac9a3fe6d0279269 /compiler
parent36c0a6d40fb6aae9c450305085d64e2ba55c6c58 (diff)
parent582fd1fb539ddea199dbc238946b00465a20620e (diff)
downloadrust-1c90b9fe6eac122b4d3965913b3615f47751a4d3.tar.gz
rust-1c90b9fe6eac122b4d3965913b3615f47751a4d3.zip
Auto merge of #125004 - pymongo:issue-125002, r=estebank
Fix println! ICE when parsing percent prefix number

This PR fixes #125002 ICE occurring, for example, with `println!("%100000", 1)` or `println!("%    100000", 1)`.

## Test Case/Change Explanation

The return type of `Num::from_str` has been changed to `Option<Self>` to handle errors when parsing large integers fails.

1. The first `println!` in the test case covers the change of the first `Num::from_str` usage in `format_foreign.rs:426`.
2. The second `println!` in the test case covers the change of the second `Num::from_str` usage in line 460.
3. The 3rd to 5th `Num::from_str` usages behave the same as before.

The 3rd usage would cause an ICE when `num > u16::MAX` in the previous version, but this commit does not include a fix for the ICE in `println!("{:100000$}")`. I think we need to emit an error in the compiler and have more discussion in another issue/PR.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs24
1 files changed, 15 insertions, 9 deletions
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 307e582d65e..bc2c6def68a 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -263,13 +263,13 @@ pub(crate) mod printf {
     }
 
     impl Num {
-        fn from_str(s: &str, arg: Option<&str>) -> Self {
+        fn from_str(s: &str, arg: Option<&str>) -> Option<Self> {
             if let Some(arg) = arg {
-                Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{arg:?}`")))
+                arg.parse().ok().map(|arg| Num::Arg(arg))
             } else if s == "*" {
-                Num::Next
+                Some(Num::Next)
             } else {
-                Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{s:?}`")))
+                s.parse().ok().map(|num| Num::Num(num))
             }
         }
 
@@ -421,7 +421,10 @@ pub(crate) mod printf {
                             state = Prec;
                             parameter = None;
                             flags = "";
-                            width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                            width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
+                            if width.is_none() {
+                                return fallback();
+                            }
                             move_to!(end);
                         }
                         // It's invalid, is what it is.
@@ -452,7 +455,10 @@ pub(crate) mod printf {
                 '1'..='9' => {
                     let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Prec;
-                    width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                    width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
+                    if width.is_none() {
+                        return fallback();
+                    }
                     move_to!(end);
                 }
                 _ => {
@@ -468,7 +474,7 @@ pub(crate) mod printf {
             match end.next_cp() {
                 Some(('$', end2)) => {
                     state = Prec;
-                    width = Some(Num::from_str("", Some(at.slice_between(end).unwrap())));
+                    width = Num::from_str("", at.slice_between(end));
                     move_to!(end2);
                 }
                 _ => {
@@ -500,7 +506,7 @@ pub(crate) mod printf {
                     match end.next_cp() {
                         Some(('$', end2)) => {
                             state = Length;
-                            precision = Some(Num::from_str("*", next.slice_between(end)));
+                            precision = Num::from_str("*", next.slice_between(end));
                             move_to!(end2);
                         }
                         _ => {
@@ -513,7 +519,7 @@ pub(crate) mod printf {
                 '0'..='9' => {
                     let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Length;
-                    precision = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                    precision = at.slice_between(end).and_then(|num| Num::from_str(num, None));
                     move_to!(end);
                 }
                 _ => return fallback(),