From 8af3c26ae65a729d5e953baa620c2e00afdad5ce Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 26 Mar 2026 10:54:41 +1100 Subject: [PATCH 1/3] Add some size assertions for `List`/`RawList`. These will be augmented in the next commit. --- compiler/rustc_middle/src/ty/list.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 82c23abefce45..79dfeb2b44964 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -310,3 +310,14 @@ impl<'tcx> From>> 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, 8); + static_assert_size!(&RawList, 8); + // tidy-alphabetical-end +} From da42dc0cb707a89f63f60737d60527059345dc66 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 26 Mar 2026 10:54:28 +1100 Subject: [PATCH 2/3] Remove `OpaqueListContents`. `RawList::opaque` has type `OpaqueListContents`, which is commented thusly: > A dummy type used to force `List` to be unsized while not requiring > references to it be wide pointers. The first part is true: it does make `List` unsized. This is a little annoying at times, requiring special handling. The second part is false: `&List` is a narrow pointer whether the `opaque` field is present or not. This commit removes `RawList::opaque` and `OpaqueListContents`. Consequences: - `List`/`RawList` are now sized and we can add size assertions. - The `Erasable` impls for `&List`/`&ListWithCachedTypeInfo` are no longer necessary, because the impl for `&T` now covers them. - The unsafe `DynSync` and `Aligned` impls can be removed. - The `ptr_alignment_type` feature is no longer needed by `rustc_middle`. --- compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_middle/src/query/erase.rs | 8 ------- compiler/rustc_middle/src/ty/list.rs | 27 +++++------------------- 3 files changed, 5 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index c8702c42c47f6..ce8300331b846 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -45,7 +45,6 @@ #![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] -#![feature(ptr_alignment_type)] #![feature(range_bounds_is_empty)] #![feature(rustc_attrs)] #![feature(sized_hierarchy)] diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 81c3c7baa07af..409f0ff2c37dd 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -119,14 +119,6 @@ impl Erasable for &'_ [T] { type Storage = [u8; size_of::<&'_ [()]>()]; } -impl Erasable for &'_ ty::List { - type Storage = [u8; size_of::<&'_ ty::List<()>>()]; -} - -impl Erasable for &'_ ty::ListWithCachedTypeInfo { - type Storage = [u8; size_of::<&'_ ty::ListWithCachedTypeInfo<()>>()]; -} - impl Erasable for Result<&'_ T, traits::query::NoSolution> { type Storage = [u8; size_of::>()]; } diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 79dfeb2b44964..cb2c429e019a1 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -4,8 +4,7 @@ use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::{fmt, iter, mem, ptr, slice}; -use rustc_data_structures::aligned::{Aligned, align_of}; -use rustc_data_structures::sync::DynSync; +use rustc_data_structures::aligned::align_of; use rustc_serialize::{Encodable, Encoder}; use rustc_type_ir::FlagComputation; @@ -37,7 +36,6 @@ pub type List = RawList<(), T>; #[repr(C)] pub struct RawList { skel: ListSkeleton, - opaque: OpaqueListContents, } /// A [`RawList`] without the unsized tail. This type is used for layout computation @@ -57,12 +55,6 @@ impl Default for &List { } } -unsafe extern "C" { - /// A dummy type used to force `List` to be unsized while not requiring - /// references to it be wide pointers. - type OpaqueListContents; -} - impl RawList { #[inline(always)] pub fn len(&self) -> usize { @@ -257,19 +249,6 @@ impl<'a, H, T: Copy> IntoIterator for &'a RawList { unsafe impl Sync for RawList {} -// We need this since `List` uses extern type `OpaqueListContents`. -unsafe impl DynSync for RawList {} - -// Safety: -// Layouts of `ListSkeleton` and `RawList` are the same, modulo opaque tail, -// thus aligns of `ListSkeleton` and `RawList` must be the same. -unsafe impl Aligned for RawList { - #[cfg(bootstrap)] - const ALIGN: ptr::Alignment = align_of::>(); - #[cfg(not(bootstrap))] - const ALIGN: mem::Alignment = align_of::>(); -} - /// A [`List`] that additionally stores type information inline to speed up /// [`TypeVisitableExt`](super::TypeVisitableExt) operations. pub type ListWithCachedTypeInfo = RawList; @@ -319,5 +298,9 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(&List, 8); static_assert_size!(&RawList, 8); + static_assert_size!(List, 8); + static_assert_size!(List, 8); + static_assert_size!(RawList, 16); + static_assert_size!(RawList, 16); // tidy-alphabetical-end } From 25f7a588b84fd2da7db4b620bf06a1d3140daaff Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 26 Mar 2026 11:48:13 +1100 Subject: [PATCH 3/3] Merge `ListSkeleton` into `RawList`. They now have identical layout, so we don't need both. --- compiler/rustc_middle/src/ty/list.rs | 33 +++++++++++----------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index cb2c429e019a1..cb3d0e92796e4 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -35,13 +35,6 @@ pub type List = RawList<(), T>; /// [`Hash`] and [`Encodable`]. #[repr(C)] pub struct RawList { - skel: ListSkeleton, -} - -/// A [`RawList`] without the unsized tail. This type is used for layout computation -/// and constructing empty lists. -#[repr(C)] -struct ListSkeleton { header: H, len: usize, /// Although this claims to be a zero-length array, in practice `len` @@ -58,7 +51,7 @@ impl Default for &List { impl RawList { #[inline(always)] pub fn len(&self) -> usize { - self.skel.len + self.len } #[inline(always)] @@ -89,18 +82,18 @@ impl RawList { assert!(!slice.is_empty()); let (layout, _offset) = - Layout::new::>().extend(Layout::for_value::<[T]>(slice)).unwrap(); + Layout::new::>().extend(Layout::for_value::<[T]>(slice)).unwrap(); let mem = arena.dropless.alloc_raw(layout) as *mut RawList; unsafe { // Write the header - (&raw mut (*mem).skel.header).write(header); + (&raw mut (*mem).header).write(header); // Write the length - (&raw mut (*mem).skel.len).write(slice.len()); + (&raw mut (*mem).len).write(slice.len()); // Write the elements - (&raw mut (*mem).skel.data) + (&raw mut (*mem).data) .cast::() .copy_from_nonoverlapping(slice.as_ptr(), slice.len()); @@ -144,8 +137,8 @@ macro_rules! impl_list_empty { #[repr(align(64))] struct MaxAlign; - static EMPTY: ListSkeleton<$header_ty, MaxAlign> = - ListSkeleton { header: $header_init, len: 0, data: [] }; + static EMPTY: RawList<$header_ty, MaxAlign> = + RawList { header: $header_init, len: 0, data: [] }; assert!(align_of::() <= align_of::()); @@ -229,12 +222,12 @@ impl Deref for RawList { impl AsRef<[T]> for RawList { #[inline(always)] fn as_ref(&self) -> &[T] { - let data_ptr = (&raw const self.skel.data).cast::(); + let data_ptr = (&raw const self.data).cast::(); // SAFETY: `data_ptr` has the same provenance as `self` and can therefore - // access the `self.skel.len` elements stored at `self.skel.data`. - // Note that we specifically don't reborrow `&self.skel.data`, because that + // access the `self.len` elements stored at `self.data`. + // Note that we specifically don't reborrow `&self.data`, because that // would give us a pointer with provenance over 0 bytes. - unsafe { slice::from_raw_parts(data_ptr, self.skel.len) } + unsafe { slice::from_raw_parts(data_ptr, self.len) } } } @@ -256,12 +249,12 @@ pub type ListWithCachedTypeInfo = RawList; impl ListWithCachedTypeInfo { #[inline(always)] pub fn flags(&self) -> TypeFlags { - self.skel.header.flags + self.header.flags } #[inline(always)] pub fn outer_exclusive_binder(&self) -> DebruijnIndex { - self.skel.header.outer_exclusive_binder + self.header.outer_exclusive_binder } }