From a514b8315e02f842782f4c5d9c88347e3f17f8ec Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 25 Jun 2024 19:50:04 +0200 Subject: [PATCH] core: avoid `extern type`s in formatting infrastructure --- library/core/src/fmt/rt.rs | 40 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 92626feabf3d7..debed12308d18 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -5,6 +5,7 @@ use super::*; use crate::hint::unreachable_unchecked; +use crate::ptr::NonNull; #[lang = "format_placeholder"] #[derive(Copy, Clone)] @@ -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), } @@ -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"] @@ -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, } } @@ -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. @@ -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() }, } @@ -208,7 +220,3 @@ impl UnsafeArg { Self { _private: () } } } - -extern "C" { - type Opaque; -}