Skip to content

Clean up "const" situation in format_args!(). #140544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/check_consts/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ symbols! {
Arc,
ArcWeak,
Argument,
ArgumentMethods,
ArrayIntoIter,
AsMut,
AsRef,
Expand Down Expand Up @@ -249,6 +248,7 @@ symbols! {
Error,
File,
FileType,
FmtArgumentsNew,
Fn,
FnMut,
FnOnce,
Expand Down
35 changes: 0 additions & 35 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
89 changes: 69 additions & 20 deletions library/core/src/fmt/rt.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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] {
[]
}
}
Expand All @@ -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 }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
2 changes: 1 addition & 1 deletion tests/pretty/issue-4264.pp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
((::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);
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/consts/const-eval/format.stderr
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
Loading