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