Rollup merge of #140544 - m-ou-se:format-args-const-cleanup, r=fee1-dead
Clean up "const" situation in format_args!().
This cleans up the "const" situation in the format_args!() expansion/lowering.
Rather than marking the Argument::new_display etc. functions as non-const, this marks the Arguments::new_v1 functions as non-const.
Example expansion/lowering of format_args!() in const:
```rust
// Error: cannot call non-const formatting macro in constant functions
const {
fmt::Arguments::new_v1( // Now the error is produced here.
&["Hello, ", "!\n"],
&[
fmt::Argument::new_display(&world) // The error used to be produced here.
],
)
}
```
This commit is contained in:
@@ -622,44 +622,9 @@ pub struct Arguments<'a> {
|
||||
args: &'a [rt::Argument<'a>],
|
||||
}
|
||||
|
||||
/// Used by the format_args!() macro to create a fmt::Arguments object.
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "fmt_internals", issue = "none")]
|
||||
impl<'a> Arguments<'a> {
|
||||
#[inline]
|
||||
pub const fn new_const<const N: usize>(pieces: &'a [&'static str; N]) -> Self {
|
||||
const { assert!(N <= 1) };
|
||||
Arguments { pieces, fmt: None, args: &[] }
|
||||
}
|
||||
|
||||
/// When using the format_args!() macro, this function is used to generate the
|
||||
/// Arguments structure.
|
||||
#[inline]
|
||||
pub const fn new_v1<const P: usize, const A: usize>(
|
||||
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 }
|
||||
}
|
||||
|
||||
/// 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 }
|
||||
}
|
||||
|
||||
/// Estimates the length of the formatted text.
|
||||
///
|
||||
/// This is intended to be used for setting initial `String` capacity
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#![allow(missing_debug_implementations)]
|
||||
#![unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
|
||||
|
||||
//! These are the lang items used by format_args!().
|
||||
//! All types and methods in this file are used by the compiler in
|
||||
//! the expansion/lowering of format_args!().
|
||||
//!
|
||||
//! Do not modify them without understanding the consequences for the format_args!() macro.
|
||||
|
||||
use super::*;
|
||||
use crate::hint::unreachable_unchecked;
|
||||
@@ -110,46 +113,45 @@ macro_rules! argument_new {
|
||||
};
|
||||
}
|
||||
|
||||
#[rustc_diagnostic_item = "ArgumentMethods"]
|
||||
impl Argument<'_> {
|
||||
#[inline]
|
||||
pub fn new_display<T: Display>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_display<T: Display>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as Display>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as Debug>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, |_: &T, _| Ok(()))
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as Octal>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as LowerHex>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as UpperHex>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as Pointer>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as Binary>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as LowerExp>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
|
||||
pub const fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
|
||||
argument_new!(T, x, <T as UpperExp>::fmt)
|
||||
}
|
||||
#[inline]
|
||||
@@ -200,15 +202,8 @@ impl Argument<'_> {
|
||||
/// let f = format_args!("{}", "a");
|
||||
/// println!("{f}");
|
||||
/// ```
|
||||
///
|
||||
/// This function should _not_ be const, to make sure we don't accept
|
||||
/// format_args!() and panic!() with arguments in const, even when not evaluated:
|
||||
///
|
||||
/// ```compile_fail,E0015
|
||||
/// const _: () = if false { panic!("a {}", "a") };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn none() -> [Self; 0] {
|
||||
pub const fn none() -> [Self; 0] {
|
||||
[]
|
||||
}
|
||||
}
|
||||
@@ -229,3 +224,57 @@ impl UnsafeArg {
|
||||
Self { _private: () }
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by the format_args!() macro to create a fmt::Arguments object.
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "fmt_internals", issue = "none")]
|
||||
#[rustc_diagnostic_item = "FmtArgumentsNew"]
|
||||
impl<'a> Arguments<'a> {
|
||||
#[inline]
|
||||
pub const fn new_const<const N: usize>(pieces: &'a [&'static str; N]) -> Self {
|
||||
const { assert!(N <= 1) };
|
||||
Arguments { pieces, fmt: None, args: &[] }
|
||||
}
|
||||
|
||||
/// When using the format_args!() macro, this function is used to generate the
|
||||
/// Arguments structure.
|
||||
///
|
||||
/// This function should _not_ be const, to make sure we don't accept
|
||||
/// format_args!() and panic!() with arguments in const, even when not evaluated:
|
||||
///
|
||||
/// ```compile_fail,E0015
|
||||
/// const _: () = if false { panic!("a {}", "a") };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new_v1<const P: usize, const A: usize>(
|
||||
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 }
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
///
|
||||
/// This function should _not_ be const, to make sure we don't accept
|
||||
/// format_args!() and panic!() with arguments in const, even when not evaluated:
|
||||
///
|
||||
/// ```compile_fail,E0015
|
||||
/// const _: () = if false { panic!("a {:1}", "a") };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub 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 }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user