Skip to content
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

More core::fmt::rt cleanup. #110766

Merged
merged 5 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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_ast_lowering/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ fn make_format_spec<'hir>(
None => sym::Unknown,
},
);
// This needs to match `Flag` in library/core/src/fmt/mod.rs.
// This needs to match `Flag` in library/core/src/fmt/rt.rs.
let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
| ((sign == Some(FormatSign::Minus)) as u32) << 1
| (alternate as u32) << 2
Expand Down
246 changes: 52 additions & 194 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,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 Argument<'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) -> Argument<'_> {
Self::new(x, $t::fmt)
}
};
}

#[rustc_diagnostic_item = "ArgumentMethods"]
impl<'a> Argument<'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) -> 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) } }
}

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) -> Argument<'_> {
Argument::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 Flag {
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 {
Expand All @@ -401,22 +304,18 @@ 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 [Argument<'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");
}
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 [Argument<'a>]) -> Arguments<'a> {
pub const 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");
}
Expand All @@ -425,19 +324,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::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`.
#[doc(hidden)]
#[inline]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
pub fn new_v1_formatted(
pieces: &'a [&'static str],
args: &'a [Argument<'a>],
args: &'a [rt::Argument<'a>],
fmt: &'a [rt::Placeholder],
_unsafe_arg: UnsafeArg,
_unsafe_arg: rt::UnsafeArg,
) -> Arguments<'a> {
Arguments { pieces, fmt: Some(fmt), args }
}
Expand All @@ -446,9 +343,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();

Expand All @@ -468,43 +363,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::Placeholder]>,

// Dynamic arguments for interpolation, to be interleaved with string
// pieces. (Every argument is preceded by a string piece.)
args: &'a [Argument<'a>],
}

impl<'a> Arguments<'a> {
/// Get the formatted string, if it has no arguments to be formatted at runtime.
///
Expand Down Expand Up @@ -1244,7 +1102,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;
}
}
Expand Down Expand Up @@ -1274,7 +1132,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
Ok(())
}

unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[Argument<'_>]) -> Result {
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;
Expand All @@ -1292,10 +1150,10 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[Argument<'
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: &[Argument<'_>], cnt: &rt::Count) -> Option<usize> {
unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option<usize> {
match *cnt {
rt::Count::Is(n) => Some(n),
rt::Count::Implied => None,
Expand Down Expand Up @@ -1878,7 +1736,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_plus(&self) -> bool {
self.flags & (1 << Flag::SignPlus as u32) != 0
self.flags & (1 << rt::Flag::SignPlus as u32) != 0
}

/// Determines if the `-` flag was specified.
Expand Down Expand Up @@ -1907,7 +1765,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_minus(&self) -> bool {
self.flags & (1 << Flag::SignMinus as u32) != 0
self.flags & (1 << rt::Flag::SignMinus as u32) != 0
}

/// Determines if the `#` flag was specified.
Expand Down Expand Up @@ -1935,7 +1793,7 @@ impl<'a> Formatter<'a> {
#[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn alternate(&self) -> bool {
self.flags & (1 << Flag::Alternate as u32) != 0
self.flags & (1 << rt::Flag::Alternate as u32) != 0
}

/// Determines if the `0` flag was specified.
Expand All @@ -1961,17 +1819,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 << Flag::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 << Flag::DebugLowerHex as u32) != 0
self.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0
}

fn debug_upper_hex(&self) -> bool {
self.flags & (1 << Flag::DebugUpperHex as u32) != 0
self.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0
}

/// Creates a [`DebugStruct`] builder designed to assist with creation of
Expand Down Expand Up @@ -2531,13 +2389,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 << (Flag::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 << (Flag::Alternate as u32);
f.flags |= 1 << (rt::Flag::Alternate as u32);

let ret = LowerHex::fmt(&ptr_addr, f);

Expand Down
Loading