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