Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions compiler/rustc_middle/src/query/erase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,6 @@ pub fn restore_val<T: Erasable>(erased_value: Erased<T>) -> T {
unsafe { transmute_unchecked::<MaybeUninit<T::Storage>, T>(data) }
}

// FIXME(#151565): Using `T: ?Sized` here should let us remove the separate
// impls for fat reference types.
Comment on lines -112 to -113
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I was thinking we could replace size_of::<&'_ ()>() with size_of::<&'_ T>() and just get the correct size automatically, but that appears to not actually work smoothly since it then complains about needing #![feature(generic_const_exprs)].

So removing this FIXME is probably the right call.

impl<T> Erasable for &'_ T {
type Storage = [u8; size_of::<&'_ ()>()];
}
Expand All @@ -119,12 +117,14 @@ impl<T> Erasable for &'_ [T] {
type Storage = [u8; size_of::<&'_ [()]>()];
}

impl<T> Erasable for &'_ ty::List<T> {
type Storage = [u8; size_of::<&'_ ty::List<()>>()];
}

impl<T> Erasable for &'_ ty::ListWithCachedTypeInfo<T> {
type Storage = [u8; size_of::<&'_ ty::ListWithCachedTypeInfo<()>>()];
// Note: this impl does not overlap with the impl for `&'_ T` above because `RawList` is unsized
// and does not satisfy the implicit `T: Sized` bound.
//
// Furthermore, even if that implicit bound was removed (by adding `T: ?Sized`) this impl still
// wouldn't overlap because `?Sized` is equivalent to `MetaSized` and `RawList` does not satisfy
// `MetaSized` because it contains an extern type.
impl<H, T> Erasable for &'_ ty::RawList<H, T> {
type Storage = [u8; size_of::<&'_ ty::RawList<(), ()>>()];
}

impl<T> Erasable for Result<&'_ T, traits::query::NoSolution> {
Expand Down
38 changes: 30 additions & 8 deletions compiler/rustc_middle/src/ty/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,18 @@ pub type List<T> = RawList<(), T>;
#[repr(C)]
pub struct RawList<H, T> {
skel: ListSkeleton<H, T>,
opaque: OpaqueListContents,

// `List`/`RawList` is variable-sized. So we want it to be an unsized
// type because calling `size_of::<List<Foo>>` would be dangerous.
//
// We also want `&List`/`&RawList` to be thin pointers.
//
// A field with an extern type is a hacky way to achieve this. (See
// https://github.com/rust-lang/rust/pull/154399#issuecomment-4157036415
// for some discussion.) This field is never directly manipulated because
// `RawList` instances are created with manual memory layout in
// `from_arena`.
_extern_ty: ExternTy,
}

/// A [`RawList`] without the unsized tail. This type is used for layout computation
Expand All @@ -47,7 +58,8 @@ struct ListSkeleton<H, T> {
header: H,
len: usize,
/// Although this claims to be a zero-length array, in practice `len`
/// elements are actually present.
/// elements are actually present. This is achieved with manual memory
/// layout in `from_arena`. See also the comment on `RawList::_extern_ty`.
data: [T; 0],
}

Expand All @@ -58,9 +70,7 @@ impl<T> Default for &List<T> {
}

unsafe extern "C" {
/// A dummy type used to force `List` to be unsized while not requiring
/// references to it be wide pointers.
type OpaqueListContents;
type ExternTy;
}

impl<H, T> RawList<H, T> {
Expand Down Expand Up @@ -257,12 +267,13 @@ impl<'a, H, T: Copy> IntoIterator for &'a RawList<H, T> {

unsafe impl<H: Sync, T: Sync> Sync for RawList<H, T> {}

// We need this since `List` uses extern type `OpaqueListContents`.
// We need this because `List` uses the extern type `ExternTy`.
unsafe impl<H: DynSync, T: DynSync> DynSync for RawList<H, T> {}

// Safety:
// Layouts of `ListSkeleton<H, T>` and `RawList<H, T>` are the same, modulo opaque tail,
// thus aligns of `ListSkeleton<H, T>` and `RawList<H, T>` must be the same.
// Layouts of `ListSkeleton<H, T>` and `RawList<H, T>` are the same, modulo the
// `_extern_ty` field (which is never instantiated in practice). Therefore,
// aligns of `ListSkeleton<H, T>` and `RawList<H, T>` must be the same.
unsafe impl<H, T> Aligned for RawList<H, T> {
#[cfg(bootstrap)]
const ALIGN: ptr::Alignment = align_of::<ListSkeleton<H, T>>();
Expand Down Expand Up @@ -310,3 +321,14 @@ impl<'tcx> From<FlagComputation<TyCtxt<'tcx>>> for TypeInfo {
}
}
}

#[cfg(target_pointer_width = "64")]
mod size_asserts {
use rustc_data_structures::static_assert_size;

use super::*;
// tidy-alphabetical-start
static_assert_size!(&List<u32>, 8); // thin pointer
static_assert_size!(&RawList<u8, u32>, 8); // thin pointer
// tidy-alphabetical-end
}
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pub use self::context::{
};
pub use self::fold::*;
pub use self::instance::{Instance, InstanceKind, ReifyReason};
pub(crate) use self::list::RawList;
pub use self::list::{List, ListWithCachedTypeInfo};
pub use self::opaque_types::OpaqueTypeKey;
pub use self::pattern::{Pattern, PatternKind};
Expand Down
Loading