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