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
68macro_rules! argument_new {
69    ($t:ty, $x:expr, $f:expr) => {
70        Argument {
71            // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and
72            // a `fn(&T, ...)`, so the invariant is maintained.
73            ty: ArgumentType::Placeholder {
74                value: NonNull::<$t>::from_ref($x).cast(),
75                // The Rust ABI considers all pointers to be equivalent, so transmuting a fn(&T) to
76                // fn(NonNull<()>) and calling it with a NonNull<()> that points at a T is allowed.
77                // However, the CFI sanitizer does not allow this, and triggers a crash when it
78                // happens.
79                //
80                // To avoid this crash, we use a helper function when CFI is enabled. To avoid the
81                // cost of this helper function (mainly code-size) when it is not needed, we
82                // transmute the function pointer otherwise.
83                //
84                // This is similar to what the Rust compiler does internally with vtables when KCFI
85                // is enabled, where it generates trampoline functions that only serve to adjust the
86                // expected type of the argument. `ArgumentType::Placeholder` is a bit like a
87                // manually constructed trait object, so it is not surprising that the same approach
88                // has to be applied here as well.
89                //
90                // It is still considered problematic (from the Rust side) that CFI rejects entirely
91                // legal Rust programs, so we do not consider anything done here a stable guarantee,
92                // but meanwhile we carry this work-around to keep Rust compatible with CFI and
93                // KCFI.
94                #[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))]
95                formatter: {
96                    let f: fn(&$t, &mut Formatter<'_>) -> Result = $f;
97                    // SAFETY: This is only called with `value`, which has the right type.
98                    unsafe { core::mem::transmute(f) }
99                },
100                #[cfg(any(sanitize = "cfi", sanitize = "kcfi"))]
101                formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| {
102                    let func = $f;
103                    // SAFETY: This is the same type as the `value` field.
104                    let r = unsafe { ptr.cast::<$t>().as_ref() };
105                    (func)(r, fmt)
106                },
107                _lifetime: PhantomData,
108            },
109        }
110    };
111}
112
113#[rustc_diagnostic_item = "ArgumentMethods"]
114impl Argument<'_> {
115    #[inline]
116    pub fn new_display<T: Display>(x: &T) -> Argument<'_> {
117        argument_new!(T, x, <T as Display>::fmt)
118    }
119    #[inline]
120    pub fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
121        argument_new!(T, x, <T as Debug>::fmt)
122    }
123    #[inline]
124    pub fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
125        argument_new!(T, x, |_: &T, _| Ok(()))
126    }
127    #[inline]
128    pub fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
129        argument_new!(T, x, <T as Octal>::fmt)
130    }
131    #[inline]
132    pub fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
133        argument_new!(T, x, <T as LowerHex>::fmt)
134    }
135    #[inline]
136    pub fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
137        argument_new!(T, x, <T as UpperHex>::fmt)
138    }
139    #[inline]
140    pub fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
141        argument_new!(T, x, <T as Pointer>::fmt)
142    }
143    #[inline]
144    pub fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
145        argument_new!(T, x, <T as Binary>::fmt)
146    }
147    #[inline]
148    pub fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
149        argument_new!(T, x, <T as LowerExp>::fmt)
150    }
151    #[inline]
152    pub fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
153        argument_new!(T, x, <T as 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    #[inline]
170    pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
171        match self.ty {
172            // SAFETY:
173            // Because of the invariant that if `formatter` had the type
174            // `fn(&T, _) -> _` then `value` has type `&'b T` where `'b` is
175            // the lifetime of the `ArgumentType`, and because references
176            // and `NonNull` are ABI-compatible, this is completely equivalent
177            // to calling the original function passed to `new` with the
178            // original reference, which is sound.
179            ArgumentType::Placeholder { formatter, value, .. } => unsafe { formatter(value, f) },
180            // SAFETY: the caller promised this.
181            ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
182        }
183    }
184
185    #[inline]
186    pub(super) const fn as_u16(&self) -> Option<u16> {
187        match self.ty {
188            ArgumentType::Count(count) => Some(count),
189            ArgumentType::Placeholder { .. } => None,
190        }
191    }
192
193    /// Used by `format_args` when all arguments are gone after inlining,
194    /// when using `&[]` would incorrectly allow for a bigger lifetime.
195    ///
196    /// This fails without format argument inlining, and that shouldn't be different
197    /// when the argument is inlined:
198    ///
199    /// ```compile_fail,E0716
200    /// let f = format_args!("{}", "a");
201    /// println!("{f}");
202    /// ```
203    #[inline]
204    pub const fn none() -> [Self; 0] {
205        []
206    }
207}
208
209/// This struct represents the unsafety of constructing an `Arguments`.
210/// It exists, rather than an unsafe function, in order to simplify the expansion
211/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
212#[lang = "format_unsafe_arg"]
213pub struct UnsafeArg {
214    _private: (),
215}
216
217impl UnsafeArg {
218    /// See documentation where `UnsafeArg` is required to know when it is safe to
219    /// create and use `UnsafeArg`.
220    #[inline]
221    pub const unsafe fn new() -> Self {
222        Self { _private: () }
223    }
224}