Skip to content

Commit a514b83

Browse files
committed
core: avoid extern types in formatting infrastructure
1 parent d929a42 commit a514b83

File tree

1 file changed

+24
-16
lines changed
  • library/core/src/fmt

1 file changed

+24
-16
lines changed

library/core/src/fmt/rt.rs

+24-16
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
use super::*;
77
use 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,7 +87,8 @@ enum ArgumentType<'a> {
8387
#[lang = "format_argument"]
8488
#[derive(Copy, Clone)]
8589
pub struct Argument<'a> {
86-
ty: ArgumentType<'a>,
90+
ty: ArgumentType,
91+
_lifetime: PhantomData<&'a ()>,
8792
}
8893

8994
#[rustc_diagnostic_item = "ArgumentMethods"]
@@ -98,13 +103,13 @@ impl<'a> Argument<'a> {
98103
// `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
99104
// and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
100105
// (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-
}
106+
Argument {
107+
ty: ArgumentType::Placeholder {
108+
value: NonNull::from(x).cast(),
109+
// SAFETY: function pointers always have the same layout.
110+
formatter: unsafe { mem::transmute(f) },
111+
},
112+
_lifetime: PhantomData,
108113
}
109114
}
110115

@@ -146,7 +151,7 @@ impl<'a> Argument<'a> {
146151
}
147152
#[inline(always)]
148153
pub fn from_usize(x: &usize) -> Argument<'_> {
149-
Argument { ty: ArgumentType::Count(*x) }
154+
Argument { ty: ArgumentType::Count(*x), _lifetime: PhantomData }
150155
}
151156

152157
/// Format this placeholder argument.
@@ -162,7 +167,14 @@ impl<'a> Argument<'a> {
162167
#[inline(always)]
163168
pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
164169
match self.ty {
165-
ArgumentType::Placeholder { formatter, value } => formatter(value, f),
170+
// SAFETY:
171+
// `Argument` is constructed so that if `formatter` originally had
172+
// the type `fn(&T, ...)` then `value` has type `&T`. Since we use
173+
// `value` within the lifetime 'a of the reference and references
174+
// and `NonNull` are ABI-compatible, this is completely equivalent
175+
// to calling the original function passed to `new` with the original
176+
// reference, which is always sound.
177+
ArgumentType::Placeholder { formatter, value } => unsafe { formatter(value, f) },
166178
// SAFETY: the caller promised this.
167179
ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
168180
}
@@ -208,7 +220,3 @@ impl UnsafeArg {
208220
Self { _private: () }
209221
}
210222
}
211-
212-
extern "C" {
213-
type Opaque;
214-
}

0 commit comments

Comments
 (0)