core/fmt/
rt.rs

1#![allow(missing_debug_implementations)]
2#![unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
3
4//! These are the lang items used by format_args!().
5
6use super::*;
7use crate::hint::unreachable_unchecked;
8use crate::ptr::NonNull;
9
10#[lang = "format_placeholder"]
11#[derive(Copy, Clone)]
12pub struct Placeholder {
13    pub position: usize,
14    #[cfg(bootstrap)]
15    pub fill: char,
16    #[cfg(bootstrap)]
17    pub align: Alignment,
18    pub flags: u32,
19    pub precision: Count,
20    pub width: Count,
21}
22
23#[cfg(bootstrap)]
24impl Placeholder {
25    #[inline]
26    pub const fn new(
27        position: usize,
28        fill: char,
29        align: Alignment,
30        flags: u32,
31        precision: Count,
32        width: Count,
33    ) -> Self {
34        Self { position, fill, align, flags, precision, width }
35    }
36}
37
38#[cfg(bootstrap)]
39#[lang = "format_alignment"]
40#[derive(Copy, Clone, PartialEq, Eq)]
41pub enum Alignment {
42    Left,
43    Right,
44    Center,
45    Unknown,
46}
47
48/// Used by [width](https://doc.rust-lang.org/std/fmt/#width)
49/// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
50#[lang = "format_count"]
51#[derive(Copy, Clone)]
52pub enum Count {
53    /// Specified with a literal number, stores the value
54    #[cfg(bootstrap)]
55    Is(usize),
56    /// Specified with a literal number, stores the value
57    #[cfg(not(bootstrap))]
58    Is(u16),
59    /// Specified using `$` and `*` syntaxes, stores the index into `args`
60    Param(usize),
61    /// Not specified
62    Implied,
63}
64
65#[derive(Copy, Clone)]
66enum ArgumentType<'a> {
67    Placeholder {
68        // INVARIANT: `formatter` has type `fn(&T, _) -> _` for some `T`, and `value`
69        // was derived from a `&'a T`.
70        value: NonNull<()>,
71        formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result,
72        _lifetime: PhantomData<&'a ()>,
73    },
74    Count(u16),
75}
76
77/// This struct represents a generic "argument" which is taken by format_args!().
78///
79/// This can be either a placeholder argument or a count argument.
80/// * A placeholder argument contains a function to format the given value. At
81///   compile time it is ensured that the function and the value have the correct
82///   types, and then this struct is used to canonicalize arguments to one type.
83///   Placeholder arguments are essentially an optimized partially applied formatting
84///   function, equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
85/// * A count argument contains a count for dynamic formatting parameters like
86///   precision and width.
87#[lang = "format_argument"]
88#[derive(Copy, Clone)]
89pub struct Argument<'a> {
90    ty: ArgumentType<'a>,
91}
92
93#[rustc_diagnostic_item = "ArgumentMethods"]
94impl Argument<'_> {
95    #[inline]
96    const fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> {
97        Argument {
98            // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and
99            // a `fn(&T, ...)`, so the invariant is maintained.
100            ty: ArgumentType::Placeholder {
101                value: NonNull::from_ref(x).cast(),
102                // SAFETY: function pointers always have the same layout.
103                formatter: unsafe { mem::transmute(f) },
104                _lifetime: PhantomData,
105            },
106        }
107    }
108
109    #[inline]
110    pub fn new_display<T: Display>(x: &T) -> Argument<'_> {
111        Self::new(x, Display::fmt)
112    }
113    #[inline]
114    pub fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
115        Self::new(x, Debug::fmt)
116    }
117    #[inline]
118    pub fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
119        Self::new(x, |_, _| Ok(()))
120    }
121    #[inline]
122    pub fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
123        Self::new(x, Octal::fmt)
124    }
125    #[inline]
126    pub fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
127        Self::new(x, LowerHex::fmt)
128    }
129    #[inline]
130    pub fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
131        Self::new(x, UpperHex::fmt)
132    }
133    #[inline]
134    pub fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
135        Self::new(x, Pointer::fmt)
136    }
137    #[inline]
138    pub fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
139        Self::new(x, Binary::fmt)
140    }
141    #[inline]
142    pub fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
143        Self::new(x, LowerExp::fmt)
144    }
145    #[inline]
146    pub fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
147        Self::new(x, UpperExp::fmt)
148    }
149    #[inline]
150    #[track_caller]
151    pub const fn from_usize(x: &usize) -> Argument<'_> {
152        if *x > u16::MAX as usize {
153            panic!("Formatting argument out of range");
154        }
155        Argument { ty: ArgumentType::Count(*x as u16) }
156    }
157
158    /// Format this placeholder argument.
159    ///
160    /// # Safety
161    ///
162    /// This argument must actually be a placeholder argument.
163    ///
164    // FIXME: Transmuting formatter in new and indirectly branching to/calling
165    // it here is an explicit CFI violation.
166    #[allow(inline_no_sanitize)]
167    #[no_sanitize(cfi, kcfi)]
168    #[inline]
169    pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
170        match self.ty {
171            // SAFETY:
172            // Because of the invariant that if `formatter` had the type
173            // `fn(&T, _) -> _` then `value` has type `&'b T` where `'b` is
174            // the lifetime of the `ArgumentType`, and because references
175            // and `NonNull` are ABI-compatible, this is completely equivalent
176            // to calling the original function passed to `new` with the
177            // original reference, which is sound.
178            ArgumentType::Placeholder { formatter, value, .. } => unsafe { formatter(value, f) },
179            // SAFETY: the caller promised this.
180            ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
181        }
182    }
183
184    #[inline]
185    pub(super) const fn as_u16(&self) -> Option<u16> {
186        match self.ty {
187            ArgumentType::Count(count) => Some(count),
188            ArgumentType::Placeholder { .. } => None,
189        }
190    }
191
192    /// Used by `format_args` when all arguments are gone after inlining,
193    /// when using `&[]` would incorrectly allow for a bigger lifetime.
194    ///
195    /// This fails without format argument inlining, and that shouldn't be different
196    /// when the argument is inlined:
197    ///
198    /// ```compile_fail,E0716
199    /// let f = format_args!("{}", "a");
200    /// println!("{f}");
201    /// ```
202    #[inline]
203    pub const fn none() -> [Self; 0] {
204        []
205    }
206}
207
208/// This struct represents the unsafety of constructing an `Arguments`.
209/// It exists, rather than an unsafe function, in order to simplify the expansion
210/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
211#[lang = "format_unsafe_arg"]
212pub struct UnsafeArg {
213    _private: (),
214}
215
216impl UnsafeArg {
217    /// See documentation where `UnsafeArg` is required to know when it is safe to
218    /// create and use `UnsafeArg`.
219    #[inline]
220    pub const unsafe fn new() -> Self {
221        Self { _private: () }
222    }
223}