1#![allow(missing_debug_implementations)]
2#![unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
34//! All types and methods in this file are used by the compiler in
5//! the expansion/lowering of format_args!().
6//!
7//! Do not modify them without understanding the consequences for the format_args!() macro.
89use super::*;
10use crate::hint::unreachable_unchecked;
11use crate::ptr::NonNull;
1213#[derive(#[automatically_derived]
impl<'a> crate::marker::Copy for ArgumentType<'a> { }Copy, #[automatically_derived]
impl<'a> crate::clone::Clone for ArgumentType<'a> {
#[inline]
fn clone(&self) -> ArgumentType<'a> {
let _: crate::clone::AssertParamIsClone<NonNull<()>>;
let _:
crate::clone::AssertParamIsClone<unsafe fn(NonNull<()>,
&mut Formatter<'_>) -> Result>;
let _: crate::clone::AssertParamIsClone<PhantomData<&'a ()>>;
let _: crate::clone::AssertParamIsClone<u16>;
*self
}
}Clone)]
14enum ArgumentType<'a> {
15 Placeholder {
16// INVARIANT: `formatter` has type `fn(&T, _) -> _` for some `T`, and `value`
17 // was derived from a `&'a T`.
18value: NonNull<()>,
19 formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result,
20 _lifetime: PhantomData<&'a ()>,
21 },
22 Count(u16),
23}
2425/// This struct represents a generic "argument" which is taken by format_args!().
26///
27/// This can be either a placeholder argument or a count argument.
28/// * A placeholder argument contains a function to format the given value. At
29/// compile time it is ensured that the function and the value have the correct
30/// types, and then this struct is used to canonicalize arguments to one type.
31/// Placeholder arguments are essentially an optimized partially applied formatting
32/// function, equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
33/// * A count argument contains a count for dynamic formatting parameters like
34/// precision and width.
35#[lang = "format_argument"]
36#[derive(#[automatically_derived]
impl<'a> crate::marker::Copy for Argument<'a> { }Copy, #[automatically_derived]
impl<'a> crate::clone::Clone for Argument<'a> {
#[inline]
fn clone(&self) -> Argument<'a> {
let _: crate::clone::AssertParamIsClone<ArgumentType<'a>>;
*self
}
}Clone)]
37#[repr(align(2))] // To ensure pointers to this struct always have their lowest bit cleared.
38pub struct Argument<'a> {
39 ty: ArgumentType<'a>,
40}
4142macro_rules!argument_new {
43 ($t:ty, $x:expr, $f:expr) => {
44 Argument {
45// INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and
46 // a `fn(&T, ...)`, so the invariant is maintained.
47ty: ArgumentType::Placeholder {
48 value: NonNull::<$t>::from_ref($x).cast(),
49// The Rust ABI considers all pointers to be equivalent, so transmuting a fn(&T) to
50 // fn(NonNull<()>) and calling it with a NonNull<()> that points at a T is allowed.
51 // However, the CFI sanitizer does not allow this, and triggers a crash when it
52 // happens.
53 //
54 // To avoid this crash, we use a helper function when CFI is enabled. To avoid the
55 // cost of this helper function (mainly code-size) when it is not needed, we
56 // transmute the function pointer otherwise.
57 //
58 // This is similar to what the Rust compiler does internally with vtables when KCFI
59 // is enabled, where it generates trampoline functions that only serve to adjust the
60 // expected type of the argument. `ArgumentType::Placeholder` is a bit like a
61 // manually constructed trait object, so it is not surprising that the same approach
62 // has to be applied here as well.
63 //
64 // It is still considered problematic (from the Rust side) that CFI rejects entirely
65 // legal Rust programs, so we do not consider anything done here a stable guarantee,
66 // but meanwhile we carry this work-around to keep Rust compatible with CFI and
67 // KCFI.
68#[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))]
69formatter: {
70let f: fn(&$t, &mut Formatter<'_>) -> Result = $f;
71// SAFETY: This is only called with `value`, which has the right type.
72unsafe { core::mem::transmute(f) }
73 },
74#[cfg(any(sanitize = "cfi", sanitize = "kcfi"))]
75formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| {
76let func = $f;
77// SAFETY: This is the same type as the `value` field.
78let r = unsafe { ptr.cast::<$t>().as_ref() };
79 (func)(r, fmt)
80 },
81 _lifetime: PhantomData,
82 },
83 }
84 };
85}
8687impl Argument<'_> {
88#[inline]
89pub const fn new_display<T: Display>(x: &T) -> Argument<'_> {
90Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result = <T as Display>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as Display>::fmt)91 }
92#[inline]
93pub const fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
94Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result = <T as Debug>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as Debug>::fmt)95 }
96#[inline]
97pub const fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
98Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result = |_: &T, _| Ok(());
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, |_: &T, _| Ok(()))99 }
100#[inline]
101pub const fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
102Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result = <T as Octal>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as Octal>::fmt)103 }
104#[inline]
105pub const fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
106Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result =
<T as LowerHex>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as LowerHex>::fmt)107 }
108#[inline]
109pub const fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
110Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result =
<T as UpperHex>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as UpperHex>::fmt)111 }
112#[inline]
113pub const fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
114Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result = <T as Pointer>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as Pointer>::fmt)115 }
116#[inline]
117pub const fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
118Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result = <T as Binary>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as Binary>::fmt)119 }
120#[inline]
121pub const fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
122Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result =
<T as LowerExp>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as LowerExp>::fmt)123 }
124#[inline]
125pub const fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
126Argument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
formatter: {
let f: fn(&T, &mut Formatter<'_>) -> Result =
<T as UpperExp>::fmt;
unsafe { core::mem::transmute(f) }
},
_lifetime: PhantomData,
},
}argument_new!(T, x, <T as UpperExp>::fmt)127 }
128#[inline]
129 #[track_caller]
130pub const fn from_usize(x: &usize) -> Argument<'_> {
131if *x > u16::MAXas usize {
132{
crate::panicking::panic_fmt(format_args!("Formatting argument out of range"));
};panic!("Formatting argument out of range");
133 }
134Argument { ty: ArgumentType::Count(*xas u16) }
135 }
136137/// Format this placeholder argument.
138 ///
139 /// # Safety
140 ///
141 /// This argument must actually be a placeholder argument.
142#[inline]
143pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
144match self.ty {
145// SAFETY:
146 // Because of the invariant that if `formatter` had the type
147 // `fn(&T, _) -> _` then `value` has type `&'b T` where `'b` is
148 // the lifetime of the `ArgumentType`, and because references
149 // and `NonNull` are ABI-compatible, this is completely equivalent
150 // to calling the original function passed to `new` with the
151 // original reference, which is sound.
152ArgumentType::Placeholder { formatter, value, .. } => unsafe { formatter(value, f) },
153// SAFETY: the caller promised this.
154ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
155 }
156 }
157158#[inline]
159pub(super) const fn as_u16(&self) -> Option<u16> {
160match self.ty {
161 ArgumentType::Count(count) => Some(count),
162 ArgumentType::Placeholder { .. } => None,
163 }
164 }
165}