diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 61f850c2fc166..fab2c0dfa4014 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -49,7 +49,7 @@ fn update_limit( let error_str = match e.kind() { IntErrorKind::PosOverflow => "`limit` is too large", IntErrorKind::Empty => "`limit` must be a non-negative integer", - IntErrorKind::InvalidDigit => "not a valid integer", + IntErrorKind::InvalidDigit(_) => "not a valid integer", IntErrorKind::NegOverflow => { bug!("`limit` should never negatively overflow") } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f28c4673cc033..b89d86d7885b9 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1588,7 +1588,7 @@ pub trait Iterator { /// This will print: /// /// ```text - /// Parsing error: invalid digit found in string + /// Parsing error: invalid digit found at index 0 /// Sum: 3 /// ``` #[inline] diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index e2cc8faf8547d..441375fe62a50 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -95,14 +95,14 @@ pub enum IntErrorKind { /// /// Among other causes, this variant will be constructed when parsing an empty string. Empty, - /// Contains an invalid digit in its context. + /// Contains an invalid digit at the index provided. /// /// Among other causes, this variant will be constructed when parsing a string that /// contains a non-ASCII char. /// /// This variant is also constructed when a `+` or `-` is misplaced within a string /// either on its own or in the middle of a number. - InvalidDigit, + InvalidDigit(usize), /// Integer is too large to store in target integer type. PosOverflow, /// Integer is too small to store in target integer type. @@ -135,7 +135,7 @@ impl ParseIntError { pub fn __description(&self) -> &str { match self.kind { IntErrorKind::Empty => "cannot parse integer from empty string", - IntErrorKind::InvalidDigit => "invalid digit found in string", + IntErrorKind::InvalidDigit(_) => "invalid digit found in string", IntErrorKind::PosOverflow => "number too large to fit in target type", IntErrorKind::NegOverflow => "number too small to fit in target type", IntErrorKind::Zero => "number would be zero for non-zero type", @@ -146,6 +146,11 @@ impl ParseIntError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseIntError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.__description().fmt(f) + match self.kind { + IntErrorKind::InvalidDigit(i) => { + write!(f, "invalid digit found at index {}", i) + } + _ => self.__description().fmt(f), + } } } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index f0bd976ba83d5..a6570c27a85a1 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -824,34 +824,39 @@ fn from_str_radix(src: &str, radix: u32) -> Result T::min_value(); // all valid digits are ascii, so we will just iterate over the utf8 bytes // and cast them to chars. .to_digit() will safely return None for anything // other than a valid ascii digit for the given radix, including the first-byte // of multi-byte sequences - let src = src.as_bytes(); - - let (is_positive, digits) = match src[0] { - b'+' | b'-' if src[1..].is_empty() => { - return Err(PIE { kind: InvalidDigit }); + let mut src = src.as_bytes().iter().enumerate().peekable(); + + let first_digit = src.peek().ok_or(PIE { kind: Empty })?.1; + + let (is_positive, digits) = match first_digit { + b'+' | b'-' => { + src.next(); + if src.peek().is_none() { + return Err(PIE { kind: InvalidDigit(0) }); + } else { + match first_digit { + b'+' => (true, src), + b'-' if is_signed_ty => (false, src), + _ => return Err(PIE { kind: InvalidDigit(0) }), + } + } } - b'+' => (true, &src[1..]), - b'-' if is_signed_ty => (false, &src[1..]), _ => (true, src), }; let mut result = T::from_u32(0); if is_positive { // The number is positive - for &c in digits { + for (index, &c) in digits { let x = match (c as char).to_digit(radix) { Some(x) => x, - None => return Err(PIE { kind: InvalidDigit }), + None => return Err(PIE { kind: InvalidDigit(index) }), }; result = match result.checked_mul(radix) { Some(result) => result, @@ -864,10 +869,10 @@ fn from_str_radix(src: &str, radix: u32) -> Result x, - None => return Err(PIE { kind: InvalidDigit }), + None => return Err(PIE { kind: InvalidDigit(index) }), }; result = match result.checked_mul(radix) { Some(result) => result, diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index c2c08522d0cae..18eb035d54a0d 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -134,7 +134,7 @@ fn test_from_str() { assert_eq!("0".parse::().err().map(|e| e.kind().clone()), Some(IntErrorKind::Zero)); assert_eq!( "-1".parse::().err().map(|e| e.kind().clone()), - Some(IntErrorKind::InvalidDigit) + Some(IntErrorKind::InvalidDigit(0)) ); assert_eq!( "-129".parse::().err().map(|e| e.kind().clone()), diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index e66a73ac1289b..6901e26570a86 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -124,14 +124,14 @@ fn test_leading_plus() { #[test] fn test_invalid() { - test_parse::("--129", Err(IntErrorKind::InvalidDigit)); - test_parse::("++129", Err(IntErrorKind::InvalidDigit)); - test_parse::("Съешь", Err(IntErrorKind::InvalidDigit)); - test_parse::("123Hello", Err(IntErrorKind::InvalidDigit)); - test_parse::("--", Err(IntErrorKind::InvalidDigit)); - test_parse::("-", Err(IntErrorKind::InvalidDigit)); - test_parse::("+", Err(IntErrorKind::InvalidDigit)); - test_parse::("-1", Err(IntErrorKind::InvalidDigit)); + test_parse::("--129", Err(IntErrorKind::InvalidDigit(1))); + test_parse::("++129", Err(IntErrorKind::InvalidDigit(1))); + test_parse::("Съешь", Err(IntErrorKind::InvalidDigit(0))); + test_parse::("123Hello", Err(IntErrorKind::InvalidDigit(3))); + test_parse::("--", Err(IntErrorKind::InvalidDigit(1))); + test_parse::("-", Err(IntErrorKind::InvalidDigit(0))); + test_parse::("+", Err(IntErrorKind::InvalidDigit(0))); + test_parse::("-1", Err(IntErrorKind::InvalidDigit(0))); } #[test] diff --git a/src/test/ui/feature-gates/unstable-attribute-allow-issue-0.stderr b/src/test/ui/feature-gates/unstable-attribute-allow-issue-0.stderr index 4ed42101af8e6..eca616ad86277 100644 --- a/src/test/ui/feature-gates/unstable-attribute-allow-issue-0.stderr +++ b/src/test/ui/feature-gates/unstable-attribute-allow-issue-0.stderr @@ -12,7 +12,7 @@ error[E0545]: `issue` must be a non-zero numeric string or "none" LL | #[unstable(feature = "unstable_test_feature", issue = "something")] | ^^^^^^^^----------- | | - | invalid digit found in string + | invalid digit found at index 0 error: aborting due to 2 previous errors diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr index bd7b88da1584d..57ac2f88d9feb 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr @@ -16,7 +16,7 @@ error[E0545]: `issue` must be a non-zero numeric string or "none" LL | #[unstable(feature = "a", issue = "no")] | ^^^^^^^^---- | | - | invalid digit found in string + | invalid digit found at index 0 error: aborting due to 3 previous errors