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:
@@ -352,7 +352,7 @@ fn build_error_for_const_call<'tcx>(
|
||||
);
|
||||
err
|
||||
}
|
||||
_ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => {
|
||||
_ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => {
|
||||
ccx.dcx().create_err(errors::NonConstFmtMacroCall {
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
|
||||
@@ -174,7 +174,6 @@ symbols! {
|
||||
Arc,
|
||||
ArcWeak,
|
||||
Argument,
|
||||
ArgumentMethods,
|
||||
ArrayIntoIter,
|
||||
AsMut,
|
||||
AsRef,
|
||||
@@ -249,6 +248,7 @@ symbols! {
|
||||
Error,
|
||||
File,
|
||||
FileType,
|
||||
FmtArgumentsNew,
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
StorageDead(_18);
|
||||
_16 = &_17;
|
||||
_15 = &(*_16);
|
||||
_11 = Arguments::<'_>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable];
|
||||
_11 = core::fmt::rt::<impl Arguments<'_>>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
|
||||
@@ -34,7 +34,7 @@ fn bar() ({
|
||||
((::alloc::fmt::format as
|
||||
for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
|
||||
as
|
||||
fn(&[&'static str; 1]) -> Arguments<'_> {Arguments::<'_>::new_const::<1>})((&([("test"
|
||||
fn(&[&'static str; 1]) -> Arguments<'_> {core::fmt::rt::<impl Arguments<'_>>::new_const::<1>})((&([("test"
|
||||
as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
|
||||
as String)
|
||||
} as String)) as String);
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
error[E0015]: cannot call non-const formatting macro in constant functions
|
||||
--> $DIR/format.rs:2:13
|
||||
--> $DIR/format.rs:2:5
|
||||
|
|
||||
LL | panic!("{:?}", 0);
|
||||
| ^^^^
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: cannot call non-const formatting macro in constant functions
|
||||
--> $DIR/format.rs:7:15
|
||||
--> $DIR/format.rs:7:5
|
||||
|
|
||||
LL | println!("{:?}", 0);
|
||||
| ^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
Reference in New Issue
Block a user