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}