From 074faae56a13e1db9dfdc81898e08a168899c742 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 | 48 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 92626feabf3d7..4b303e43b14b7 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,28 +87,21 @@ 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"] impl<'a> Argument<'a> { #[inline(always)] fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { - // SAFETY: `mem::transmute(x)` is safe because - // 1. `&'b T` keeps the lifetime it originated with `'b` - // (so as to not have an unbounded lifetime) - // 2. `&'b T` and `&'b Opaque` have the same memory layout - // (when `T` is `Sized`, as it is here) - // `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 +143,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 +159,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 +212,3 @@ impl UnsafeArg { Self { _private: () } } } - -extern "C" { - type Opaque; -}