diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /library/core/src/fmt | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-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.rs | 14 | ||||
-rw-r--r-- | library/core/src/fmt/float.rs | 12 | ||||
-rw-r--r-- | library/core/src/fmt/mod.rs | 416 | ||||
-rw-r--r-- | library/core/src/fmt/num.rs | 15 | ||||
-rw-r--r-- | library/core/src/fmt/rt.rs | 212 | ||||
-rw-r--r-- | library/core/src/fmt/rt/v1.rs | 63 |
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, -} |