Rollup merge of #124941 - Skgland:stabilize-const-int-from-str, r=dtolnay
Stabilize const `{integer}::from_str_radix` i.e. `const_int_from_str` This PR stabilizes the feature `const_int_from_str`. - ACP Issue: rust-lang/libs-team#74 - Implementation PR: rust-lang/rust#99322 - Part of Tracking Issue: rust-lang/rust#59133 API Change Diff: ```diff impl {integer} { - pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError>; + pub const fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError>; } impl ParseIntError { - pub fn kind(&self) -> &IntErrorKind; + pub const fn kind(&self) -> &IntErrorKind; } ``` This makes it easier to parse integers at compile-time, e.g. the example from the Tracking Issue: ```rust env!("SOMETHING").parse::<usize>().unwrap() ``` could now be achived with ```rust match usize::from_str_radix(env!("SOMETHING"), 10) { Ok(val) => val, Err(err) => panic!("Invalid value for SOMETHING environment variable."), } ``` rather than having to depend on a library that implements or manually implement the parsing at compile-time. --- Checklist based on [Libs Stabilization Guide - When there's const involved](https://std-dev-guide.rust-lang.org/development/stabilization.html#when-theres-const-involved) I am treating this as a [partial stabilization](https://std-dev-guide.rust-lang.org/development/stabilization.html#partial-stabilizations) as it shares a tracking issue (and is rather small), so directly opening the partial stabilization PR for the subset (feature `const_int_from_str`) being stabilized. - [x] ping Constant Evaluation WG - [x] no unsafe involved - [x] no `#[allow_internal_unstable]` - [ ] usage of `intrinsic::const_eval_select` rust-lang/rust#124625 in `from_str_radix_assert` to change the error message between compile-time and run-time - [ ] [rust-labg/libs-api FCP](https://github.com/rust-lang/rust/pull/124941#issuecomment-2207021921)
This commit is contained in:
commit
86721a4c90
@ -127,7 +127,6 @@
|
|||||||
#![feature(const_hash)]
|
#![feature(const_hash)]
|
||||||
#![feature(const_heap)]
|
#![feature(const_heap)]
|
||||||
#![feature(const_index_range_slice_index)]
|
#![feature(const_index_range_slice_index)]
|
||||||
#![feature(const_int_from_str)]
|
|
||||||
#![feature(const_intrinsic_copy)]
|
#![feature(const_intrinsic_copy)]
|
||||||
#![feature(const_intrinsic_forget)]
|
#![feature(const_intrinsic_forget)]
|
||||||
#![feature(const_ipv4)]
|
#![feature(const_ipv4)]
|
||||||
|
@ -113,7 +113,7 @@ pub enum IntErrorKind {
|
|||||||
impl ParseIntError {
|
impl ParseIntError {
|
||||||
/// Outputs the detailed cause of parsing an integer failing.
|
/// Outputs the detailed cause of parsing an integer failing.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
|
#[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[stable(feature = "int_error_matching", since = "1.55.0")]
|
#[stable(feature = "int_error_matching", since = "1.55.0")]
|
||||||
pub const fn kind(&self) -> &IntErrorKind {
|
pub const fn kind(&self) -> &IntErrorKind {
|
||||||
&self.kind
|
&self.kind
|
||||||
|
@ -1386,6 +1386,7 @@ fn from_str(src: &str) -> Result<Self, ParseIntError> {
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[unstable(issue = "none", feature = "std_internals")]
|
#[unstable(issue = "none", feature = "std_internals")]
|
||||||
|
#[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
|
pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
|
||||||
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
|
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
|
||||||
}
|
}
|
||||||
@ -1435,7 +1436,7 @@ impl $int_ty {
|
|||||||
#[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")]
|
#[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")]
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
|
#[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> {
|
pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> {
|
||||||
use self::IntErrorKind::*;
|
use self::IntErrorKind::*;
|
||||||
use self::ParseIntError as PIE;
|
use self::ParseIntError as PIE;
|
||||||
@ -1565,7 +1566,7 @@ impl $size {
|
|||||||
#[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")]
|
#[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")]
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")]
|
#[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> {
|
pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> {
|
||||||
match <$t>::from_str_radix(src, radix) {
|
match <$t>::from_str_radix(src, radix) {
|
||||||
Ok(x) => Ok(x as $size),
|
Ok(x) => Ok(x as $size),
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#![feature(const_hash)]
|
#![feature(const_hash)]
|
||||||
#![feature(const_heap)]
|
#![feature(const_heap)]
|
||||||
#![feature(const_intrinsic_copy)]
|
#![feature(const_intrinsic_copy)]
|
||||||
#![feature(const_int_from_str)]
|
|
||||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||||
#![feature(const_nonnull_new)]
|
#![feature(const_nonnull_new)]
|
||||||
#![feature(const_pointer_is_aligned)]
|
#![feature(const_pointer_is_aligned)]
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![feature(const_int_from_str)]
|
|
||||||
#![warn(clippy::from_str_radix_10)]
|
#![warn(clippy::from_str_radix_10)]
|
||||||
|
|
||||||
mod some_mod {
|
mod some_mod {
|
||||||
@ -61,7 +60,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn issue_12732() {
|
// https://github.com/rust-lang/rust-clippy/issues/12731
|
||||||
|
fn issue_12731() {
|
||||||
const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10);
|
const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10);
|
||||||
const B: () = {
|
const B: () = {
|
||||||
let _ = u32::from_str_radix("123", 10);
|
let _ = u32::from_str_radix("123", 10);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![feature(const_int_from_str)]
|
|
||||||
#![warn(clippy::from_str_radix_10)]
|
#![warn(clippy::from_str_radix_10)]
|
||||||
|
|
||||||
mod some_mod {
|
mod some_mod {
|
||||||
@ -61,7 +60,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn issue_12732() {
|
// https://github.com/rust-lang/rust-clippy/issues/12731
|
||||||
|
fn issue_12731() {
|
||||||
const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10);
|
const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10);
|
||||||
const B: () = {
|
const B: () = {
|
||||||
let _ = u32::from_str_radix("123", 10);
|
let _ = u32::from_str_radix("123", 10);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
--> tests/ui/from_str_radix_10.rs:29:5
|
--> tests/ui/from_str_radix_10.rs:28:5
|
||||||
|
|
|
|
||||||
LL | u32::from_str_radix("30", 10)?;
|
LL | u32::from_str_radix("30", 10)?;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::<u32>()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::<u32>()`
|
||||||
@ -8,43 +8,43 @@ LL | u32::from_str_radix("30", 10)?;
|
|||||||
= help: to override `-D warnings` add `#[allow(clippy::from_str_radix_10)]`
|
= help: to override `-D warnings` add `#[allow(clippy::from_str_radix_10)]`
|
||||||
|
|
||||||
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
--> tests/ui/from_str_radix_10.rs:32:5
|
--> tests/ui/from_str_radix_10.rs:31:5
|
||||||
|
|
|
|
||||||
LL | i64::from_str_radix("24", 10)?;
|
LL | i64::from_str_radix("24", 10)?;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::<i64>()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::<i64>()`
|
||||||
|
|
||||||
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
--> tests/ui/from_str_radix_10.rs:34:5
|
--> tests/ui/from_str_radix_10.rs:33:5
|
||||||
|
|
|
|
||||||
LL | isize::from_str_radix("100", 10)?;
|
LL | isize::from_str_radix("100", 10)?;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::<isize>()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::<isize>()`
|
||||||
|
|
||||||
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
--> tests/ui/from_str_radix_10.rs:36:5
|
--> tests/ui/from_str_radix_10.rs:35:5
|
||||||
|
|
|
|
||||||
LL | u8::from_str_radix("7", 10)?;
|
LL | u8::from_str_radix("7", 10)?;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::<u8>()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::<u8>()`
|
||||||
|
|
||||||
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
--> tests/ui/from_str_radix_10.rs:38:5
|
--> tests/ui/from_str_radix_10.rs:37:5
|
||||||
|
|
|
|
||||||
LL | u16::from_str_radix(&("10".to_owned() + "5"), 10)?;
|
LL | u16::from_str_radix(&("10".to_owned() + "5"), 10)?;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::<u16>()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::<u16>()`
|
||||||
|
|
||||||
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
--> tests/ui/from_str_radix_10.rs:40:5
|
--> tests/ui/from_str_radix_10.rs:39:5
|
||||||
|
|
|
|
||||||
LL | i128::from_str_radix(Test + Test, 10)?;
|
LL | i128::from_str_radix(Test + Test, 10)?;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::<i128>()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::<i128>()`
|
||||||
|
|
||||||
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
--> tests/ui/from_str_radix_10.rs:44:5
|
--> tests/ui/from_str_radix_10.rs:43:5
|
||||||
|
|
|
|
||||||
LL | i32::from_str_radix(string, 10)?;
|
LL | i32::from_str_radix(string, 10)?;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::<i32>()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::<i32>()`
|
||||||
|
|
||||||
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
--> tests/ui/from_str_radix_10.rs:48:5
|
--> tests/ui/from_str_radix_10.rs:47:5
|
||||||
|
|
|
|
||||||
LL | i32::from_str_radix(&stringier, 10)?;
|
LL | i32::from_str_radix(&stringier, 10)?;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()`
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(const_int_from_str)]
|
|
||||||
|
|
||||||
const _OK: () = match i32::from_str_radix("-1234", 10) {
|
const _OK: () = match i32::from_str_radix("-1234", 10) {
|
||||||
Ok(x) => assert!(x == -1234),
|
Ok(x) => assert!(x == -1234),
|
||||||
Err(_) => panic!(),
|
Err(_) => panic!(),
|
||||||
|
@ -6,7 +6,7 @@ error[E0080]: evaluation of constant value failed
|
|||||||
note: inside `core::num::<impl u64>::from_str_radix`
|
note: inside `core::num::<impl u64>::from_str_radix`
|
||||||
--> $SRC_DIR/core/src/num/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/num/mod.rs:LL:COL
|
||||||
note: inside `_TOO_LOW`
|
note: inside `_TOO_LOW`
|
||||||
--> $DIR/parse_ints.rs:7:24
|
--> $DIR/parse_ints.rs:5:24
|
||||||
|
|
|
|
||||||
LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); };
|
LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed
|
|||||||
note: inside `core::num::<impl u64>::from_str_radix`
|
note: inside `core::num::<impl u64>::from_str_radix`
|
||||||
--> $SRC_DIR/core/src/num/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/num/mod.rs:LL:COL
|
||||||
note: inside `_TOO_HIGH`
|
note: inside `_TOO_HIGH`
|
||||||
--> $DIR/parse_ints.rs:8:25
|
--> $DIR/parse_ints.rs:6:25
|
||||||
|
|
|
|
||||||
LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); };
|
LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Loading…
Reference in New Issue
Block a user