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