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