diff --git a/src/lifetime_expansion.rs b/src/lifetime_expansion.rs index 867b643..fc1b6ca 100644 --- a/src/lifetime_expansion.rs +++ b/src/lifetime_expansion.rs @@ -30,7 +30,6 @@ pub const fn lifetime_translator<'a, 'b, T>(_val_a: &'a &'b (), val_b: &'b T) -> } /// This does the same thing as [`lifetime_translator`], just for mutable refs. -#[inline(never)] pub fn lifetime_translator_mut<'a, 'b, T>(_val_a: &'a &'b (), val_b: &'b mut T) -> &'a mut T { val_b } diff --git a/src/transmute.rs b/src/transmute.rs index 2d12261..572cef9 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -22,9 +22,8 @@ /// # Safety /// lol /// +#[allow(unused_assignments)] pub fn transmute(obj: A) -> B { - use std::hint::black_box; - // The layout of `DummyEnum` is approximately // DummyEnum { // is_a_or_b: u8, @@ -34,23 +33,22 @@ pub fn transmute(obj: A) -> B { // This should hopefully be more reliable than spamming the stack with a value and hoping the memory // is placed correctly by the compiler. enum DummyEnum { - A(Option>), - B(Option>), + A(Result>>), + B(Result>>), } - #[inline(never)] - fn transmute_inner(dummy: &mut DummyEnum, obj: A) -> B { - let DummyEnum::B(ref_to_b) = dummy else { - unreachable!() - }; - let ref_to_b = crate::lifetime_expansion::expand_mut(ref_to_b); - *dummy = DummyEnum::A(Some(Box::new(obj))); - black_box(dummy); - - *ref_to_b.take().unwrap() + union Blank { + _a: std::mem::ManuallyDrop, + _b: std::mem::ManuallyDrop, } - transmute_inner(black_box(&mut DummyEnum::B(None)), obj) + let mut res = DummyEnum::B(Err(None)); + let DummyEnum::B(ref_to_b) = &mut res else { + unreachable!() + }; + let ref_to_b = crate::lifetime_expansion::expand_mut(ref_to_b); + res = DummyEnum::A(Ok(obj)); + std::mem::replace(ref_to_b, Err(None)).ok().unwrap() } #[cfg(test)]