5
5
6
6
use super :: * ;
7
7
use crate :: hint:: unreachable_unchecked;
8
+ use crate :: ptr:: NonNull ;
8
9
9
10
#[ lang = "format_placeholder" ]
10
11
#[ derive( Copy , Clone ) ]
@@ -65,8 +66,11 @@ pub(super) enum Flag {
65
66
}
66
67
67
68
#[ derive( Copy , Clone ) ]
68
- enum ArgumentType < ' a > {
69
- Placeholder { value : & ' a Opaque , formatter : fn ( & Opaque , & mut Formatter < ' _ > ) -> Result } ,
69
+ enum ArgumentType {
70
+ Placeholder {
71
+ value : NonNull < ( ) > ,
72
+ formatter : unsafe fn ( NonNull < ( ) > , & mut Formatter < ' _ > ) -> Result ,
73
+ } ,
70
74
Count ( usize ) ,
71
75
}
72
76
@@ -83,28 +87,21 @@ enum ArgumentType<'a> {
83
87
#[ lang = "format_argument" ]
84
88
#[ derive( Copy , Clone ) ]
85
89
pub struct Argument < ' a > {
86
- ty : ArgumentType < ' a > ,
90
+ ty : ArgumentType ,
91
+ _lifetime : PhantomData < & ' a ( ) > ,
87
92
}
88
93
89
94
#[ rustc_diagnostic_item = "ArgumentMethods" ]
90
95
impl < ' a > Argument < ' a > {
91
96
#[ inline( always) ]
92
97
fn new < ' b , T > ( x : & ' b T , f : fn ( & T , & mut Formatter < ' _ > ) -> Result ) -> Argument < ' b > {
93
- // SAFETY: `mem::transmute(x)` is safe because
94
- // 1. `&'b T` keeps the lifetime it originated with `'b`
95
- // (so as to not have an unbounded lifetime)
96
- // 2. `&'b T` and `&'b Opaque` have the same memory layout
97
- // (when `T` is `Sized`, as it is here)
98
- // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
99
- // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
100
- // (as long as `T` is `Sized`)
101
- unsafe {
102
- Argument {
103
- ty : ArgumentType :: Placeholder {
104
- formatter : mem:: transmute ( f) ,
105
- value : mem:: transmute ( x) ,
106
- } ,
107
- }
98
+ Argument {
99
+ ty : ArgumentType :: Placeholder {
100
+ value : NonNull :: from ( x) . cast ( ) ,
101
+ // SAFETY: function pointers always have the same layout.
102
+ formatter : unsafe { mem:: transmute ( f) } ,
103
+ } ,
104
+ _lifetime : PhantomData ,
108
105
}
109
106
}
110
107
@@ -146,7 +143,7 @@ impl<'a> Argument<'a> {
146
143
}
147
144
#[ inline( always) ]
148
145
pub fn from_usize ( x : & usize ) -> Argument < ' _ > {
149
- Argument { ty : ArgumentType :: Count ( * x) }
146
+ Argument { ty : ArgumentType :: Count ( * x) , _lifetime : PhantomData }
150
147
}
151
148
152
149
/// Format this placeholder argument.
@@ -162,7 +159,14 @@ impl<'a> Argument<'a> {
162
159
#[ inline( always) ]
163
160
pub ( super ) unsafe fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result {
164
161
match self . ty {
165
- ArgumentType :: Placeholder { formatter, value } => formatter ( value, f) ,
162
+ // SAFETY:
163
+ // `Argument` is constructed so that if `formatter` originally had
164
+ // the type `fn(&T, ...)` then `value` has type `&T`. Since we use
165
+ // `value` within the lifetime 'a of the reference and references
166
+ // and `NonNull` are ABI-compatible, this is completely equivalent
167
+ // to calling the original function passed to `new` with the original
168
+ // reference, which is always sound.
169
+ ArgumentType :: Placeholder { formatter, value } => unsafe { formatter ( value, f) } ,
166
170
// SAFETY: the caller promised this.
167
171
ArgumentType :: Count ( _) => unsafe { unreachable_unchecked ( ) } ,
168
172
}
@@ -208,7 +212,3 @@ impl UnsafeArg {
208
212
Self { _private : ( ) }
209
213
}
210
214
}
211
-
212
- extern "C" {
213
- type Opaque ;
214
- }
0 commit comments