5
5
6
6
use super :: * ;
7
7
use crate :: hint:: unreachable_unchecked;
8
- use crate :: ptr:: NonNull ;
9
8
10
9
#[ lang = "format_placeholder" ]
11
10
#[ derive( Copy , Clone ) ]
@@ -37,15 +36,13 @@ pub enum Count {
37
36
Implied ,
38
37
}
39
38
39
+ trait FormatThunk {
40
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result ;
41
+ }
42
+
40
43
#[ derive( Copy , Clone ) ]
41
44
enum ArgumentType < ' a > {
42
- Placeholder {
43
- // INVARIANT: `formatter` has type `fn(&T, _) -> _` for some `T`, and `value`
44
- // was derived from a `&'a T`.
45
- value : NonNull < ( ) > ,
46
- formatter : unsafe fn ( NonNull < ( ) > , & mut Formatter < ' _ > ) -> Result ,
47
- _lifetime : PhantomData < & ' a ( ) > ,
48
- } ,
45
+ Placeholder ( & ' a dyn FormatThunk ) ,
49
46
Count ( u16 ) ,
50
47
}
51
48
@@ -65,62 +62,61 @@ pub struct Argument<'a> {
65
62
ty : ArgumentType < ' a > ,
66
63
}
67
64
65
+ macro_rules! define_argument_constructor {
66
+ ( $method: ident, $trait: ident, $fmt: item) => {
67
+ #[ inline]
68
+ pub fn $method<T : $trait>( x: & T ) -> Argument <' _> {
69
+ #[ repr( transparent) ]
70
+ struct Wrapper <T >( T ) ;
71
+
72
+ // SAFETY: `Wrapper<T>` has the same memory layout as `T` due to #[repr(transparent)].
73
+ let thunk = unsafe { mem:: transmute:: <& T , & Wrapper <T >>( x) } ;
74
+
75
+ impl <T : $trait> FormatThunk for Wrapper <T > {
76
+ #[ inline]
77
+ $fmt
78
+ }
79
+
80
+ Self :: new( thunk)
81
+ }
82
+ } ;
83
+
84
+ ( $method: ident, $trait: ident) => {
85
+ define_argument_constructor!(
86
+ $method,
87
+ $trait,
88
+ fn fmt( & self , f: & mut Formatter <' _>) -> Result {
89
+ let Self ( inner) = self ;
90
+ inner. fmt( f)
91
+ }
92
+ ) ;
93
+ } ;
94
+ }
95
+
68
96
#[ rustc_diagnostic_item = "ArgumentMethods" ]
69
97
impl Argument < ' _ > {
70
98
#[ inline]
71
- const fn new < ' a , T > ( x : & ' a T , f : fn ( & T , & mut Formatter < ' _ > ) -> Result ) -> Argument < ' a > {
72
- Argument {
73
- // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and
74
- // a `fn(&T, ...)`, so the invariant is maintained.
75
- ty : ArgumentType :: Placeholder {
76
- value : NonNull :: from_ref ( x) . cast ( ) ,
77
- // SAFETY: function pointers always have the same layout.
78
- formatter : unsafe { mem:: transmute ( f) } ,
79
- _lifetime : PhantomData ,
80
- } ,
81
- }
99
+ fn new < ' a > ( x : & ' a dyn FormatThunk ) -> Argument < ' a > {
100
+ Argument { ty : ArgumentType :: Placeholder ( x) }
82
101
}
83
102
84
- #[ inline]
85
- pub fn new_display < T : Display > ( x : & T ) -> Argument < ' _ > {
86
- Self :: new ( x, Display :: fmt)
87
- }
88
- #[ inline]
89
- pub fn new_debug < T : Debug > ( x : & T ) -> Argument < ' _ > {
90
- Self :: new ( x, Debug :: fmt)
91
- }
92
- #[ inline]
93
- pub fn new_debug_noop < T : Debug > ( x : & T ) -> Argument < ' _ > {
94
- Self :: new ( x, |_, _| Ok ( ( ) ) )
95
- }
96
- #[ inline]
97
- pub fn new_octal < T : Octal > ( x : & T ) -> Argument < ' _ > {
98
- Self :: new ( x, Octal :: fmt)
99
- }
100
- #[ inline]
101
- pub fn new_lower_hex < T : LowerHex > ( x : & T ) -> Argument < ' _ > {
102
- Self :: new ( x, LowerHex :: fmt)
103
- }
104
- #[ inline]
105
- pub fn new_upper_hex < T : UpperHex > ( x : & T ) -> Argument < ' _ > {
106
- Self :: new ( x, UpperHex :: fmt)
107
- }
108
- #[ inline]
109
- pub fn new_pointer < T : Pointer > ( x : & T ) -> Argument < ' _ > {
110
- Self :: new ( x, Pointer :: fmt)
111
- }
112
- #[ inline]
113
- pub fn new_binary < T : Binary > ( x : & T ) -> Argument < ' _ > {
114
- Self :: new ( x, Binary :: fmt)
115
- }
116
- #[ inline]
117
- pub fn new_lower_exp < T : LowerExp > ( x : & T ) -> Argument < ' _ > {
118
- Self :: new ( x, LowerExp :: fmt)
119
- }
120
- #[ inline]
121
- pub fn new_upper_exp < T : UpperExp > ( x : & T ) -> Argument < ' _ > {
122
- Self :: new ( x, UpperExp :: fmt)
123
- }
103
+ define_argument_constructor ! ( new_display, Display ) ;
104
+ define_argument_constructor ! ( new_debug, Debug ) ;
105
+ define_argument_constructor ! (
106
+ new_debug_noop,
107
+ Debug ,
108
+ fn fmt( & self , _: & mut Formatter <' _>) -> Result {
109
+ Ok ( ( ) )
110
+ }
111
+ ) ;
112
+ define_argument_constructor ! ( new_octal, Octal ) ;
113
+ define_argument_constructor ! ( new_lower_hex, LowerHex ) ;
114
+ define_argument_constructor ! ( new_upper_hex, UpperHex ) ;
115
+ define_argument_constructor ! ( new_pointer, Pointer ) ;
116
+ define_argument_constructor ! ( new_binary, Binary ) ;
117
+ define_argument_constructor ! ( new_lower_exp, LowerExp ) ;
118
+ define_argument_constructor ! ( new_upper_exp, UpperExp ) ;
119
+
124
120
#[ inline]
125
121
#[ track_caller]
126
122
pub const fn from_usize ( x : & usize ) -> Argument < ' _ > {
@@ -135,22 +131,10 @@ impl Argument<'_> {
135
131
/// # Safety
136
132
///
137
133
/// This argument must actually be a placeholder argument.
138
- ///
139
- // FIXME: Transmuting formatter in new and indirectly branching to/calling
140
- // it here is an explicit CFI violation.
141
- #[ allow( inline_no_sanitize) ]
142
- #[ no_sanitize( cfi, kcfi) ]
143
134
#[ inline]
144
135
pub ( super ) unsafe fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result {
145
136
match self . ty {
146
- // SAFETY:
147
- // Because of the invariant that if `formatter` had the type
148
- // `fn(&T, _) -> _` then `value` has type `&'b T` where `'b` is
149
- // the lifetime of the `ArgumentType`, and because references
150
- // and `NonNull` are ABI-compatible, this is completely equivalent
151
- // to calling the original function passed to `new` with the
152
- // original reference, which is sound.
153
- ArgumentType :: Placeholder { formatter, value, .. } => unsafe { formatter ( value, f) } ,
137
+ ArgumentType :: Placeholder ( thunk) => thunk. fmt ( f) ,
154
138
// SAFETY: the caller promised this.
155
139
ArgumentType :: Count ( _) => unsafe { unreachable_unchecked ( ) } ,
156
140
}
0 commit comments