From cefd2f3802e5fc3e5a498a02f66443023e6bd001 Mon Sep 17 00:00:00 2001 From: Lars Schumann Date: Sun, 26 Apr 2026 20:19:06 +0000 Subject: [PATCH 1/3] prefer T::IS_ZST over manual check --- library/alloc/src/boxed/thin.rs | 9 +++++---- library/core/src/iter/adapters/map_windows.rs | 4 ++-- library/core/src/mem/mod.rs | 2 +- .../crates/core_simd/src/simd/ptr/const_ptr.rs | 5 +++-- .../crates/core_simd/src/simd/ptr/mut_ptr.rs | 5 +++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 2a34537f58e31..22c3d89e3ccdb 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -10,7 +10,8 @@ use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] use core::marker::Unsize; #[cfg(not(no_global_oom_handling))] -use core::mem::{self, SizedTypeProperties}; +use core::mem; +use core::mem::SizedTypeProperties; use core::ops::{Deref, DerefMut}; use core::ptr::{self, NonNull, Pointee}; @@ -112,7 +113,7 @@ impl ThinBox { where T: Unsize, { - if size_of::() == 0 { + if T::IS_ZST { let ptr = WithOpaqueHeader::new_unsize_zst::(value); ThinBox { ptr, _marker: PhantomData } } else { @@ -281,7 +282,7 @@ impl WithHeader { let ptr = if layout.size() == 0 { // Some paranoia checking, mostly so that the ThinBox tests are // more able to catch issues. - debug_assert!(value_offset == 0 && size_of::() == 0 && size_of::() == 0); + debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST); layout.dangling_ptr() } else { let ptr = alloc::alloc(layout); @@ -311,7 +312,7 @@ impl WithHeader { Dyn: Pointee + ?Sized, T: Unsize, { - assert!(size_of::() == 0); + assert!(T::IS_ZST); const fn max(a: usize, b: usize) -> usize { if a > b { a } else { b } diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index 097a0745c61c7..5d96de5cbcb6b 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -1,5 +1,5 @@ use crate::iter::FusedIterator; -use crate::mem::MaybeUninit; +use crate::mem::{MaybeUninit, SizedTypeProperties}; use crate::{fmt, ptr}; /// An iterator over the mapped windows of another iterator. @@ -47,7 +47,7 @@ impl MapWindows { assert!(N != 0, "array in `Iterator::map_windows` must contain more than 0 elements"); // Only ZST arrays' length can be so large. - if size_of::() == 0 { + if I::Item::IS_ZST { assert!( N.checked_mul(2).is_some(), "array size of `Iterator::map_windows` is too large" diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 2fbb5842ef778..e8f2d772cf6a6 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1619,7 +1619,7 @@ pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { #[rustc_const_unstable(feature = "mem_conjure_zst", issue = "95383")] pub const unsafe fn conjure_zst() -> T { const_assert!( - size_of::() == 0, + T::IS_ZST, "mem::conjure_zst invoked on a non-zero-sized type", "mem::conjure_zst invoked on type {name}, which is not zero-sized", name: &str = crate::any::type_name::() diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs index 7ef9dc21373ec..183b8c9717239 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -107,8 +107,9 @@ impl SimdConstPtr for Simd<*const T, N> { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. use core::ptr::Pointee; - assert_eq!(size_of::<::Metadata>(), 0); - assert_eq!(size_of::<::Metadata>(), 0); + use core::mem::SizedTypeProperties; + assert!(<::Metadata>::IS_ZST); + assert!(<::Metadata>::IS_ZST); // Safety: pointers can be cast unsafe { core::intrinsics::simd::simd_cast_ptr(self) } diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs index 3b9b75ddf5660..b6d115165d381 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -104,8 +104,9 @@ impl SimdMutPtr for Simd<*mut T, N> { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. use core::ptr::Pointee; - assert_eq!(size_of::<::Metadata>(), 0); - assert_eq!(size_of::<::Metadata>(), 0); + use core::mem::SizedTypeProperties; + assert!(<::Metadata>::IS_ZST); + assert!(<::Metadata>::IS_ZST); // Safety: pointers can be cast unsafe { core::intrinsics::simd::simd_cast_ptr(self) } From feff5d43ead50246b192ce7af250aa435e62c633 Mon Sep 17 00:00:00 2001 From: Lars Schumann Date: Mon, 27 Apr 2026 17:43:09 +0000 Subject: [PATCH 2/3] replace manual is_zst checks in compiler-builtins and proc_macro --- library/compiler-builtins/compiler-builtins/src/lib.rs | 3 ++- .../compiler-builtins/src/mem/x86_64.rs | 5 +++-- library/proc_macro/src/bridge/selfless_reify.rs | 4 ++-- library/proc_macro/src/lib.rs | 9 +++++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 9e847206caf19..e9bdb6941535c 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -7,9 +7,10 @@ #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(linkage)] -#![feature(repr_simd)] #![feature(macro_metavar_expr_concat)] +#![feature(repr_simd)] #![feature(rustc_attrs)] +#![feature(sized_type_properties)] #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] #![no_builtins] diff --git a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs index bf36a286ac951..d7691b7033560 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs @@ -17,7 +17,8 @@ // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". use core::arch::asm; -use core::{intrinsics, mem}; +use core::intrinsics; +use core::mem::{self, SizedTypeProperties}; #[inline(always)] #[cfg(target_feature = "ermsb")] @@ -135,7 +136,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { F: FnOnce(*const U, *const U, usize) -> i32, { // Ensure T is not a ZST. - const { assert!(mem::size_of::() != 0) }; + const { assert!(!T::IS_ZST) }; let end = a.add(intrinsics::unchecked_div(n, mem::size_of::())); while a != end { diff --git a/library/proc_macro/src/bridge/selfless_reify.rs b/library/proc_macro/src/bridge/selfless_reify.rs index 1a9951af8c9f1..2864f804a2d91 100644 --- a/library/proc_macro/src/bridge/selfless_reify.rs +++ b/library/proc_macro/src/bridge/selfless_reify.rs @@ -36,7 +36,7 @@ //! } //! ``` -use std::mem; +use std::mem::{self, SizedTypeProperties}; pub(super) const fn reify_to_extern_c_fn_hrt_bridge< R, @@ -47,7 +47,7 @@ pub(super) const fn reify_to_extern_c_fn_hrt_bridge< // FIXME(eddyb) describe the `F` type (e.g. via `type_name::`) once panic // formatting becomes possible in `const fn`. const { - assert!(size_of::() == 0, "selfless_reify: closure must be zero-sized"); + assert!(F::IS_ZST, "selfless_reify: closure must be zero-sized"); } extern "C" fn wrapper) -> R + Copy>( bridge: super::BridgeConfig<'_>, diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index a01bf38a62dbf..a1254278ba51d 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -18,16 +18,17 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] #![doc(rust_logo)] -#![feature(rustdoc_internals)] -#![feature(staged_api)] #![feature(allow_internal_unstable)] #![feature(decl_macro)] +#![feature(extend_one)] +#![feature(mem_conjure_zst)] #![feature(negative_impls)] #![feature(panic_can_unwind)] #![feature(restricted_std)] #![feature(rustc_attrs)] -#![feature(extend_one)] -#![feature(mem_conjure_zst)] +#![feature(rustdoc_internals)] +#![feature(sized_type_properties)] +#![feature(staged_api)] #![recursion_limit = "256"] #![allow(internal_features)] #![deny(ffi_unwind_calls)] From 3a4dff8f43dda7638f011a379b3bc3f95eb7b469 Mon Sep 17 00:00:00 2001 From: Lars Schumann Date: Mon, 27 Apr 2026 19:29:36 +0000 Subject: [PATCH 3/3] replace manual is_zst checks in rustc_middle and rustc_arena --- compiler/rustc_arena/src/lib.rs | 21 +++++++++++---------- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/ty/list.rs | 5 +++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 24ade7300c33b..c7ca0a7f6d504 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -17,13 +17,14 @@ #![feature(dropck_eyepatch)] #![feature(never_type)] #![feature(rustc_attrs)] +#![feature(sized_type_properties)] #![feature(unwrap_infallible)] // tidy-alphabetical-end use std::alloc::Layout; use std::cell::{Cell, RefCell}; use std::marker::PhantomData; -use std::mem::{self, MaybeUninit}; +use std::mem::{self, MaybeUninit, SizedTypeProperties}; use std::ptr::{self, NonNull}; use std::{cmp, hint, slice}; @@ -87,7 +88,7 @@ impl ArenaChunk { #[inline] fn end(&mut self) -> *mut T { unsafe { - if size_of::() == 0 { + if T::IS_ZST { // A pointer as large as possible for zero-sized elements. ptr::without_provenance_mut(!0) } else { @@ -140,7 +141,7 @@ impl TypedArena { /// Allocates an object in the `TypedArena`, returning a reference to it. #[inline] pub fn alloc(&self, object: T) -> &mut T { - assert!(size_of::() != 0); + assert!(!T::IS_ZST); if self.ptr == self.end { self.grow(1) @@ -181,7 +182,7 @@ impl TypedArena { /// approach to arena-allocating slices of droppable values. #[inline] unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T { - assert!(size_of::() != 0); + assert!(!T::IS_ZST); assert!(len != 0); // Ensure the current chunk can fit `len` objects. @@ -227,7 +228,7 @@ impl TypedArena { // So we collect all the elements beforehand, which takes care of reentrancy and panic // safety. This function is much less hot than `DroplessArena::alloc_from_iter`, so it // doesn't need to be hyper-optimized. - assert!(size_of::() != 0); + assert!(!T::IS_ZST); let vec: Result, E> = iter.into_iter().collect(); let mut vec = vec?; @@ -296,7 +297,7 @@ impl TypedArena { let end = self.ptr.get().addr(); // We then calculate the number of elements to be dropped in the last chunk, // which is the filled area's length. - assert_ne!(size_of::(), 0); + assert!(!T::IS_ZST); // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). let diff = (end - start) / size_of::(); @@ -459,7 +460,7 @@ impl DroplessArena { #[inline] pub fn alloc(&self, object: T) -> &mut T { assert!(!mem::needs_drop::()); - assert!(size_of::() != 0); + assert!(!T::IS_ZST); let mem = self.alloc_raw(Layout::new::()) as *mut T; @@ -483,7 +484,7 @@ impl DroplessArena { T: Copy, { assert!(!mem::needs_drop::()); - assert!(size_of::() != 0); + assert!(!T::IS_ZST); assert!(!slice.is_empty()); let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T; @@ -545,7 +546,7 @@ impl DroplessArena { // Warning: this function is reentrant: `iter` could hold a reference to `&self` and // allocate additional elements while we're iterating. let iter = iter.into_iter(); - assert!(size_of::() != 0); + assert!(!T::IS_ZST); assert!(!mem::needs_drop::()); let size_hint = iter.size_hint(); @@ -577,7 +578,7 @@ impl DroplessArena { ) -> Result<&mut [T], E> { // Despite the similarity with `alloc_from_iter`, we cannot reuse their fast case, as we // cannot know the minimum length of the iterator in this case. - assert!(size_of::() != 0); + assert!(!T::IS_ZST); // Takes care of reentrancy. let vec: Result, E> = iter.into_iter().collect(); diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 1d6132ba2a3ea..958d66d942c32 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -49,6 +49,7 @@ #![feature(range_bounds_is_empty)] #![feature(rustc_attrs)] #![feature(sized_hierarchy)] +#![feature(sized_type_properties)] #![feature(trait_alias)] #![feature(try_blocks)] #![feature(try_trait_v2)] diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index ed5a48b094f24..80fbfd6da3eb1 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -1,8 +1,9 @@ use std::alloc::Layout; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; +use std::mem::{self, SizedTypeProperties}; use std::ops::Deref; -use std::{fmt, iter, mem, ptr, slice}; +use std::{fmt, iter, ptr, slice}; use rustc_data_structures::aligned::{Aligned, align_of}; use rustc_data_structures::sync::DynSync; @@ -103,7 +104,7 @@ impl RawList { T: Copy, { assert!(!mem::needs_drop::()); - assert!(size_of::() != 0); + assert!(!T::IS_ZST); assert!(!slice.is_empty()); let (layout, _offset) =