Skip to content

Commit 074faae

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

File tree

1 file changed

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

1 file changed

+24
-24
lines changed

library/core/src/fmt/rt.rs

+24-24
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,28 +87,21 @@ 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"]
9095
impl<'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

Comments
 (0)