55
66use super :: * ;
77use crate :: hint:: unreachable_unchecked;
8+ use crate :: ptr:: NonNull ;
89
910#[ lang = "format_placeholder" ]
1011#[ derive( Copy , Clone ) ]
@@ -65,8 +66,11 @@ pub(super) enum Flag {
6566}
6667
6768#[ 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+ } ,
7074 Count ( usize ) ,
7175}
7276
@@ -83,28 +87,21 @@ enum ArgumentType<'a> {
8387#[ lang = "format_argument" ]
8488#[ derive( Copy , Clone ) ]
8589pub struct Argument < ' a > {
86- ty : ArgumentType < ' a > ,
90+ ty : ArgumentType ,
91+ _lifetime : PhantomData < & ' a ( ) > ,
8792}
8893
8994#[ rustc_diagnostic_item = "ArgumentMethods" ]
9095impl < ' a > Argument < ' a > {
9196 #[ inline( always) ]
9297 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 ,
108105 }
109106 }
110107
@@ -146,7 +143,7 @@ impl<'a> Argument<'a> {
146143 }
147144 #[ inline( always) ]
148145 pub fn from_usize ( x : & usize ) -> Argument < ' _ > {
149- Argument { ty : ArgumentType :: Count ( * x) }
146+ Argument { ty : ArgumentType :: Count ( * x) , _lifetime : PhantomData }
150147 }
151148
152149 /// Format this placeholder argument.
@@ -162,7 +159,14 @@ impl<'a> Argument<'a> {
162159 #[ inline( always) ]
163160 pub ( super ) unsafe fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result {
164161 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) } ,
166170 // SAFETY: the caller promised this.
167171 ArgumentType :: Count ( _) => unsafe { unreachable_unchecked ( ) } ,
168172 }
@@ -208,7 +212,3 @@ impl UnsafeArg {
208212 Self { _private : ( ) }
209213 }
210214}
211-
212- extern "C" {
213- type Opaque ;
214- }
0 commit comments