Skip to content

Commit

Permalink
core: avoid extern types in formatting infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
joboet committed Jun 25, 2024
1 parent d929a42 commit a514b83
Showing 1 changed file with 24 additions and 16 deletions.
40 changes: 24 additions & 16 deletions library/core/src/fmt/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use super::*;
use crate::hint::unreachable_unchecked;
use crate::ptr::NonNull;

#[lang = "format_placeholder"]
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -65,8 +66,11 @@ pub(super) enum Flag {
}

#[derive(Copy, Clone)]
enum ArgumentType<'a> {
Placeholder { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result },
enum ArgumentType {
Placeholder {
value: NonNull<()>,
formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result,
},
Count(usize),
}

Expand All @@ -83,7 +87,8 @@ enum ArgumentType<'a> {
#[lang = "format_argument"]
#[derive(Copy, Clone)]
pub struct Argument<'a> {
ty: ArgumentType<'a>,
ty: ArgumentType,
_lifetime: PhantomData<&'a ()>,
}

#[rustc_diagnostic_item = "ArgumentMethods"]
Expand All @@ -98,13 +103,13 @@ impl<'a> Argument<'a> {
// `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result`
// and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI
// (as long as `T` is `Sized`)
unsafe {
Argument {
ty: ArgumentType::Placeholder {
formatter: mem::transmute(f),
value: mem::transmute(x),
},
}
Argument {
ty: ArgumentType::Placeholder {
value: NonNull::from(x).cast(),
// SAFETY: function pointers always have the same layout.
formatter: unsafe { mem::transmute(f) },
},
_lifetime: PhantomData,
}
}

Expand Down Expand Up @@ -146,7 +151,7 @@ impl<'a> Argument<'a> {
}
#[inline(always)]
pub fn from_usize(x: &usize) -> Argument<'_> {
Argument { ty: ArgumentType::Count(*x) }
Argument { ty: ArgumentType::Count(*x), _lifetime: PhantomData }
}

/// Format this placeholder argument.
Expand All @@ -162,7 +167,14 @@ impl<'a> Argument<'a> {
#[inline(always)]
pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self.ty {
ArgumentType::Placeholder { formatter, value } => formatter(value, f),
// SAFETY:
// `Argument` is constructed so that if `formatter` originally had
// the type `fn(&T, ...)` then `value` has type `&T`. Since we use
// `value` within the lifetime 'a of the reference and references
// and `NonNull` are ABI-compatible, this is completely equivalent
// to calling the original function passed to `new` with the original
// reference, which is always sound.
ArgumentType::Placeholder { formatter, value } => unsafe { formatter(value, f) },
// SAFETY: the caller promised this.
ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
}
Expand Down Expand Up @@ -208,7 +220,3 @@ impl UnsafeArg {
Self { _private: () }
}
}

extern "C" {
type Opaque;
}

0 comments on commit a514b83

Please sign in to comment.