• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #[lang = "format_placeholder"]
9 #[derive(Copy, Clone)]
10 pub 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 
19 impl Placeholder {
20     #[inline(always)]
new( position: usize, fill: char, align: Alignment, flags: u32, precision: Count, width: Count, ) -> Self21     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)]
35 pub 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)]
46 pub 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)]
57 pub(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)]
75 pub struct Argument<'a> {
76     value: &'a Opaque,
77     formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
78 }
79 
80 #[rustc_diagnostic_item = "ArgumentMethods"]
81 impl<'a> Argument<'a> {
82     #[inline(always)]
new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b>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)]
new_display<'b, T: Display>(x: &'b T) -> Argument<'_>96     pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
97         Self::new(x, Display::fmt)
98     }
99     #[inline(always)]
new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_>100     pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_> {
101         Self::new(x, Debug::fmt)
102     }
103     #[inline(always)]
new_octal<'b, T: Octal>(x: &'b T) -> Argument<'_>104     pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'_> {
105         Self::new(x, Octal::fmt)
106     }
107     #[inline(always)]
new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'_>108     pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'_> {
109         Self::new(x, LowerHex::fmt)
110     }
111     #[inline(always)]
new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'_>112     pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'_> {
113         Self::new(x, UpperHex::fmt)
114     }
115     #[inline(always)]
new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'_>116     pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'_> {
117         Self::new(x, Pointer::fmt)
118     }
119     #[inline(always)]
new_binary<'b, T: Binary>(x: &'b T) -> Argument<'_>120     pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'_> {
121         Self::new(x, Binary::fmt)
122     }
123     #[inline(always)]
new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'_>124     pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'_> {
125         Self::new(x, LowerExp::fmt)
126     }
127     #[inline(always)]
new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'_>128     pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'_> {
129         Self::new(x, UpperExp::fmt)
130     }
131     #[inline(always)]
from_usize(x: &usize) -> Argument<'_>132     pub fn from_usize(x: &usize) -> Argument<'_> {
133         Self::new(x, USIZE_MARKER)
134     }
135 
136     #[inline(always)]
fmt(&self, f: &mut Formatter<'_>) -> Result137     pub(super) fn fmt(&self, f: &mut Formatter<'_>) -> Result {
138         (self.formatter)(self.value, f)
139     }
140 
141     #[inline(always)]
as_usize(&self) -> Option<usize>142     pub(super) fn as_usize(&self) -> Option<usize> {
143         // We are type punning a bit here: USIZE_MARKER only takes an &usize but
144         // formatter takes an &Opaque. Rust understandably doesn't think we should compare
145         // the function pointers if they don't have the same signature, so we cast to
146         // usizes to tell it that we just want to compare addresses.
147         if self.formatter as usize == USIZE_MARKER as usize {
148             // SAFETY: The `formatter` field is only set to USIZE_MARKER if
149             // the value is a usize, so this is safe
150             Some(unsafe { *(self.value as *const _ as *const usize) })
151         } else {
152             None
153         }
154     }
155 
156     /// Used by `format_args` when all arguments are gone after inlining,
157     /// when using `&[]` would incorrectly allow for a bigger lifetime.
158     ///
159     /// This fails without format argument inlining, and that shouldn't be different
160     /// when the argument is inlined:
161     ///
162     /// ```compile_fail,E0716
163     /// let f = format_args!("{}", "a");
164     /// println!("{f}");
165     /// ```
166     #[inline(always)]
none() -> [Self; 0]167     pub fn none() -> [Self; 0] {
168         []
169     }
170 }
171 
172 /// This struct represents the unsafety of constructing an `Arguments`.
173 /// It exists, rather than an unsafe function, in order to simplify the expansion
174 /// of `format_args!(..)` and reduce the scope of the `unsafe` block.
175 #[lang = "format_unsafe_arg"]
176 pub struct UnsafeArg {
177     _private: (),
178 }
179 
180 impl UnsafeArg {
181     /// See documentation where `UnsafeArg` is required to know when it is safe to
182     /// create and use `UnsafeArg`.
183     #[inline(always)]
new() -> Self184     pub unsafe fn new() -> Self {
185         Self { _private: () }
186     }
187 }
188 
189 extern "C" {
190     type Opaque;
191 }
192 
193 // This guarantees a single stable value for the function pointer associated with
194 // indices/counts in the formatting infrastructure.
195 //
196 // Note that a function defined as such would not be correct as functions are
197 // always tagged unnamed_addr with the current lowering to LLVM IR, so their
198 // address is not considered important to LLVM and as such the as_usize cast
199 // could have been miscompiled. In practice, we never call as_usize on non-usize
200 // containing data (as a matter of static generation of the formatting
201 // arguments), so this is merely an additional check.
202 //
203 // We primarily want to ensure that the function pointer at `USIZE_MARKER` has
204 // an address corresponding *only* to functions that also take `&usize` as their
205 // first argument. The read_volatile here ensures that we can safely ready out a
206 // usize from the passed reference and that this address does not point at a
207 // non-usize taking function.
208 static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| {
209     // SAFETY: ptr is a reference
210     let _v: usize = unsafe { crate::ptr::read_volatile(ptr) };
211     loop {}
212 };
213