summaryrefslogtreecommitdiffstats
path: root/library/core/src/fmt
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /library/core/src/fmt
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core/src/fmt')
-rw-r--r--library/core/src/fmt/builders.rs14
-rw-r--r--library/core/src/fmt/float.rs12
-rw-r--r--library/core/src/fmt/mod.rs416
-rw-r--r--library/core/src/fmt/num.rs15
-rw-r--r--library/core/src/fmt/rt.rs212
-rw-r--r--library/core/src/fmt/rt/v1.rs63
6 files changed, 371 insertions, 361 deletions
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index 7da49b04a..36f49d51c 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -60,7 +60,7 @@ impl fmt::Write for PadAdapter<'_, '_> {
/// }
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_struct("Foo")
/// .field("bar", &self.bar)
/// .field("baz", &self.baz)
@@ -109,14 +109,14 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
/// .field("bar", &self.bar) // We add `bar` field.
/// .field("another", &self.another) // We add `another` field.
/// // We even add a field which doesn't exist (because why not?).
- /// .field("not_existing_field", &1)
+ /// .field("nonexistent_field", &1)
/// .finish() // We're good to go!
/// }
/// }
///
/// assert_eq!(
/// format!("{:?}", Bar { bar: 10, another: "Hello World".to_string() }),
- /// "Bar { bar: 10, another: \"Hello World\", not_existing_field: 1 }",
+ /// "Bar { bar: 10, another: \"Hello World\", nonexistent_field: 1 }",
/// );
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
@@ -249,7 +249,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
/// struct Foo(i32, String);
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_tuple("Foo")
/// .field(&self.0)
/// .field(&self.1)
@@ -418,7 +418,7 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_set().entries(self.0.iter()).finish()
/// }
/// }
@@ -548,7 +548,7 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_list().entries(self.0.iter()).finish()
/// }
/// }
@@ -678,7 +678,7 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
/// struct Foo(Vec<(String, i32)>);
///
/// impl fmt::Debug for Foo {
-/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
/// }
/// }
diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs
index 89d5fac30..3bbf5d877 100644
--- a/library/core/src/fmt/float.rs
+++ b/library/core/src/fmt/float.rs
@@ -45,7 +45,8 @@ where
&mut buf,
&mut parts,
);
- fmt.pad_formatted_parts(&formatted)
+ // SAFETY: `to_exact_fixed_str` and `format_exact` produce only ASCII characters.
+ unsafe { fmt.pad_formatted_parts(&formatted) }
}
// Don't inline this so callers that call both this and the above won't wind
@@ -71,7 +72,8 @@ where
&mut buf,
&mut parts,
);
- fmt.pad_formatted_parts(&formatted)
+ // SAFETY: `to_shortest_str` and `format_shortest` produce only ASCII characters.
+ unsafe { fmt.pad_formatted_parts(&formatted) }
}
fn float_to_decimal_display<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
@@ -116,7 +118,8 @@ where
&mut buf,
&mut parts,
);
- fmt.pad_formatted_parts(&formatted)
+ // SAFETY: `to_exact_exp_str` and `format_exact` produce only ASCII characters.
+ unsafe { fmt.pad_formatted_parts(&formatted) }
}
// Don't inline this so callers that call both this and the above won't wind
@@ -143,7 +146,8 @@ where
&mut buf,
&mut parts,
);
- fmt.pad_formatted_parts(&formatted)
+ // SAFETY: `to_shortest_exp_str` and `format_shortest` produce only ASCII characters.
+ unsafe { fmt.pad_formatted_parts(&formatted) }
}
// Common code of floating point LowerExp and UpperExp.
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index fcda097f0..1786b309c 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -18,6 +18,7 @@ mod float;
#[cfg(no_fp_fmt_parse)]
mod nofloat;
mod num;
+mod rt;
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Alignment")]
@@ -38,12 +39,6 @@ pub enum Alignment {
#[stable(feature = "debug_builders", since = "1.2.0")]
pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
-#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-#[doc(hidden)]
-pub mod rt {
- pub mod v1;
-}
-
/// The type returned by formatter methods.
///
/// # Examples
@@ -227,7 +222,7 @@ impl<W: Write + ?Sized> Write for &mut W {
pub struct Formatter<'a> {
flags: u32,
fill: char,
- align: rt::v1::Alignment,
+ align: rt::Alignment,
width: Option<usize>,
precision: Option<usize>,
@@ -248,7 +243,7 @@ impl<'a> Formatter<'a> {
Formatter {
flags: 0,
fill: ' ',
- align: rt::v1::Alignment::Unknown,
+ align: rt::Alignment::Unknown,
width: None,
precision: None,
buf,
@@ -256,145 +251,48 @@ impl<'a> Formatter<'a> {
}
}
-// NB. Argument is essentially an optimized partially applied formatting function,
-// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
-
-extern "C" {
- type Opaque;
-}
-
-/// This struct represents the generic "argument" which is taken by the Xprintf
-/// family of functions. It contains a function to format the given value. At
-/// compile time it is ensured that the function and the value have the correct
-/// types, and then this struct is used to canonicalize arguments to one type.
-#[lang = "format_argument"]
+/// This structure represents a safely precompiled version of a format string
+/// and its arguments. This cannot be generated at runtime because it cannot
+/// safely be done, so no constructors are given and the fields are private
+/// to prevent modification.
+///
+/// The [`format_args!`] macro will safely create an instance of this structure.
+/// The macro validates the format string at compile-time so usage of the
+/// [`write()`] and [`format()`] functions can be safely performed.
+///
+/// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug`
+/// and `Display` contexts as seen below. The example also shows that `Debug`
+/// and `Display` format to the same thing: the interpolated format string
+/// in `format_args!`.
+///
+/// ```rust
+/// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2));
+/// let display = format!("{}", format_args!("{} foo {:?}", 1, 2));
+/// assert_eq!("1 foo 2", display);
+/// assert_eq!(display, debug);
+/// ```
+///
+/// [`format()`]: ../../std/fmt/fn.format.html
+#[lang = "format_arguments"]
+#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Copy, Clone)]
-#[allow(missing_debug_implementations)]
-#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-#[doc(hidden)]
-pub struct ArgumentV1<'a> {
- value: &'a Opaque,
- formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
-}
-
-/// This struct represents the unsafety of constructing an `Arguments`.
-/// It exists, rather than an unsafe function, in order to simplify the expansion
-/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
-#[lang = "format_unsafe_arg"]
-#[allow(missing_debug_implementations)]
-#[doc(hidden)]
-#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-pub struct UnsafeArg {
- _private: (),
-}
-
-impl UnsafeArg {
- /// See documentation where `UnsafeArg` is required to know when it is safe to
- /// create and use `UnsafeArg`.
- #[doc(hidden)]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[inline(always)]
- pub unsafe fn new() -> Self {
- Self { _private: () }
- }
-}
-
-// This guarantees a single stable value for the function pointer associated with
-// indices/counts in the formatting infrastructure.
-//
-// Note that a function defined as such would not be correct as functions are
-// always tagged unnamed_addr with the current lowering to LLVM IR, so their
-// address is not considered important to LLVM and as such the as_usize cast
-// could have been miscompiled. In practice, we never call as_usize on non-usize
-// containing data (as a matter of static generation of the formatting
-// arguments), so this is merely an additional check.
-//
-// We primarily want to ensure that the function pointer at `USIZE_MARKER` has
-// an address corresponding *only* to functions that also take `&usize` as their
-// first argument. The read_volatile here ensures that we can safely ready out a
-// usize from the passed reference and that this address does not point at a
-// non-usize taking function.
-#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| {
- // SAFETY: ptr is a reference
- let _v: usize = unsafe { crate::ptr::read_volatile(ptr) };
- loop {}
-};
-
-macro_rules! arg_new {
- ($f: ident, $t: ident) => {
- #[doc(hidden)]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[inline]
- pub fn $f<'b, T: $t>(x: &'b T) -> ArgumentV1<'_> {
- Self::new(x, $t::fmt)
- }
- };
-}
-
-#[rustc_diagnostic_item = "ArgumentV1Methods"]
-impl<'a> ArgumentV1<'a> {
- #[doc(hidden)]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[inline]
- pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
- // SAFETY: `mem::transmute(x)` is safe because
- // 1. `&'b T` keeps the lifetime it originated with `'b`
- // (so as to not have an unbounded lifetime)
- // 2. `&'b T` and `&'b Opaque` have the same memory layout
- // (when `T` is `Sized`, as it is here)
- // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
- // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
- // (as long as `T` is `Sized`)
- unsafe { ArgumentV1 { formatter: mem::transmute(f), value: mem::transmute(x) } }
- }
-
- arg_new!(new_display, Display);
- arg_new!(new_debug, Debug);
- arg_new!(new_octal, Octal);
- arg_new!(new_lower_hex, LowerHex);
- arg_new!(new_upper_hex, UpperHex);
- arg_new!(new_pointer, Pointer);
- arg_new!(new_binary, Binary);
- arg_new!(new_lower_exp, LowerExp);
- arg_new!(new_upper_exp, UpperExp);
+pub struct Arguments<'a> {
+ // Format string pieces to print.
+ pieces: &'a [&'static str],
- #[doc(hidden)]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
- ArgumentV1::new(x, USIZE_MARKER)
- }
-
- fn as_usize(&self) -> Option<usize> {
- // We are type punning a bit here: USIZE_MARKER only takes an &usize but
- // formatter takes an &Opaque. Rust understandably doesn't think we should compare
- // the function pointers if they don't have the same signature, so we cast to
- // usizes to tell it that we just want to compare addresses.
- if self.formatter as usize == USIZE_MARKER as usize {
- // SAFETY: The `formatter` field is only set to USIZE_MARKER if
- // the value is a usize, so this is safe
- Some(unsafe { *(self.value as *const _ as *const usize) })
- } else {
- None
- }
- }
-}
+ // Placeholder specs, or `None` if all specs are default (as in "{}{}").
+ fmt: Option<&'a [rt::Placeholder]>,
-// flags available in the v1 format of format_args
-#[derive(Copy, Clone)]
-enum FlagV1 {
- SignPlus,
- SignMinus,
- Alternate,
- SignAwareZeroPad,
- DebugLowerHex,
- DebugUpperHex,
+ // Dynamic arguments for interpolation, to be interleaved with string
+ // pieces. (Every argument is preceded by a string piece.)
+ 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> {
- #[doc(hidden)]
#[inline]
- #[unstable(feature = "fmt_internals", issue = "none")]
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
pub const fn new_const(pieces: &'a [&'static str]) -> Self {
if pieces.len() > 1 {
@@ -405,23 +303,8 @@ impl<'a> Arguments<'a> {
/// When using the format_args!() macro, this function is used to generate the
/// Arguments structure.
- #[cfg(not(bootstrap))]
- #[doc(hidden)]
#[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
- if pieces.len() < args.len() || pieces.len() > args.len() + 1 {
- panic!("invalid args");
- }
- Arguments { pieces, fmt: None, args }
- }
-
- #[cfg(bootstrap)]
- #[doc(hidden)]
- #[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
- pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
+ pub fn new_v1(pieces: &'a [&'static str], args: &'a [rt::Argument<'a>]) -> Arguments<'a> {
if pieces.len() < args.len() || pieces.len() > args.len() + 1 {
panic!("invalid args");
}
@@ -430,21 +313,17 @@ impl<'a> Arguments<'a> {
/// This function is used to specify nonstandard formatting parameters.
///
- /// An `UnsafeArg` is required because the following invariants must be held
+ /// 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::v1::Argument::position`] value within `fmt` must be a
- /// valid index of `args`.
- /// 3. Every [`rt::v1::Count::Param`] within `fmt` must contain a valid index of
- /// `args`.
- #[doc(hidden)]
+ /// 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]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
pub fn new_v1_formatted(
pieces: &'a [&'static str],
- args: &'a [ArgumentV1<'a>],
- fmt: &'a [rt::v1::Argument],
- _unsafe_arg: UnsafeArg,
+ args: &'a [rt::Argument<'a>],
+ fmt: &'a [rt::Placeholder],
+ _unsafe_arg: rt::UnsafeArg,
) -> Arguments<'a> {
Arguments { pieces, fmt: Some(fmt), args }
}
@@ -453,9 +332,7 @@ impl<'a> Arguments<'a> {
///
/// This is intended to be used for setting initial `String` capacity
/// when using `format!`. Note: this is neither the lower nor upper bound.
- #[doc(hidden)]
#[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
pub fn estimated_capacity(&self) -> usize {
let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum();
@@ -475,43 +352,6 @@ impl<'a> Arguments<'a> {
}
}
-/// This structure represents a safely precompiled version of a format string
-/// and its arguments. This cannot be generated at runtime because it cannot
-/// safely be done, so no constructors are given and the fields are private
-/// to prevent modification.
-///
-/// The [`format_args!`] macro will safely create an instance of this structure.
-/// The macro validates the format string at compile-time so usage of the
-/// [`write()`] and [`format()`] functions can be safely performed.
-///
-/// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug`
-/// and `Display` contexts as seen below. The example also shows that `Debug`
-/// and `Display` format to the same thing: the interpolated format string
-/// in `format_args!`.
-///
-/// ```rust
-/// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2));
-/// let display = format!("{}", format_args!("{} foo {:?}", 1, 2));
-/// assert_eq!("1 foo 2", display);
-/// assert_eq!(display, debug);
-/// ```
-///
-/// [`format()`]: ../../std/fmt/fn.format.html
-#[lang = "format_arguments"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Copy, Clone)]
-pub struct Arguments<'a> {
- // Format string pieces to print.
- pieces: &'a [&'static str],
-
- // Placeholder specs, or `None` if all specs are default (as in "{}{}").
- fmt: Option<&'a [rt::v1::Argument]>,
-
- // Dynamic arguments for interpolation, to be interleaved with string
- // pieces. (Every argument is preceded by a string piece.)
- args: &'a [ArgumentV1<'a>],
-}
-
impl<'a> Arguments<'a> {
/// Get the formatted string, if it has no arguments to be formatted at runtime.
///
@@ -541,7 +381,7 @@ impl<'a> Arguments<'a> {
///
/// fn write_str(_: &str) { /* ... */ }
///
- /// fn write_fmt(args: &Arguments) {
+ /// fn write_fmt(args: &Arguments<'_>) {
/// if let Some(s) = args.as_str() {
/// write_str(s)
/// } else {
@@ -1251,7 +1091,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
if !piece.is_empty() {
formatter.buf.write_str(*piece)?;
}
- (arg.formatter)(arg.value, &mut formatter)?;
+ arg.fmt(&mut formatter)?;
idx += 1;
}
}
@@ -1281,15 +1121,15 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
Ok(())
}
-unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result {
- fmt.fill = arg.format.fill;
- fmt.align = arg.format.align;
- fmt.flags = arg.format.flags;
+unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result {
+ fmt.fill = arg.fill;
+ fmt.align = arg.align;
+ fmt.flags = arg.flags;
// SAFETY: arg and args come from the same Arguments,
// which guarantees the indexes are always within bounds.
unsafe {
- fmt.width = getcount(args, &arg.format.width);
- fmt.precision = getcount(args, &arg.format.precision);
+ fmt.width = getcount(args, &arg.width);
+ fmt.precision = getcount(args, &arg.precision);
}
// Extract the correct argument
@@ -1299,14 +1139,14 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV
let value = unsafe { args.get_unchecked(arg.position) };
// Then actually do some printing
- (value.formatter)(value.value, fmt)
+ value.fmt(fmt)
}
-unsafe fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option<usize> {
+unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<usize> {
match *cnt {
- rt::v1::Count::Is(n) => Some(n),
- rt::v1::Count::Implied => None,
- rt::v1::Count::Param(i) => {
+ rt::Count::Is(n) => Some(n),
+ rt::Count::Implied => None,
+ rt::Count::Param(i) => {
debug_assert!(i < args.len());
// SAFETY: cnt and args come from the same Arguments,
// which guarantees this index is always within bounds.
@@ -1388,7 +1228,7 @@ impl<'a> Formatter<'a> {
/// }
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// // We need to remove "-" from the number output.
/// let tmp = self.nb.abs().to_string();
///
@@ -1449,9 +1289,9 @@ impl<'a> Formatter<'a> {
// is zero
Some(min) if self.sign_aware_zero_pad() => {
let old_fill = crate::mem::replace(&mut self.fill, '0');
- let old_align = crate::mem::replace(&mut self.align, rt::v1::Alignment::Right);
+ let old_align = crate::mem::replace(&mut self.align, rt::Alignment::Right);
write_prefix(self, sign, prefix)?;
- let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
+ let post_padding = self.padding(min - width, Alignment::Right)?;
self.buf.write_str(buf)?;
post_padding.write(self)?;
self.fill = old_fill;
@@ -1460,7 +1300,7 @@ impl<'a> Formatter<'a> {
}
// Otherwise, the sign and prefix goes after the padding
Some(min) => {
- let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
+ let post_padding = self.padding(min - width, Alignment::Right)?;
write_prefix(self, sign, prefix)?;
self.buf.write_str(buf)?;
post_padding.write(self)
@@ -1488,7 +1328,7 @@ impl<'a> Formatter<'a> {
/// struct Foo;
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// formatter.pad("Foo")
/// }
/// }
@@ -1535,7 +1375,7 @@ impl<'a> Formatter<'a> {
// If we're under both the maximum and the minimum width, then fill
// up the minimum width with the specified string + some alignment.
else {
- let align = rt::v1::Alignment::Left;
+ let align = Alignment::Left;
let post_padding = self.padding(width - chars_count, align)?;
self.buf.write_str(s)?;
post_padding.write(self)
@@ -1550,17 +1390,19 @@ impl<'a> Formatter<'a> {
pub(crate) fn padding(
&mut self,
padding: usize,
- default: rt::v1::Alignment,
+ default: Alignment,
) -> result::Result<PostPadding, Error> {
let align = match self.align {
- rt::v1::Alignment::Unknown => default,
- _ => self.align,
+ rt::Alignment::Unknown => default,
+ rt::Alignment::Left => Alignment::Left,
+ rt::Alignment::Right => Alignment::Right,
+ rt::Alignment::Center => Alignment::Center,
};
let (pre_pad, post_pad) = match align {
- rt::v1::Alignment::Left => (0, padding),
- rt::v1::Alignment::Right | rt::v1::Alignment::Unknown => (padding, 0),
- rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
+ Alignment::Left => (0, padding),
+ Alignment::Right => (padding, 0),
+ Alignment::Center => (padding / 2, (padding + 1) / 2),
};
for _ in 0..pre_pad {
@@ -1573,14 +1415,17 @@ impl<'a> Formatter<'a> {
/// Takes the formatted parts and applies the padding.
/// Assumes that the caller already has rendered the parts with required precision,
/// so that `self.precision` can be ignored.
- fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
+ ///
+ /// # Safety
+ ///
+ /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8.
+ unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
if let Some(mut width) = self.width {
// for the sign-aware zero padding, we render the sign first and
// behave as if we had no sign from the beginning.
let mut formatted = formatted.clone();
let old_fill = self.fill;
let old_align = self.align;
- let mut align = old_align;
if self.sign_aware_zero_pad() {
// a sign always goes first
let sign = formatted.sign;
@@ -1589,19 +1434,22 @@ impl<'a> Formatter<'a> {
// remove the sign from the formatted parts
formatted.sign = "";
width = width.saturating_sub(sign.len());
- align = rt::v1::Alignment::Right;
self.fill = '0';
- self.align = rt::v1::Alignment::Right;
+ self.align = rt::Alignment::Right;
}
// remaining parts go through the ordinary padding process.
let len = formatted.len();
let ret = if width <= len {
// no padding
- self.write_formatted_parts(&formatted)
+ // SAFETY: Per the precondition.
+ unsafe { self.write_formatted_parts(&formatted) }
} else {
- let post_padding = self.padding(width - len, align)?;
- self.write_formatted_parts(&formatted)?;
+ let post_padding = self.padding(width - len, Alignment::Right)?;
+ // SAFETY: Per the precondition.
+ unsafe {
+ self.write_formatted_parts(&formatted)?;
+ }
post_padding.write(self)
};
self.fill = old_fill;
@@ -1609,20 +1457,20 @@ impl<'a> Formatter<'a> {
ret
} else {
// this is the common case and we take a shortcut
- self.write_formatted_parts(formatted)
+ // SAFETY: Per the precondition.
+ unsafe { self.write_formatted_parts(formatted) }
}
}
- fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
- fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
+ /// # Safety
+ ///
+ /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8.
+ unsafe fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
+ unsafe fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
// SAFETY: This is used for `numfmt::Part::Num` and `numfmt::Part::Copy`.
// It's safe to use for `numfmt::Part::Num` since every char `c` is between
- // `b'0'` and `b'9'`, which means `s` is valid UTF-8.
- // It's also probably safe in practice to use for `numfmt::Part::Copy(buf)`
- // since `buf` should be plain ASCII, but it's possible for someone to pass
- // in a bad value for `buf` into `numfmt::to_shortest_str` since it is a
- // public function.
- // FIXME: Determine whether this could result in UB.
+ // `b'0'` and `b'9'`, which means `s` is valid UTF-8. It's safe to use for
+ // `numfmt::Part::Copy` due to this function's precondition.
buf.write_str(unsafe { str::from_utf8_unchecked(s) })
}
@@ -1649,11 +1497,15 @@ impl<'a> Formatter<'a> {
*c = b'0' + (v % 10) as u8;
v /= 10;
}
- write_bytes(self.buf, &s[..len])?;
+ // SAFETY: Per the precondition.
+ unsafe {
+ write_bytes(self.buf, &s[..len])?;
+ }
}
- numfmt::Part::Copy(buf) => {
+ // SAFETY: Per the precondition.
+ numfmt::Part::Copy(buf) => unsafe {
write_bytes(self.buf, buf)?;
- }
+ },
}
}
Ok(())
@@ -1670,7 +1522,7 @@ impl<'a> Formatter<'a> {
/// struct Foo;
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// formatter.write_str("Foo")
/// // This is equivalent to:
/// // write!(formatter, "Foo")
@@ -1695,7 +1547,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// formatter.write_fmt(format_args!("Foo {}", self.0))
/// }
/// }
@@ -1730,7 +1582,7 @@ impl<'a> Formatter<'a> {
/// struct Foo;
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let c = formatter.fill();
/// if let Some(width) = formatter.width() {
/// for _ in 0..width {
@@ -1758,14 +1610,12 @@ impl<'a> Formatter<'a> {
/// # Examples
///
/// ```
- /// extern crate core;
- ///
/// use std::fmt::{self, Alignment};
///
/// struct Foo;
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let s = if let Some(s) = formatter.align() {
/// match s {
/// Alignment::Left => "left",
@@ -1788,10 +1638,10 @@ impl<'a> Formatter<'a> {
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
pub fn align(&self) -> Option<Alignment> {
match self.align {
- rt::v1::Alignment::Left => Some(Alignment::Left),
- rt::v1::Alignment::Right => Some(Alignment::Right),
- rt::v1::Alignment::Center => Some(Alignment::Center),
- rt::v1::Alignment::Unknown => None,
+ rt::Alignment::Left => Some(Alignment::Left),
+ rt::Alignment::Right => Some(Alignment::Right),
+ rt::Alignment::Center => Some(Alignment::Center),
+ rt::Alignment::Unknown => None,
}
}
@@ -1805,7 +1655,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if let Some(width) = formatter.width() {
/// // If we received a width, we use it
/// write!(formatter, "{:width$}", format!("Foo({})", self.0), width = width)
@@ -1836,7 +1686,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(f32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if let Some(precision) = formatter.precision() {
/// // If we received a precision, we use it.
/// write!(formatter, "Foo({1:.*})", precision, self.0)
@@ -1866,7 +1716,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if formatter.sign_plus() {
/// write!(formatter,
/// "Foo({}{})",
@@ -1885,7 +1735,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_plus(&self) -> bool {
- self.flags & (1 << FlagV1::SignPlus as u32) != 0
+ self.flags & (1 << rt::Flag::SignPlus as u32) != 0
}
/// Determines if the `-` flag was specified.
@@ -1898,7 +1748,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if formatter.sign_minus() {
/// // You want a minus sign? Have one!
/// write!(formatter, "-Foo({})", self.0)
@@ -1914,7 +1764,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_minus(&self) -> bool {
- self.flags & (1 << FlagV1::SignMinus as u32) != 0
+ self.flags & (1 << rt::Flag::SignMinus as u32) != 0
}
/// Determines if the `#` flag was specified.
@@ -1927,7 +1777,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if formatter.alternate() {
/// write!(formatter, "Foo({})", self.0)
/// } else {
@@ -1942,7 +1792,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn alternate(&self) -> bool {
- self.flags & (1 << FlagV1::Alternate as u32) != 0
+ self.flags & (1 << rt::Flag::Alternate as u32) != 0
}
/// Determines if the `0` flag was specified.
@@ -1955,7 +1805,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(i32);
///
/// impl fmt::Display for Foo {
- /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
/// assert!(formatter.sign_aware_zero_pad());
/// assert_eq!(formatter.width(), Some(4));
/// // We ignore the formatter's options.
@@ -1968,17 +1818,17 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_aware_zero_pad(&self) -> bool {
- self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0
+ self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0
}
// FIXME: Decide what public API we want for these two flags.
// https://github.com/rust-lang/rust/issues/48584
fn debug_lower_hex(&self) -> bool {
- self.flags & (1 << FlagV1::DebugLowerHex as u32) != 0
+ self.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0
}
fn debug_upper_hex(&self) -> bool {
- self.flags & (1 << FlagV1::DebugUpperHex as u32) != 0
+ self.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0
}
/// Creates a [`DebugStruct`] builder designed to assist with creation of
@@ -1999,7 +1849,7 @@ impl<'a> Formatter<'a> {
/// }
///
/// impl fmt::Debug for Foo {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_struct("Foo")
/// .field("bar", &self.bar)
/// .field("baz", &self.baz)
@@ -2157,7 +2007,7 @@ impl<'a> Formatter<'a> {
/// struct Foo<T>(i32, String, PhantomData<T>);
///
/// impl<T> fmt::Debug for Foo<T> {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_tuple("Foo")
/// .field(&self.0)
/// .field(&self.1)
@@ -2289,7 +2139,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_list().entries(self.0.iter()).finish()
/// }
/// }
@@ -2312,7 +2162,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_set().entries(self.0.iter()).finish()
/// }
/// }
@@ -2328,14 +2178,14 @@ impl<'a> Formatter<'a> {
/// ```rust
/// use std::fmt;
///
- /// struct Arm<'a, L: 'a, R: 'a>(&'a (L, R));
- /// struct Table<'a, K: 'a, V: 'a>(&'a [(K, V)], V);
+ /// struct Arm<'a, L, R>(&'a (L, R));
+ /// struct Table<'a, K, V>(&'a [(K, V)], V);
///
/// impl<'a, L, R> fmt::Debug for Arm<'a, L, R>
/// where
/// L: 'a + fmt::Debug, R: 'a + fmt::Debug
/// {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// L::fmt(&(self.0).0, fmt)?;
/// fmt.write_str(" => ")?;
/// R::fmt(&(self.0).1, fmt)
@@ -2346,7 +2196,7 @@ impl<'a> Formatter<'a> {
/// where
/// K: 'a + fmt::Debug, V: 'a + fmt::Debug
/// {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_set()
/// .entries(self.0.iter().map(Arm))
/// .entry(&Arm(&(format_args!("_"), &self.1)))
@@ -2370,7 +2220,7 @@ impl<'a> Formatter<'a> {
/// struct Foo(Vec<(String, i32)>);
///
/// impl fmt::Debug for Foo {
- /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
/// }
/// }
@@ -2429,6 +2279,7 @@ fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperEx
#[unstable(feature = "never_type", issue = "35121")]
impl Debug for ! {
+ #[inline]
fn fmt(&self, _: &mut Formatter<'_>) -> Result {
*self
}
@@ -2436,6 +2287,7 @@ impl Debug for ! {
#[unstable(feature = "never_type", issue = "35121")]
impl Display for ! {
+ #[inline]
fn fmt(&self, _: &mut Formatter<'_>) -> Result {
*self
}
@@ -2538,13 +2390,13 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul
// or not to zero extend, and then unconditionally set it to get the
// prefix.
if f.alternate() {
- f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
+ f.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32);
if f.width.is_none() {
f.width = Some((usize::BITS / 4) as usize + 2);
}
}
- f.flags |= 1 << (FlagV1::Alternate as u32);
+ f.flags |= 1 << (rt::Flag::Alternate as u32);
let ret = LowerHex::fmt(&ptr_addr, f);
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index d8365ae9b..4f42f73eb 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -52,8 +52,12 @@ impl_int! { i8 i16 i32 i64 i128 isize }
impl_uint! { u8 u16 u32 u64 u128 usize }
/// A type that represents a specific radix
+///
+/// # Safety
+///
+/// `digit` must return an ASCII character.
#[doc(hidden)]
-trait GenericRadix: Sized {
+unsafe trait GenericRadix: Sized {
/// The number of digits.
const BASE: u8;
@@ -129,7 +133,7 @@ struct UpperHex;
macro_rules! radix {
($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
- impl GenericRadix for $T {
+ unsafe impl GenericRadix for $T {
const BASE: u8 = $base;
const PREFIX: &'static str = $prefix;
fn digit(x: u8) -> u8 {
@@ -407,7 +411,7 @@ macro_rules! impl_Exp {
let parts = &[
numfmt::Part::Copy(buf_slice),
numfmt::Part::Zero(added_precision),
- numfmt::Part::Copy(exp_slice)
+ numfmt::Part::Copy(exp_slice),
];
let sign = if !is_nonnegative {
"-"
@@ -416,8 +420,9 @@ macro_rules! impl_Exp {
} else {
""
};
- let formatted = numfmt::Formatted{sign, parts};
- f.pad_formatted_parts(&formatted)
+ let formatted = numfmt::Formatted { sign, parts };
+ // SAFETY: `buf_slice` and `exp_slice` contain only ASCII characters.
+ unsafe { f.pad_formatted_parts(&formatted) }
}
$(
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
new file mode 100644
index 000000000..d37888c27
--- /dev/null
+++ b/library/core/src/fmt/rt.rs
@@ -0,0 +1,212 @@
+#![allow(missing_debug_implementations)]
+#![unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
+
+//! These are the lang items used by format_args!().
+
+use super::*;
+
+#[lang = "format_placeholder"]
+#[derive(Copy, Clone)]
+pub struct Placeholder {
+ pub position: usize,
+ pub fill: char,
+ pub align: Alignment,
+ pub flags: u32,
+ pub precision: Count,
+ pub width: Count,
+}
+
+impl Placeholder {
+ #[inline(always)]
+ pub const fn new(
+ position: usize,
+ fill: char,
+ align: Alignment,
+ flags: u32,
+ precision: Count,
+ width: Count,
+ ) -> Self {
+ Self { position, fill, align, flags, precision, width }
+ }
+}
+
+#[lang = "format_alignment"]
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum Alignment {
+ Left,
+ Right,
+ Center,
+ Unknown,
+}
+
+/// Used by [width](https://doc.rust-lang.org/std/fmt/#width)
+/// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
+#[lang = "format_count"]
+#[derive(Copy, Clone)]
+pub enum Count {
+ /// Specified with a literal number, stores the value
+ Is(usize),
+ /// Specified using `$` and `*` syntaxes, stores the index into `args`
+ Param(usize),
+ /// Not specified
+ Implied,
+}
+
+// This needs to match the order of flags in compiler/rustc_ast_lowering/src/format.rs.
+#[derive(Copy, Clone)]
+pub(super) enum Flag {
+ SignPlus,
+ SignMinus,
+ Alternate,
+ SignAwareZeroPad,
+ DebugLowerHex,
+ DebugUpperHex,
+}
+
+/// This struct represents the generic "argument" which is taken by format_args!().
+/// It contains a function to format the given value. At compile time it is ensured that the
+/// function and the value have the correct types, and then this struct is used to canonicalize
+/// arguments to one type.
+///
+/// Argument is essentially an optimized partially applied formatting function,
+/// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
+#[lang = "format_argument"]
+#[derive(Copy, Clone)]
+pub struct Argument<'a> {
+ value: &'a Opaque,
+ formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
+}
+
+#[rustc_diagnostic_item = "ArgumentMethods"]
+impl<'a> Argument<'a> {
+ #[inline(always)]
+ fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
+ // SAFETY: `mem::transmute(x)` is safe because
+ // 1. `&'b T` keeps the lifetime it originated with `'b`
+ // (so as to not have an unbounded lifetime)
+ // 2. `&'b T` and `&'b Opaque` have the same memory layout
+ // (when `T` is `Sized`, as it is here)
+ // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
+ // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
+ // (as long as `T` is `Sized`)
+ unsafe { Argument { formatter: mem::transmute(f), value: mem::transmute(x) } }
+ }
+
+ #[inline(always)]
+ pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Display::fmt)
+ }
+ #[inline(always)]
+ pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Debug::fmt)
+ }
+ #[inline(always)]
+ pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Octal::fmt)
+ }
+ #[inline(always)]
+ pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'_> {
+ Self::new(x, LowerHex::fmt)
+ }
+ #[inline(always)]
+ pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'_> {
+ Self::new(x, UpperHex::fmt)
+ }
+ #[inline(always)]
+ pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Pointer::fmt)
+ }
+ #[inline(always)]
+ pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'_> {
+ Self::new(x, Binary::fmt)
+ }
+ #[inline(always)]
+ pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'_> {
+ Self::new(x, LowerExp::fmt)
+ }
+ #[inline(always)]
+ pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'_> {
+ Self::new(x, UpperExp::fmt)
+ }
+ #[inline(always)]
+ pub fn from_usize(x: &usize) -> Argument<'_> {
+ Self::new(x, USIZE_MARKER)
+ }
+
+ #[inline(always)]
+ pub(super) fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ (self.formatter)(self.value, f)
+ }
+
+ #[inline(always)]
+ pub(super) fn as_usize(&self) -> Option<usize> {
+ // We are type punning a bit here: USIZE_MARKER only takes an &usize but
+ // formatter takes an &Opaque. Rust understandably doesn't think we should compare
+ // the function pointers if they don't have the same signature, so we cast to
+ // usizes to tell it that we just want to compare addresses.
+ if self.formatter as usize == USIZE_MARKER as usize {
+ // SAFETY: The `formatter` field is only set to USIZE_MARKER if
+ // the value is a usize, so this is safe
+ Some(unsafe { *(self.value as *const _ as *const usize) })
+ } else {
+ None
+ }
+ }
+
+ /// Used by `format_args` when all arguments are gone after inlining,
+ /// when using `&[]` would incorrectly allow for a bigger lifetime.
+ ///
+ /// This fails without format argument inlining, and that shouldn't be different
+ /// when the argument is inlined:
+ ///
+ /// ```compile_fail,E0716
+ /// let f = format_args!("{}", "a");
+ /// println!("{f}");
+ /// ```
+ #[inline(always)]
+ pub fn none() -> [Self; 0] {
+ []
+ }
+}
+
+/// This struct represents the unsafety of constructing an `Arguments`.
+/// It exists, rather than an unsafe function, in order to simplify the expansion
+/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
+#[lang = "format_unsafe_arg"]
+pub struct UnsafeArg {
+ _private: (),
+}
+
+impl UnsafeArg {
+ /// See documentation where `UnsafeArg` is required to know when it is safe to
+ /// create and use `UnsafeArg`.
+ #[inline(always)]
+ pub unsafe fn new() -> Self {
+ Self { _private: () }
+ }
+}
+
+extern "C" {
+ type Opaque;
+}
+
+// This guarantees a single stable value for the function pointer associated with
+// indices/counts in the formatting infrastructure.
+//
+// Note that a function defined as such would not be correct as functions are
+// always tagged unnamed_addr with the current lowering to LLVM IR, so their
+// address is not considered important to LLVM and as such the as_usize cast
+// could have been miscompiled. In practice, we never call as_usize on non-usize
+// containing data (as a matter of static generation of the formatting
+// arguments), so this is merely an additional check.
+//
+// We primarily want to ensure that the function pointer at `USIZE_MARKER` has
+// an address corresponding *only* to functions that also take `&usize` as their
+// first argument. The read_volatile here ensures that we can safely ready out a
+// usize from the passed reference and that this address does not point at a
+// non-usize taking function.
+static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| {
+ // SAFETY: ptr is a reference
+ let _v: usize = unsafe { crate::ptr::read_volatile(ptr) };
+ loop {}
+};
diff --git a/library/core/src/fmt/rt/v1.rs b/library/core/src/fmt/rt/v1.rs
deleted file mode 100644
index 6d70796f7..000000000
--- a/library/core/src/fmt/rt/v1.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-//! This is an internal module used by the ifmt! runtime. These structures are
-//! emitted to static arrays to precompile format strings ahead of time.
-//!
-//! These definitions are similar to their `ct` equivalents, but differ in that
-//! these can be statically allocated and are slightly optimized for the runtime
-#![allow(missing_debug_implementations)]
-
-#[lang = "format_placeholder"]
-#[derive(Copy, Clone)]
-// FIXME: Rename this to Placeholder
-pub struct Argument {
- pub position: usize,
- pub format: FormatSpec,
-}
-
-#[derive(Copy, Clone)]
-pub struct FormatSpec {
- pub fill: char,
- pub align: Alignment,
- pub flags: u32,
- pub precision: Count,
- pub width: Count,
-}
-
-impl Argument {
- #[inline(always)]
- pub const fn new(
- position: usize,
- fill: char,
- align: Alignment,
- flags: u32,
- precision: Count,
- width: Count,
- ) -> Self {
- Self { position, format: FormatSpec { fill, align, flags, precision, width } }
- }
-}
-
-/// Possible alignments that can be requested as part of a formatting directive.
-#[lang = "format_alignment"]
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub enum Alignment {
- /// Indication that contents should be left-aligned.
- Left,
- /// Indication that contents should be right-aligned.
- Right,
- /// Indication that contents should be center-aligned.
- Center,
- /// No alignment was requested.
- Unknown,
-}
-
-/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
-#[lang = "format_count"]
-#[derive(Copy, Clone)]
-pub enum Count {
- /// Specified with a literal number, stores the value
- Is(usize),
- /// Specified using `$` and `*` syntaxes, stores the index into `args`
- Param(usize),
- /// Not specified
- Implied,
-}