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