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 | |
6 | use super::*; |
7 | use crate::hint::unreachable_unchecked; |
8 | use crate::ptr::NonNull; |
9 | |
10 | #[lang = "format_placeholder" ] |
11 | #[derive (Copy, Clone)] |
12 | pub 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 | |
23 | impl 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)] |
47 | pub 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)] |
58 | pub 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)] |
72 | enum 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)] |
95 | pub struct Argument<'a> { |
96 | ty: ArgumentType<'a>, |
97 | } |
98 | |
99 | #[rustc_diagnostic_item = "ArgumentMethods" ] |
100 | impl 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" ] |
225 | pub struct UnsafeArg { |
226 | _private: (), |
227 | } |
228 | |
229 | impl 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 | } |
237 | |