From 61361bb2129208c67134432f0bb1264749ed7180 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 3 Oct 2023 21:12:23 +0000 Subject: [PATCH 1/3] Use `transmute_unchecked` and make the types explicit in query type erasure This doesn't really change anything, but makes the code a bit more explicit/readable. --- compiler/rustc_middle/src/query/erase.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 8ba3764bcc317..88af3eac6ae99 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -2,7 +2,8 @@ use crate::mir; use crate::query::CyclePlaceholder; use crate::traits; use crate::ty::{self, Ty}; -use std::mem::{size_of, transmute_copy, MaybeUninit}; +use std::mem::{size_of, MaybeUninit}; +use std::intrinsics::transmute_unchecked; #[derive(Copy, Clone)] pub struct Erased { @@ -30,7 +31,7 @@ pub fn erase(src: T) -> Erase { Erased::<::Result> { // SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes. - data: unsafe { transmute_copy(&src) }, + data: unsafe { transmute_unchecked::>(src) }, } } @@ -41,7 +42,7 @@ pub fn restore(value: Erase) -> T { // SAFETY: Due to the use of impl Trait in `Erase` the only way to safely create an instance // of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of // the right size. - unsafe { transmute_copy(&value.data) } + unsafe { transmute_unchecked::, T>(value.data) } } impl EraseType for &'_ T { From b3d50255d9100a5034a7ef350aec29595c020faf Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 3 Oct 2023 21:13:19 +0000 Subject: [PATCH 2/3] Use consisntent style of `size_of` in query type erasure All other impls replace type generics with `()` (or a type implementing the necessery traits) and lifetimes with `'static`, do the same for those impls. --- compiler/rustc_middle/src/query/erase.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 88af3eac6ae99..deefd438c4adb 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -2,8 +2,8 @@ use crate::mir; use crate::query::CyclePlaceholder; use crate::traits; use crate::ty::{self, Ty}; -use std::mem::{size_of, MaybeUninit}; use std::intrinsics::transmute_unchecked; +use std::mem::{size_of, MaybeUninit}; #[derive(Copy, Clone)] pub struct Erased { @@ -46,15 +46,15 @@ pub fn restore(value: Erase) -> T { } impl EraseType for &'_ T { - type Result = [u8; size_of::<*const ()>()]; + type Result = [u8; size_of::<&'static ()>()]; } impl EraseType for &'_ [T] { - type Result = [u8; size_of::<*const [()]>()]; + type Result = [u8; size_of::<&'static [()]>()]; } impl EraseType for &'_ ty::List { - type Result = [u8; size_of::<*const ()>()]; + type Result = [u8; size_of::<&'static ty::List<()>>()]; } impl EraseType for &'_ rustc_index::IndexSlice { From eca9a1533f4bf2848a34723410d9ae2f1e76975d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 7 Nov 2023 20:03:07 +0000 Subject: [PATCH 3/3] Add an explanation for `transmute_unchecked` --- compiler/rustc_middle/src/query/erase.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index deefd438c4adb..b96281b864554 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -30,6 +30,13 @@ pub fn erase(src: T) -> Erase { }; Erased::<::Result> { + // `transmute_unchecked` is needed here because it does not have `transmute`'s size check + // (and thus allows to transmute between `T` and `MaybeUninit`) (we do the size + // check ourselves in the `const` block above). + // + // `transmute_copy` is also commonly used for this (and it would work here since + // `EraseType: Copy`), but `transmute_unchecked` better explains the intent. + // // SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes. data: unsafe { transmute_unchecked::>(src) }, } @@ -39,6 +46,8 @@ pub fn erase(src: T) -> Erase { #[inline(always)] pub fn restore(value: Erase) -> T { let value: Erased<::Result> = value; + // See comment in `erase` for why we use `transmute_unchecked`. + // // SAFETY: Due to the use of impl Trait in `Erase` the only way to safely create an instance // of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of // the right size.