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