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;
8
9#[lang = "format_placeholder"]
10#[derive(Copy, Clone)]
11pub 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
20impl 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)]
36pub 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)]
47pub 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)]
58pub(super) enum Flag {
59 SignPlus,
60 SignMinus,
61 Alternate,
62 SignAwareZeroPad,
63 DebugLowerHex,
64 DebugUpperHex,
65}
66
67#[derive(Copy, Clone)]
68enum 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)]
85pub struct Argument<'a> {
86 ty: ArgumentType<'a>,
87}
88
89#[rustc_diagnostic_item = "ArgumentMethods"]
90impl<'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"]
199pub struct UnsafeArg {
200 _private: (),
201}
202
203impl 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
212extern "C" {
213 type Opaque;
214}
215