From eb7cb897ea71f57eed0495f1fbc12b7cca0e55df Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 12 Apr 2026 13:26:38 +0200 Subject: [PATCH 01/31] implement our own `ulps` check to test `f16` the `float-cmp` and `num-traits` libraries don't (yet) support f16. Turns out we didn't really need much from them, just the ulps check. I've adapted the ulps check from miri instead --- Cargo.lock | 10 ---------- crates/std_float/tests/float.rs | 2 ++ crates/test_helpers/Cargo.toml | 1 - crates/test_helpers/src/approxeq.rs | 13 +++++++++---- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3b950bd5069c..80a0e1999cfaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,15 +71,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" -[[package]] -name = "float-cmp" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" -dependencies = [ - "num-traits", -] - [[package]] name = "futures-core" version = "0.3.32" @@ -388,7 +379,6 @@ dependencies = [ name = "test_helpers" version = "0.1.0" dependencies = [ - "float-cmp", "proptest", ] diff --git a/crates/std_float/tests/float.rs b/crates/std_float/tests/float.rs index 0fa5da3dca506..ece8cdda8f432 100644 --- a/crates/std_float/tests/float.rs +++ b/crates/std_float/tests/float.rs @@ -1,4 +1,5 @@ #![feature(portable_simd)] +#![feature(f16)] macro_rules! unary_test { { $scalar:tt, $($func:tt),+ } => { @@ -91,5 +92,6 @@ macro_rules! impl_tests { } } +impl_tests! { f16 } impl_tests! { f32 } impl_tests! { f64 } diff --git a/crates/test_helpers/Cargo.toml b/crates/test_helpers/Cargo.toml index da7ef7bd9945c..2abacd89b8e0b 100644 --- a/crates/test_helpers/Cargo.toml +++ b/crates/test_helpers/Cargo.toml @@ -6,4 +6,3 @@ publish = false [dependencies] proptest = { workspace = true, features = ["alloc", "std"] } -float-cmp = "0.10" diff --git a/crates/test_helpers/src/approxeq.rs b/crates/test_helpers/src/approxeq.rs index 57b43a16bc6fe..b868e09e1483a 100644 --- a/crates/test_helpers/src/approxeq.rs +++ b/crates/test_helpers/src/approxeq.rs @@ -1,7 +1,5 @@ //! Compare numeric types approximately. -use float_cmp::Ulps; - pub trait ApproxEq { fn approxeq(&self, other: &Self, _ulps: i64) -> bool; fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result; @@ -43,7 +41,14 @@ macro_rules! impl_float_approxeq { if self.is_nan() && other.is_nan() { true } else { - (self.ulps(other) as i64).abs() <= ulps + let allowed_ulp_diff = ulps; + + // Approximate the ULP by taking half the distance between the number one place "up" + // and the number one place "down". + let ulp = (other.next_up() - other.next_down()) / 2.0; + let ulp_diff = ((self - other) / ulp).abs().round() as i64; + + ulp_diff <= allowed_ulp_diff } } @@ -55,7 +60,7 @@ macro_rules! impl_float_approxeq { }; } -impl_float_approxeq! { f32, f64 } +impl_float_approxeq! { f16, f32, f64 } impl ApproxEq for [T; N] { fn approxeq(&self, other: &Self, ulps: i64) -> bool { From f40da91254c30f4379b6a6f9301c9930d352b992 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 16 Apr 2026 15:56:54 +0200 Subject: [PATCH 02/31] disable `f16` tests when not `target_has_reliable_f16_math` relevant for the cranelift backend, possibly other cases/targets too --- crates/core_simd/Cargo.toml | 8 ++++++++ crates/core_simd/tests/f16_ops.rs | 3 +++ 2 files changed, 11 insertions(+) diff --git a/crates/core_simd/Cargo.toml b/crates/core_simd/Cargo.toml index 6e576084ecfba..05fc63a6a29d3 100644 --- a/crates/core_simd/Cargo.toml +++ b/crates/core_simd/Cargo.toml @@ -31,3 +31,11 @@ path = "../test_helpers" [dev-dependencies] std_float = { path = "../std_float/", features = ["as_crate"] } + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + # Internal features aren't marked known config by default, we use these to + # gate tests. + 'cfg(target_has_reliable_f16_math)', +] diff --git a/crates/core_simd/tests/f16_ops.rs b/crates/core_simd/tests/f16_ops.rs index f89bdf4738f8b..03e239b745f12 100644 --- a/crates/core_simd/tests/f16_ops.rs +++ b/crates/core_simd/tests/f16_ops.rs @@ -1,5 +1,7 @@ #![feature(portable_simd)] #![feature(f16)] +#![expect(internal_features)] +#![feature(cfg_target_has_reliable_f16_f128)] #[macro_use] mod ops_macros; @@ -7,4 +9,5 @@ mod ops_macros; // FIXME: some f16 operations cause rustc to hang on wasm simd // https://github.com/llvm/llvm-project/issues/189251 #[cfg(not(all(target_arch = "wasm32", target_feature = "simd128")))] +#[cfg(target_has_reliable_f16_math)] impl_float_tests! { f16, i16 } From c4f3110f54c86ca5f5b08ddb050d3f517b450e6e Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 8 May 2026 00:12:43 -0400 Subject: [PATCH 03/31] Fix pointer API to match what was stabilized --- crates/core_simd/src/simd/ptr.rs | 46 +++++++++++++++++++++ crates/core_simd/src/simd/ptr/const_ptr.rs | 47 +++------------------- crates/core_simd/src/simd/ptr/mut_ptr.rs | 44 +++----------------- crates/core_simd/tests/pointers.rs | 24 +++++++++-- 4 files changed, 77 insertions(+), 84 deletions(-) diff --git a/crates/core_simd/src/simd/ptr.rs b/crates/core_simd/src/simd/ptr.rs index 3f8e666911853..a27367ceb791b 100644 --- a/crates/core_simd/src/simd/ptr.rs +++ b/crates/core_simd/src/simd/ptr.rs @@ -9,3 +9,49 @@ mod sealed { pub use const_ptr::*; pub use mut_ptr::*; + +use crate::simd::Simd; + +/// Creates pointers with the given addresses and no provenance. +/// +/// Equivalent to calling [`core::ptr::without_provenance`] on each element. +#[inline] +pub fn without_provenance(addr: Simd) -> Simd<*const T, N> { + // An int-to-pointer transmute currently has exactly the intended semantics: it creates a + // pointer without provenance. Note that this is *not* a stable guarantee about transmute + // semantics, it relies on sysroot crates having special status. + // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that + // pointer). + unsafe { core::mem::transmute_copy(&addr) } +} + +/// Creates mutable pointers with the given addresses and no provenance. +/// +/// Equivalent to calling [`core::ptr::without_provenance_mut`] on each element. +#[inline] +pub fn without_provenance_mut(addr: Simd) -> Simd<*mut T, N> { + // An int-to-pointer transmute currently has exactly the intended semantics: it creates a + // pointer without provenance. Note that this is *not* a stable guarantee about transmute + // semantics, it relies on sysroot crates having special status. + // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that + // pointer). + unsafe { core::mem::transmute_copy(&addr) } +} + +/// Converts addresses back to pointers, picking up some previously "exposed" provenance. +/// +/// Equivalent to calling [`core::ptr::with_exposed_provenance`] on each element. +#[inline] +pub fn with_exposed_provenance(addr: Simd) -> Simd<*const T, N> { + // SAFETY: addr is a vector of usize + unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) } +} + +/// Converts addresses back to mutable pointers, picking up some previously "exposed" provenance. +/// +/// Equivalent to calling [`core::ptr::with_exposed_provenance_mut`] on each element. +#[inline] +pub fn with_exposed_provenance_mut(addr: Simd) -> Simd<*mut T, N> { + // SAFETY: addr is a vector of usize + unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) } +} diff --git a/crates/core_simd/src/simd/ptr/const_ptr.rs b/crates/core_simd/src/simd/ptr/const_ptr.rs index 7ef9dc21373ec..be2b9e6b4835f 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -33,44 +33,21 @@ pub trait SimdConstPtr: Copy + Sealed { /// Gets the "address" portion of the pointer. /// - /// This method discards pointer semantic metadata, so the result cannot be - /// directly cast into a valid pointer. - /// - /// This method semantically discards *provenance* and - /// *address-space* information. To properly restore that information, use [`Self::with_addr`]. - /// /// Equivalent to calling [`pointer::addr`] on each element. fn addr(self) -> Self::Usize; - /// Converts an address to a pointer without giving it any provenance. - /// - /// Without provenance, this pointer is not associated with any actual allocation. Such a - /// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but - /// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers - /// are little more than a usize address in disguise. - /// - /// This is different from [`Self::with_exposed_provenance`], which creates a pointer that picks up a - /// previously exposed provenance. - /// - /// Equivalent to calling [`core::ptr::without_provenance`] on each element. - fn without_provenance(addr: Self::Usize) -> Self; - /// Creates a new pointer with the given address. /// - /// This performs the same operation as a cast, but copies the *address-space* and - /// *provenance* of `self` to the new pointer. - /// /// Equivalent to calling [`pointer::with_addr`] on each element. fn with_addr(self, addr: Self::Usize) -> Self; /// Exposes the "provenance" part of the pointer for future use in - /// [`Self::with_exposed_provenance`] and returns the "address" portion. - fn expose_provenance(self) -> Self::Usize; - - /// Converts an address back to a pointer, picking up a previously "exposed" provenance. + /// [`super::with_exposed_provenance`] and returns the "address" portion. + /// + /// Equivalent to calling [`pointer::expose_provenance`] on each element. /// - /// Equivalent to calling [`core::ptr::with_exposed_provenance`] on each element. - fn with_exposed_provenance(addr: Self::Usize) -> Self; + /// See [`super::with_exposed_provenance`] for the matching constructor. + fn expose_provenance(self) -> Self::Usize; /// Calculates the offset from a pointer using wrapping arithmetic. /// @@ -128,14 +105,6 @@ impl SimdConstPtr for Simd<*const T, N> { unsafe { core::mem::transmute_copy(&self) } } - #[inline] - fn without_provenance(addr: Self::Usize) -> Self { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - // SAFETY: Integer-to-pointer transmutes are valid (if you are okay with not getting any - // provenance). - unsafe { core::mem::transmute_copy(&addr) } - } - #[inline] fn with_addr(self, addr: Self::Usize) -> Self { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. @@ -154,12 +123,6 @@ impl SimdConstPtr for Simd<*const T, N> { unsafe { core::intrinsics::simd::simd_expose_provenance(self) } } - #[inline] - fn with_exposed_provenance(addr: Self::Usize) -> Self { - // Safety: `self` is a pointer vector - unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) } - } - #[inline] fn wrapping_offset(self, count: Self::Isize) -> Self { // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets diff --git a/crates/core_simd/src/simd/ptr/mut_ptr.rs b/crates/core_simd/src/simd/ptr/mut_ptr.rs index 3b9b75ddf5660..78b5bef4d9740 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -33,41 +33,21 @@ pub trait SimdMutPtr: Copy + Sealed { /// Gets the "address" portion of the pointer. /// - /// This method discards pointer semantic metadata, so the result cannot be - /// directly cast into a valid pointer. - /// /// Equivalent to calling [`pointer::addr`] on each element. fn addr(self) -> Self::Usize; - /// Converts an address to a pointer without giving it any provenance. - /// - /// Without provenance, this pointer is not associated with any actual allocation. Such a - /// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but - /// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers - /// are little more than a usize address in disguise. - /// - /// This is different from [`Self::with_exposed_provenance`], which creates a pointer that picks up a - /// previously exposed provenance. - /// - /// Equivalent to calling [`core::ptr::without_provenance`] on each element. - fn without_provenance(addr: Self::Usize) -> Self; - /// Creates a new pointer with the given address. /// - /// This performs the same operation as a cast, but copies the *address-space* and - /// *provenance* of `self` to the new pointer. - /// /// Equivalent to calling [`pointer::with_addr`] on each element. fn with_addr(self, addr: Self::Usize) -> Self; /// Exposes the "provenance" part of the pointer for future use in - /// [`Self::with_exposed_provenance`] and returns the "address" portion. - fn expose_provenance(self) -> Self::Usize; - - /// Converts an address back to a pointer, picking up a previously "exposed" provenance. + /// [`super::with_exposed_provenance_mut`] and returns the "address" portion. /// - /// Equivalent to calling [`core::ptr::with_exposed_provenance_mut`] on each element. - fn with_exposed_provenance(addr: Self::Usize) -> Self; + /// Equivalent to calling [`pointer::expose_provenance`] on each element. + /// + /// See [`super::with_exposed_provenance_mut`] for the matching constructor. + fn expose_provenance(self) -> Self::Usize; /// Calculates the offset from a pointer using wrapping arithmetic. /// @@ -125,14 +105,6 @@ impl SimdMutPtr for Simd<*mut T, N> { unsafe { core::mem::transmute_copy(&self) } } - #[inline] - fn without_provenance(addr: Self::Usize) -> Self { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - // SAFETY: Integer-to-pointer transmutes are valid (if you are okay with not getting any - // provenance). - unsafe { core::mem::transmute_copy(&addr) } - } - #[inline] fn with_addr(self, addr: Self::Usize) -> Self { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. @@ -151,12 +123,6 @@ impl SimdMutPtr for Simd<*mut T, N> { unsafe { core::intrinsics::simd::simd_expose_provenance(self) } } - #[inline] - fn with_exposed_provenance(addr: Self::Usize) -> Self { - // Safety: `self` is a pointer vector - unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) } - } - #[inline] fn wrapping_offset(self, count: Self::Isize) -> Self { // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets diff --git a/crates/core_simd/tests/pointers.rs b/crates/core_simd/tests/pointers.rs index 6e74c2d18b1ed..06670cc9dd976 100644 --- a/crates/core_simd/tests/pointers.rs +++ b/crates/core_simd/tests/pointers.rs @@ -2,7 +2,7 @@ use core_simd::simd::{ Simd, - ptr::{SimdConstPtr, SimdMutPtr}, + ptr::{self, SimdConstPtr, SimdMutPtr}, }; macro_rules! common_tests { @@ -82,11 +82,20 @@ mod const_ptr { fn with_exposed_provenance() { test_helpers::test_unary_elementwise( - &Simd::<*const u32, LANES>::with_exposed_provenance, + &ptr::with_exposed_provenance::, &core::ptr::with_exposed_provenance::, &|_| true, ); } + + fn without_provenance() { + test_helpers::test_unary_elementwise( + &ptr::without_provenance::, + &core::ptr::without_provenance::, + &|_| true, + ); + } + } } @@ -105,10 +114,19 @@ mod mut_ptr { fn with_exposed_provenance() { test_helpers::test_unary_elementwise( - &Simd::<*mut u32, LANES>::with_exposed_provenance, + &ptr::with_exposed_provenance_mut::, &core::ptr::with_exposed_provenance_mut::, &|_| true, ); } + + fn without_provenance() { + test_helpers::test_unary_elementwise( + &ptr::without_provenance_mut::, + &core::ptr::without_provenance_mut::, + &|_| true, + ); + } + } } From beafe835d5772f8cd3408fe80cf08cf79af5aaa4 Mon Sep 17 00:00:00 2001 From: Karl Meakin Date: Thu, 28 May 2026 20:41:46 +0100 Subject: [PATCH 04/31] Optimize `swizzle_dyn` for AArch64 with N > 16 We can do swizzles for 24, 32, 48 and 64 byte vectors by stacking multiple TBL instructions. See https://godbolt.org/z/PE95nrqjj for a comparison of the generated assembly. --- crates/core_simd/src/swizzle_dyn.rs | 86 +++++++++++++++++++++++------ crates/test_helpers/src/lib.rs | 2 +- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/crates/core_simd/src/swizzle_dyn.rs b/crates/core_simd/src/swizzle_dyn.rs index ae0b174973da7..cf37aff9a76d1 100644 --- a/crates/core_simd/src/swizzle_dyn.rs +++ b/crates/core_simd/src/swizzle_dyn.rs @@ -13,11 +13,6 @@ impl Simd { #[inline] pub fn swizzle_dyn(self, idxs: Simd) -> Self { #![allow(unused_imports, unused_unsafe)] - #[cfg(all( - any(target_arch = "aarch64", target_arch = "arm64ec"), - target_endian = "little" - ))] - use core::arch::aarch64::{uint8x8_t, vqtbl1q_u8, vtbl1_u8}; #[cfg(all( target_arch = "arm", target_feature = "v7", @@ -37,25 +32,15 @@ impl Simd { unsafe { match N { #[cfg(all( - any( - target_arch = "aarch64", - target_arch = "arm64ec", - all(target_arch = "arm", target_feature = "v7") - ), + any(target_arch = "aarch64", target_arch = "arm64ec"), target_feature = "neon", target_endian = "little" ))] - 8 => transize(vtbl1_u8, self, idxs), + 8 | 16 | 24 | 32 | 48 | 64 => aarch64_swizzle(self, idxs), #[cfg(target_feature = "ssse3")] 16 => transize(x86::_mm_shuffle_epi8, self, zeroing_idxs(idxs)), #[cfg(target_feature = "simd128")] 16 => transize(wasm::i8x16_swizzle, self, idxs), - #[cfg(all( - any(target_arch = "aarch64", target_arch = "arm64ec"), - target_feature = "neon", - target_endian = "little" - ))] - 16 => transize(vqtbl1q_u8, self, idxs), #[cfg(all( target_arch = "arm", target_feature = "v7", @@ -126,6 +111,73 @@ unsafe fn armv7_neon_swizzle_u8x16(bytes: Simd, idxs: Simd) -> S } } +/// AArch64 NEON supports swizzling 8, 16, 24, 32, 48 or 64 by stacking multiple TBL instructions. +/// +/// # Safety +/// This requires AArch64 NEON to work +#[cfg(all( + any(target_arch = "aarch64", target_arch = "arm64ec"), + target_feature = "neon", + target_endian = "little" +))] +unsafe fn aarch64_swizzle(bytes: Simd, idxs: Simd) -> Simd { + use core::arch::aarch64::*; + use core::mem::transmute_copy; + + // SAFETY: Caller promised AArch64 NEON support + unsafe { + match N { + 8 => transmute_copy(&vtbl1_u8(transmute_copy(&bytes), transmute_copy(&idxs))), + 16 => transmute_copy(&vqtbl1q_u8(transmute_copy(&bytes), transmute_copy(&idxs))), + 24 => { + let bytes: uint8x8x3_t = transmute_copy(&bytes); + let idxs: uint8x8x3_t = transmute_copy(&idxs); + + let ret0 = vtbl3_u8(bytes, idxs.0); + let ret1 = vtbl3_u8(bytes, idxs.1); + let ret2 = vtbl3_u8(bytes, idxs.2); + + let ret = uint8x8x3_t(ret0, ret1, ret2); + transmute_copy(&ret) + } + 32 => { + let bytes: uint8x16x2_t = transmute_copy(&bytes); + let idxs: uint8x16x2_t = transmute_copy(&idxs); + + let ret0 = vqtbl2q_u8(bytes, idxs.0); + let ret1 = vqtbl2q_u8(bytes, idxs.1); + + let ret = uint8x16x2_t(ret0, ret1); + transmute_copy(&ret) + } + 48 => { + let bytes: uint8x16x3_t = transmute_copy(&bytes); + let idxs: uint8x16x3_t = transmute_copy(&idxs); + + let ret0 = vqtbl3q_u8(bytes, idxs.0); + let ret1 = vqtbl3q_u8(bytes, idxs.1); + let ret2 = vqtbl3q_u8(bytes, idxs.2); + + let ret = uint8x16x3_t(ret0, ret1, ret2); + transmute_copy(&ret) + } + 64 => { + let bytes: uint8x16x4_t = transmute_copy(&bytes); + let idxs: uint8x16x4_t = transmute_copy(&idxs); + + let ret0 = vqtbl4q_u8(bytes, idxs.0); + let ret1 = vqtbl4q_u8(bytes, idxs.1); + let ret2 = vqtbl4q_u8(bytes, idxs.2); + let ret3 = vqtbl4q_u8(bytes, idxs.3); + + let ret = uint8x16x4_t(ret0, ret1, ret2, ret3); + transmute_copy(&ret) + } + _ => unreachable!(), + } + } +} + /// "vpshufb like it was meant to be" on AVX2 /// /// # Safety diff --git a/crates/test_helpers/src/lib.rs b/crates/test_helpers/src/lib.rs index ce3680ac2c306..6661b0c53c7a9 100644 --- a/crates/test_helpers/src/lib.rs +++ b/crates/test_helpers/src/lib.rs @@ -678,7 +678,7 @@ macro_rules! test_lanes { //lanes_45 45; //lanes_46 46; lanes_47 47; - //lanes_48 48; + lanes_48 48; //lanes_49 49; //lanes_50 50; //lanes_51 51; From b16ee624234def39a75bc8441b2518a6854fa028 Mon Sep 17 00:00:00 2001 From: Karl Meakin Date: Sun, 31 May 2026 23:59:35 +0100 Subject: [PATCH 05/31] Provide `From` impls for AArch64 ACLE tuple types. `From` impls were already provided for the normal AArch64 ACLE vector types, but not for the x2,x3,x4 tuples of ACLE vectors. Rectify that. Also provide impls for vectors of `f16`, as I noticed they were missing. --- crates/core_simd/src/vendor/arm.rs | 50 ++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/crates/core_simd/src/vendor/arm.rs b/crates/core_simd/src/vendor/arm.rs index 3dc54481b6fd4..d2f4ffd8e867e 100644 --- a/crates/core_simd/src/vendor/arm.rs +++ b/crates/core_simd/src/vendor/arm.rs @@ -7,6 +7,16 @@ use core::arch::arm::*; #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] use core::arch::aarch64::*; +/// Transmute between `Simd` and ACLE tuple types. +macro_rules! tuple { + ($scalar:ty,$tuple:ty) => { + from_transmute! { unsafe Simd<$scalar, { size_of::<$tuple>() / size_of::<$scalar>() }> => $tuple } + }; + ($scalar:ty,$($tuples:ty),*) => { + $(tuple! { $scalar, $tuples })* + }; +} + #[cfg(all( any( target_arch = "aarch64", @@ -18,9 +28,6 @@ use core::arch::aarch64::*; mod neon { use super::*; - from_transmute! { unsafe f32x2 => float32x2_t } - from_transmute! { unsafe f32x4 => float32x4_t } - from_transmute! { unsafe u8x8 => uint8x8_t } from_transmute! { unsafe u8x16 => uint8x16_t } from_transmute! { unsafe i8x8 => int8x8_t } @@ -34,11 +41,15 @@ mod neon { from_transmute! { unsafe i16x8 => int16x8_t } from_transmute! { unsafe u16x4 => poly16x4_t } from_transmute! { unsafe u16x8 => poly16x8_t } + from_transmute! { unsafe f16x4 => float16x4_t } + from_transmute! { unsafe f16x8 => float16x8_t } from_transmute! { unsafe u32x2 => uint32x2_t } from_transmute! { unsafe u32x4 => uint32x4_t } from_transmute! { unsafe i32x2 => int32x2_t } from_transmute! { unsafe i32x4 => int32x4_t } + from_transmute! { unsafe f32x2 => float32x2_t } + from_transmute! { unsafe f32x4 => float32x4_t } from_transmute! { unsafe Simd => uint64x1_t } from_transmute! { unsafe u64x2 => uint64x2_t } @@ -46,6 +57,36 @@ mod neon { from_transmute! { unsafe i64x2 => int64x2_t } from_transmute! { unsafe Simd => poly64x1_t } from_transmute! { unsafe u64x2 => poly64x2_t } + + tuple!(i8, int8x8x2_t, int8x8x3_t, int8x8x4_t); + tuple!(i8, int8x16x2_t, int8x16x3_t, int8x16x4_t); + tuple!(u8, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t); + tuple!(u8, uint8x16x2_t, uint8x16x3_t, uint8x16x4_t); + tuple!(u8, poly8x8x2_t, poly8x8x3_t, poly8x8x4_t); + tuple!(u8, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t); + + tuple!(i16, int16x4x2_t, int16x4x3_t, int16x4x4_t); + tuple!(i16, int16x8x2_t, int16x8x3_t, int16x8x4_t); + tuple!(u16, uint16x4x2_t, uint16x4x3_t, uint16x4x4_t); + tuple!(u16, uint16x8x2_t, uint16x8x3_t, uint16x8x4_t); + tuple!(u16, poly16x4x2_t, poly16x4x3_t, poly16x4x4_t); + tuple!(u16, poly16x8x2_t, poly16x8x3_t, poly16x8x4_t); + tuple!(f16, float16x4x2_t, float16x4x3_t, float16x4x4_t); + tuple!(f16, float16x8x2_t, float16x8x3_t, float16x8x4_t); + + tuple!(i32, int32x2x2_t, int32x2x3_t, int32x2x4_t); + tuple!(i32, int32x4x2_t, int32x4x3_t, int32x4x4_t); + tuple!(u32, uint32x2x2_t, uint32x2x3_t, uint32x2x4_t); + tuple!(u32, uint32x4x2_t, uint32x4x3_t, uint32x4x4_t); + tuple!(f32, float32x2x2_t, float32x2x3_t, float32x2x4_t); + tuple!(f32, float32x4x2_t, float32x4x3_t, float32x4x4_t); + + tuple!(i64, int64x1x2_t, int64x1x3_t, int64x1x4_t); + tuple!(i64, int64x2x2_t, int64x2x3_t, int64x2x4_t); + tuple!(u64, uint64x1x2_t, uint64x1x3_t, uint64x1x4_t); + tuple!(u64, uint64x2x2_t, uint64x2x3_t, uint64x2x4_t); + tuple!(u64, poly64x1x2_t, poly64x1x3_t, poly64x1x4_t); + tuple!(u64, poly64x2x2_t, poly64x2x3_t, poly64x2x4_t); } #[cfg(any( @@ -71,4 +112,7 @@ mod aarch64 { from_transmute! { unsafe Simd => float64x1_t } from_transmute! { unsafe f64x2 => float64x2_t } + + tuple!(f64, float64x1x2_t, float64x1x3_t, float64x1x4_t); + tuple!(f64, float64x2x2_t, float64x2x3_t, float64x2x4_t); } From 61ae55e111690bc428e97a959adde0a3dcd48e6d Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sat, 30 May 2026 14:30:22 -0400 Subject: [PATCH 06/31] Use `impl` restrictions over hand-sealed traits --- crates/core_simd/src/cast.rs | 55 +++++++--------------- crates/core_simd/src/lib.rs | 1 + crates/core_simd/src/masks.rs | 15 +++--- crates/core_simd/src/simd/num.rs | 4 -- crates/core_simd/src/simd/num/float.rs | 5 +- crates/core_simd/src/simd/num/int.rs | 5 +- crates/core_simd/src/simd/num/uint.rs | 5 +- crates/core_simd/src/simd/ptr.rs | 4 -- crates/core_simd/src/simd/ptr/const_ptr.rs | 5 +- crates/core_simd/src/simd/ptr/mut_ptr.rs | 5 +- crates/core_simd/src/to_bytes.rs | 11 +---- crates/core_simd/src/vector.rs | 37 +-------------- crates/std_float/src/lib.rs | 17 +------ 13 files changed, 38 insertions(+), 131 deletions(-) diff --git a/crates/core_simd/src/cast.rs b/crates/core_simd/src/cast.rs index 69dc7ba50d58d..81187ae68ad19 100644 --- a/crates/core_simd/src/cast.rs +++ b/crates/core_simd/src/cast.rs @@ -1,54 +1,35 @@ use crate::simd::SimdElement; -mod sealed { - /// Cast vector elements to other types. - /// - /// # Safety - /// Implementing this trait asserts that the type is a valid vector element for the `simd_cast` - /// or `simd_as` intrinsics. - pub unsafe trait Sealed {} -} -use sealed::Sealed; - /// Supporting trait for `Simd::cast`. Typically doesn't need to be used directly. -pub trait SimdCast: Sealed + SimdElement {} +/// +/// # Safety +/// Implementing this trait asserts that the type is a valid vector element for the `simd_cast` or +/// `simd_as` intrinsics. +pub impl(self) unsafe trait SimdCast: SimdElement {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for i8 {} -impl SimdCast for i8 {} +unsafe impl SimdCast for i8 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for i16 {} -impl SimdCast for i16 {} +unsafe impl SimdCast for i16 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for i32 {} -impl SimdCast for i32 {} +unsafe impl SimdCast for i32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for i64 {} -impl SimdCast for i64 {} +unsafe impl SimdCast for i64 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for isize {} -impl SimdCast for isize {} +unsafe impl SimdCast for isize {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for u8 {} -impl SimdCast for u8 {} +unsafe impl SimdCast for u8 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for u16 {} -impl SimdCast for u16 {} +unsafe impl SimdCast for u16 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for u32 {} -impl SimdCast for u32 {} +unsafe impl SimdCast for u32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for u64 {} -impl SimdCast for u64 {} +unsafe impl SimdCast for u64 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for usize {} -impl SimdCast for usize {} +unsafe impl SimdCast for usize {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for f16 {} -impl SimdCast for f16 {} +unsafe impl SimdCast for f16 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for f32 {} -impl SimdCast for f32 {} +unsafe impl SimdCast for f32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl Sealed for f64 {} -impl SimdCast for f64 {} +unsafe impl SimdCast for f64 {} diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs index 413a886f6c5b8..e59b286f780da 100644 --- a/crates/core_simd/src/lib.rs +++ b/crates/core_simd/src/lib.rs @@ -4,6 +4,7 @@ f16, core_intrinsics, decl_macro, + impl_restriction, repr_simd, staged_api, prelude_import, diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index cb5d54020f7fc..90a00e016358e 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -29,7 +29,7 @@ macro_rules! impl_fix_endianness { impl_fix_endianness! { u8, u16, u32, u64 } -mod sealed { +mod private_methods { use super::*; /// Not only does this seal the `MaskElement` trait, but these functions prevent other traits @@ -38,7 +38,7 @@ mod sealed { /// For example, `eq` could be provided by requiring `MaskElement: PartialEq`, but that would /// prevent us from ever removing that bound, or from implementing `MaskElement` on /// non-`PartialEq` types in the future. - pub trait Sealed { + pub impl(super) trait PrivateMethods { fn valid(values: Simd) -> bool where Self: SimdElement; @@ -55,17 +55,20 @@ mod sealed { const FALSE: Self; } } -use sealed::Sealed; +use private_methods::PrivateMethods; /// Marker trait for types that may be used as SIMD mask elements. /// /// # Safety /// Type must be a signed integer. -pub unsafe trait MaskElement: SimdElement + SimdCast + Sealed {} +pub impl(self) unsafe trait MaskElement: + SimdElement + SimdCast + PrivateMethods +{ +} macro_rules! impl_element { { $ty:ty, $unsigned:ty } => { - impl Sealed for $ty { + impl PrivateMethods for $ty { #[inline] fn valid(value: Simd) -> bool { @@ -196,7 +199,7 @@ where pub unsafe fn from_simd_unchecked(value: Simd) -> Self { // Safety: the caller must confirm this invariant unsafe { - core::intrinsics::assume(::valid(value)); + core::intrinsics::assume(::valid(value)); } Self(value) } diff --git a/crates/core_simd/src/simd/num.rs b/crates/core_simd/src/simd/num.rs index 22a4802ec6cb5..d1186d3734b49 100644 --- a/crates/core_simd/src/simd/num.rs +++ b/crates/core_simd/src/simd/num.rs @@ -4,10 +4,6 @@ mod float; mod int; mod uint; -mod sealed { - pub trait Sealed {} -} - pub use float::*; pub use int::*; pub use uint::*; diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 14a31b527872b..142740ad01560 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -1,11 +1,10 @@ -use super::sealed::Sealed; use crate::simd::{ Mask, Select, Simd, SimdCast, SimdElement, cmp::{SimdPartialEq, SimdPartialOrd}, }; /// Operations on SIMD vectors of floats. -pub trait SimdFloat: Copy + Sealed { +pub impl(self) trait SimdFloat: Copy { /// Mask type used for manipulating this SIMD vector type. type Mask; @@ -240,8 +239,6 @@ pub trait SimdFloat: Copy + Sealed { macro_rules! impl_trait { { $($ty:ty { bits: $bits_ty:ty, mask: $mask_ty:ty }),* } => { $( - impl Sealed for Simd<$ty, N> {} - impl SimdFloat for Simd<$ty, N> { type Mask = Mask<<$mask_ty as SimdElement>::Mask, N>; diff --git a/crates/core_simd/src/simd/num/int.rs b/crates/core_simd/src/simd/num/int.rs index eee54d3968808..ab556c14d6371 100644 --- a/crates/core_simd/src/simd/num/int.rs +++ b/crates/core_simd/src/simd/num/int.rs @@ -1,10 +1,9 @@ -use super::sealed::Sealed; use crate::simd::{ Mask, Select, Simd, SimdCast, SimdElement, cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint, }; /// Operations on SIMD vectors of signed integers. -pub trait SimdInt: Copy + Sealed { +pub impl(self) trait SimdInt: Copy { /// Mask type used for manipulating this SIMD vector type. type Mask; @@ -241,8 +240,6 @@ pub trait SimdInt: Copy + Sealed { macro_rules! impl_trait { { $($ty:ident ($unsigned:ident)),* } => { $( - impl Sealed for Simd<$ty, N> {} - impl SimdInt for Simd<$ty, N> { type Mask = Mask<<$ty as SimdElement>::Mask, N>; type Scalar = $ty; diff --git a/crates/core_simd/src/simd/num/uint.rs b/crates/core_simd/src/simd/num/uint.rs index 606107a1f06f8..e4d383a0c21a5 100644 --- a/crates/core_simd/src/simd/num/uint.rs +++ b/crates/core_simd/src/simd/num/uint.rs @@ -1,8 +1,7 @@ -use super::sealed::Sealed; use crate::simd::{Simd, SimdCast, SimdElement, cmp::SimdOrd}; /// Operations on SIMD vectors of unsigned integers. -pub trait SimdUint: Copy + Sealed { +pub impl(self) trait SimdUint: Copy { /// Scalar type contained by this SIMD vector type. type Scalar; @@ -124,8 +123,6 @@ pub trait SimdUint: Copy + Sealed { macro_rules! impl_trait { { $($ty:ident ($signed:ident)),* } => { $( - impl Sealed for Simd<$ty, N> {} - impl SimdUint for Simd<$ty, N> { type Scalar = $ty; diff --git a/crates/core_simd/src/simd/ptr.rs b/crates/core_simd/src/simd/ptr.rs index a27367ceb791b..bb5d9c870f448 100644 --- a/crates/core_simd/src/simd/ptr.rs +++ b/crates/core_simd/src/simd/ptr.rs @@ -3,10 +3,6 @@ mod const_ptr; mod mut_ptr; -mod sealed { - pub trait Sealed {} -} - pub use const_ptr::*; pub use mut_ptr::*; diff --git a/crates/core_simd/src/simd/ptr/const_ptr.rs b/crates/core_simd/src/simd/ptr/const_ptr.rs index be2b9e6b4835f..4d21af5270b3e 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -1,8 +1,7 @@ -use super::sealed::Sealed; use crate::simd::{Mask, Simd, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of constant pointers. -pub trait SimdConstPtr: Copy + Sealed { +pub impl(self) trait SimdConstPtr: Copy { /// Vector of `usize` with the same number of elements. type Usize; @@ -65,8 +64,6 @@ pub trait SimdConstPtr: Copy + Sealed { fn wrapping_sub(self, count: Self::Usize) -> Self; } -impl Sealed for Simd<*const T, N> {} - impl SimdConstPtr for Simd<*const T, N> { type Usize = Simd; type Isize = Simd; diff --git a/crates/core_simd/src/simd/ptr/mut_ptr.rs b/crates/core_simd/src/simd/ptr/mut_ptr.rs index 78b5bef4d9740..b7b96d5e98722 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -1,8 +1,7 @@ -use super::sealed::Sealed; use crate::simd::{Mask, Simd, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of mutable pointers. -pub trait SimdMutPtr: Copy + Sealed { +pub impl(self) trait SimdMutPtr: Copy { /// Vector of `usize` with the same number of elements. type Usize; @@ -65,8 +64,6 @@ pub trait SimdMutPtr: Copy + Sealed { fn wrapping_sub(self, count: Self::Usize) -> Self; } -impl Sealed for Simd<*mut T, N> {} - impl SimdMutPtr for Simd<*mut T, N> { type Usize = Simd; type Isize = Simd; diff --git a/crates/core_simd/src/to_bytes.rs b/crates/core_simd/src/to_bytes.rs index 1fd285e457db8..becc4e5a93a3c 100644 --- a/crates/core_simd/src/to_bytes.rs +++ b/crates/core_simd/src/to_bytes.rs @@ -1,17 +1,10 @@ use crate::simd::{ - Simd, SimdElement, + Simd, num::{SimdFloat, SimdInt, SimdUint}, }; -mod sealed { - use super::*; - pub trait Sealed {} - impl Sealed for Simd {} -} -use sealed::Sealed; - /// Converts SIMD vectors to vectors of bytes -pub trait ToBytes: Sealed { +pub impl(self) trait ToBytes { /// This type, reinterpreted as bytes. type Bytes: Copy + Unpin diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index fbef69f267aa5..55de9dac4637f 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -1058,11 +1058,6 @@ where } } -mod sealed { - pub trait Sealed {} -} -use sealed::Sealed; - /// Marker trait for types that may be used as SIMD vector elements. /// /// # Safety @@ -1071,104 +1066,76 @@ use sealed::Sealed; /// Strictly, it is valid to impl if the vector will not be miscompiled. /// Practically, it is user-unfriendly to impl it if the vector won't compile, /// even when no soundness guarantees are broken by allowing the user to try. -pub unsafe trait SimdElement: Sealed + Copy { +pub impl(self) unsafe trait SimdElement: Copy { /// The mask element type corresponding to this element type. type Mask: MaskElement; } -impl Sealed for u8 {} - // Safety: u8 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for u8 { type Mask = i8; } -impl Sealed for u16 {} - // Safety: u16 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for u16 { type Mask = i16; } -impl Sealed for u32 {} - // Safety: u32 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for u32 { type Mask = i32; } -impl Sealed for u64 {} - // Safety: u64 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for u64 { type Mask = i64; } -impl Sealed for usize {} - // Safety: usize is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for usize { type Mask = isize; } -impl Sealed for i8 {} - // Safety: i8 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for i8 { type Mask = i8; } -impl Sealed for i16 {} - // Safety: i16 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for i16 { type Mask = i16; } -impl Sealed for i32 {} - // Safety: i32 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for i32 { type Mask = i32; } -impl Sealed for i64 {} - // Safety: i64 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for i64 { type Mask = i64; } -impl Sealed for isize {} - // Safety: isize is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for isize { type Mask = isize; } -impl Sealed for f16 {} - // Safety: f16 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for f16 { type Mask = i16; } -impl Sealed for f32 {} - // Safety: f32 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for f32 { type Mask = i32; } -impl Sealed for f64 {} - // Safety: f64 is a valid SIMD element type, and is supported by this API unsafe impl SimdElement for f64 { type Mask = i64; } -impl Sealed for *const T {} - // Safety: (thin) const pointers are valid SIMD element types, and are supported by this API // // Fat pointers may be supported in the future. @@ -1179,8 +1146,6 @@ where type Mask = isize; } -impl Sealed for *mut T {} - // Safety: (thin) mut pointers are valid SIMD element types, and are supported by this API // // Fat pointers may be supported in the future. diff --git a/crates/std_float/src/lib.rs b/crates/std_float/src/lib.rs index ff3525452231a..4714881bcdad3 100644 --- a/crates/std_float/src/lib.rs +++ b/crates/std_float/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(impl_restriction)] #![cfg_attr( feature = "as_crate", feature(core_intrinsics), @@ -14,16 +15,6 @@ use core::intrinsics::simd as intrinsics; use simd::Simd; -#[cfg(feature = "as_crate")] -mod experimental { - pub trait Sealed {} -} - -#[cfg(feature = "as_crate")] -use experimental as sealed; - -use crate::sealed::Sealed; - /// This trait provides a possibly-temporary implementation of float functions /// that may, in the absence of hardware support, canonicalize to calling an /// operating system's `math.h` dynamically-loaded library (also known as a @@ -43,7 +34,7 @@ use crate::sealed::Sealed; /// when either the compiler or its supporting runtime functions are improved. /// For now this trait is available to permit experimentation with SIMD float /// operations that may lack hardware support, such as `mul_add`. -pub trait StdFloat: Sealed + Sized { +pub impl(self) trait StdFloat: Sized { /// Elementwise fused multiply-add. Computes `(self * a) + b` with only one rounding error, /// yielding a more accurate result than an unfused multiply-add. /// @@ -170,10 +161,6 @@ pub trait StdFloat: Sealed + Sized { fn fract(self) -> Self; } -impl Sealed for Simd {} -impl Sealed for Simd {} -impl Sealed for Simd {} - impl StdFloat for Simd { #[inline] fn fract(self) -> Self { From ae33abea636f41988aca494ffa8f76688174e286 Mon Sep 17 00:00:00 2001 From: Karl Meakin Date: Sat, 20 Jun 2026 00:24:37 +0100 Subject: [PATCH 07/31] Add `Mask::last_set` method For symmetry with `Mask::first_set` --- crates/core_simd/src/masks.rs | 63 +++++++++++++++++++++++++++++++-- crates/core_simd/tests/masks.rs | 15 +++++--- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index cb5d54020f7fc..847869c260a9b 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -361,8 +361,7 @@ where pub fn first_set(self) -> Option { // If bitmasks are efficient, using them is better if cfg!(target_feature = "sse") && N <= 64 { - let tz = self.to_bitmask().trailing_zeros(); - return if tz == 64 { None } else { Some(tz as usize) }; + return self.to_bitmask().lowest_one().map(|i| i as usize); } // To find the first set index: @@ -411,6 +410,66 @@ where Some(min_index) } } + + /// Finds the index of the last set element. + /// + /// ``` + /// # #![feature(portable_simd)] + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::mask32x8; + /// assert_eq!(mask32x8::splat(false).last_set(), None); + /// assert_eq!(mask32x8::splat(true).last_set(), Some(7)); + /// + /// let mask = mask32x8::from_array([false, true, false, false, true, false, true, false]); + /// assert_eq!(mask.last_set(), Some(6)); + /// ``` + #[inline] + #[must_use = "method returns the index and does not mutate the original value"] + pub fn last_set(self) -> Option { + // If bitmasks are efficient, using them is better + if cfg!(target_feature = "sse") && N <= 64 { + return self.to_bitmask().highest_one().map(|i| i as usize); + } + + // To find the first set index: + // * create a vector 0..N + // * replace unset mask elements in that vector with -1 + // * perform _signed_ reduce-max + // * check if the result is -1 or an index + + let index: Simd = const { + let mut index = [0; N]; + let mut i = 0; + while i < N { + index[i] = i; + i += 1; + } + // Safety: the input and output are integer vectors + unsafe { core::intrinsics::simd::simd_cast(Simd::from_array(index)) } + }; + + // Safety: the input and output are integer vectors + let masked_index: Simd = + unsafe { core::intrinsics::simd::simd_or((!self).to_simd(), index) }; + + // Safety: the input is an integer vector + let max_index: T = unsafe { core::intrinsics::simd::simd_reduce_max(masked_index) }; + + if max_index.eq(T::TRUE) { + None + } else { + let max_index = max_index.to_usize(); + + // Allow eliminating bounds checks when using the index + // Safety: the index can't exceed the number of elements in the vector + unsafe { + core::hint::assert_unchecked(max_index < N); + } + + Some(max_index) + } + } } // vector/array conversion diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs index 98a74be8e3955..6bcf02ee12075 100644 --- a/crates/core_simd/tests/masks.rs +++ b/crates/core_simd/tests/masks.rs @@ -138,14 +138,19 @@ macro_rules! test_mask_api { fn first_set() { for bitmask in 0..=u8::MAX { let mask = Mask::<$type, 8>::from_bitmask(bitmask as u64); - let expected = if bitmask == 0 { - None - } else { - Some(bitmask.trailing_zeros() as usize) - }; + let expected = bitmask.lowest_one().map(|i| i as usize); assert_eq!(mask.first_set(), expected); } } + + #[test] + fn last_set() { + for bitmask in 0..=u8::MAX { + let mask = Mask::<$type, 8>::from_bitmask(bitmask as u64); + let expected = bitmask.highest_one().map(|i| i as usize); + assert_eq!(mask.last_set(), expected); + } + } } } } From 30bdfe3a5f434b352e8860a722be64fe70d77658 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Fri, 19 Jun 2026 17:02:13 +0800 Subject: [PATCH 08/31] Optimize `swizzle_dyn` for LoongArch64 with N is 16 or 32 --- crates/core_simd/src/swizzle_dyn.rs | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/crates/core_simd/src/swizzle_dyn.rs b/crates/core_simd/src/swizzle_dyn.rs index cf37aff9a76d1..95fe086a4b4ab 100644 --- a/crates/core_simd/src/swizzle_dyn.rs +++ b/crates/core_simd/src/swizzle_dyn.rs @@ -48,6 +48,8 @@ impl Simd { target_endian = "little" ))] 16 => transize(armv7_neon_swizzle_u8x16, self, idxs), + #[cfg(all(target_arch = "loongarch64", target_feature = "lsx"))] + 16 => transize(loong64_lsx_swizzle, self, idxs), #[cfg(all(target_feature = "avx2", not(target_feature = "avx512vbmi")))] 32 => transize(avx2_pshufb, self, idxs), #[cfg(all(target_feature = "avx512vl", target_feature = "avx512vbmi"))] @@ -62,6 +64,8 @@ impl Simd { }; transize(swizzler, self, idxs) } + #[cfg(all(target_arch = "loongarch64", target_feature = "lasx"))] + 32 => transize(loong64_lasx_swizzle, self, idxs), // Notable absence: avx512bw pshufb shuffle #[cfg(all(target_feature = "avx512vl", target_feature = "avx512vbmi"))] 64 => { @@ -220,6 +224,38 @@ unsafe fn avx2_pshufb(bytes: Simd, idxs: Simd) -> Simd { } } +/// LoongArch64 LSX supports swizzling `u8x16` +/// +/// # Safety +/// This requires LoongArch LSX to work +#[cfg(all(target_arch = "loongarch64", target_feature = "lsx"))] +unsafe fn loong64_lsx_swizzle(bytes: Simd, idxs: Simd) -> Simd { + use core::arch::loongarch64::{lsx_vand_v, lsx_vshuf_b, lsx_vslei_bu}; + // SAFETY: Caller promised loongarch lsx support + unsafe { + let bytes = lsx_vshuf_b(bytes.into(), bytes.into(), idxs.into()); + let mask = lsx_vslei_bu::<15>(idxs.into()); + lsx_vand_v(bytes, mask).into() + } +} + +/// LoongArch64 LASX supports swizzling `u8x32` +/// +/// # Safety +/// This requires LoongArch LASX to work +#[cfg(all(target_arch = "loongarch64", target_feature = "lasx"))] +unsafe fn loong64_lasx_swizzle(bytes: Simd, idxs: Simd) -> Simd { + use core::arch::loongarch64::{lasx_xvand_v, lasx_xvpermi_q, lasx_xvshuf_b, lasx_xvslei_bu}; + // SAFETY: Caller promised loongarch lasx support + unsafe { + let lolo = lasx_xvpermi_q::<0x00>(bytes.into(), bytes.into()); + let hihi = lasx_xvpermi_q::<0x11>(bytes.into(), bytes.into()); + let bytes = lasx_xvshuf_b(hihi, lolo, idxs.into()); + let mask = lasx_xvslei_bu::<31>(idxs.into()); + lasx_xvand_v(bytes, mask).into() + } +} + /// This sets up a call to an architecture-specific function, and in doing so /// it persuades rustc that everything is the correct size. Which it is. /// This would not be needed if one could convince Rust that, by matching on N, From 0a63dc61114d79737fcfb46dc58bd60c29c63555 Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Mon, 11 May 2026 17:19:30 -0400 Subject: [PATCH 09/31] rustdoc-json: add paths for linked associated items --- src/librustdoc/json/mod.rs | 98 ++++++++++++++++--- .../rustdoc-json/intra-doc-links/non_page.rs | 13 +++ 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 2d6865dc689b6..6994e852d6d15 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -32,7 +32,9 @@ use crate::docfs::PathError; use crate::error::Error; use crate::formats::FormatRenderer; use crate::formats::cache::Cache; +use crate::formats::item_type::ItemType; use crate::json::conversions::IntoJson; +use crate::passes::collect_intra_doc_links::UrlFragment; use crate::{clean, try_err}; pub(crate) struct JsonRenderer<'tcx> { @@ -104,6 +106,84 @@ impl<'tcx> JsonRenderer<'tcx> { }) .unwrap_or_default() } + + fn paths(&self) -> FxHashMap { + let mut paths = self + .cache + .paths + .iter() + .chain(&self.cache.external_paths) + .map(|(&k, &(ref path, kind))| { + ( + self.id_from_item_default(k.into()), + types::ItemSummary { + crate_id: k.krate.as_u32(), + path: path.iter().map(|s| s.to_string()).collect(), + kind: kind.into_json(self), + }, + ) + }) + .collect(); + + self.add_intra_doc_link_paths(&mut paths); + paths + } + + #[allow(rustc::potential_query_instability)] + fn add_intra_doc_link_paths(&self, paths: &mut FxHashMap) { + // The link target IDs were already interned when the `links` maps were emitted. + // This only fills missing summaries in `paths`, where JSON object order is not meaningful. + for link in self.cache.intra_doc_links.values().flatten() { + let Some(UrlFragment::Item(item_id)) = link.fragment.as_ref() else { + continue; + }; + let item_id = *item_id; + let id = self.id_from_item_default(item_id.into()); + + if paths.contains_key(&id) || item_id.is_local() && !self.index.contains_key(&id) { + continue; + } + + let Some(path) = self.path_for_link_target(link.page_id, item_id) else { + continue; + }; + let kind = ItemType::from_def_id(item_id, self.tcx); + paths.insert( + id, + types::ItemSummary { + crate_id: item_id.krate.as_u32(), + path, + kind: kind.into_json(self), + }, + ); + } + } + + fn path_for_link_target(&self, page_id: DefId, item_id: DefId) -> Option> { + self.path_from_cached_parent(item_id).or_else(|| { + let mut path = self.path_from_cached_parent(page_id)?; + path.push(self.tcx.opt_item_name(item_id)?.to_string()); + Some(path) + }) + } + + fn path_from_cached_parent(&self, item_id: DefId) -> Option> { + let mut suffix = Vec::new(); + let mut current = item_id; + + loop { + if let Some((path, _)) = + self.cache.paths.get(¤t).or_else(|| self.cache.external_paths.get(¤t)) + { + let mut path = path.iter().map(|s| s.to_string()).collect::>(); + path.extend(suffix.into_iter().rev()); + return Some(path); + } + + suffix.push(self.tcx.opt_item_name(current)?.to_string()); + current = self.tcx.opt_parent(current)?; + } + } } impl<'tcx> JsonRenderer<'tcx> { @@ -248,26 +328,12 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { let target = conversions::target(sess); debug!("Constructing Output"); + let paths = self.paths(); let output_crate = types::Crate { root: self.id_from_item_default(e.def_id().into()), crate_version: self.cache.crate_version.clone(), includes_private: self.cache.document_private, - paths: self - .cache - .paths - .iter() - .chain(&self.cache.external_paths) - .map(|(&k, &(ref path, kind))| { - ( - self.id_from_item_default(k.into()), - types::ItemSummary { - crate_id: k.krate.as_u32(), - path: path.iter().map(|s| s.to_string()).collect(), - kind: kind.into_json(&self), - }, - ) - }) - .collect(), + paths, external_crates: self .cache .extern_locations diff --git a/tests/rustdoc-json/intra-doc-links/non_page.rs b/tests/rustdoc-json/intra-doc-links/non_page.rs index e2d00ee64e9c2..780907c944f71 100644 --- a/tests/rustdoc-json/intra-doc-links/non_page.rs +++ b/tests/rustdoc-json/intra-doc-links/non_page.rs @@ -6,6 +6,9 @@ //! [`Trait::AssocType`] //! [`Trait::ASSOC_CONST`] //! [`Trait::method`] +//! [`std::vec::Vec::push`] +//! [`std::io::ErrorKind::NotFound`] +//! [`usize::MAX`] //@ set struct_field = "$.index[?(@.name=='struct_field')].id" //@ set Variant = "$.index[?(@.name=='Variant')].id" @@ -19,6 +22,16 @@ //@ is "$.index[?(@.name=='non_page')].links['`Trait::ASSOC_CONST`']" $ASSOC_CONST //@ is "$.index[?(@.name=='non_page')].links['`Trait::method`']" $method +// Regression test for : +// link target IDs for associated items need matching `paths` entries. +//@ has "$.paths[*].path" '["non_page", "Struct", "struct_field"]' +//@ has "$.paths[*].path" '["non_page", "Trait", "AssocType"]' +//@ has "$.paths[*].path" '["non_page", "Trait", "ASSOC_CONST"]' +//@ has "$.paths[*].path" '["non_page", "Trait", "method"]' +//@ has "$.paths[*].path" '["alloc", "vec", "Vec", "push"]' +//@ has "$.paths[*].path" '["core", "io", "error", "ErrorKind", "NotFound"]' +//@ has "$.paths[*].path" '["std", "usize", "MAX"]' + pub struct Struct { pub struct_field: i32, } From 08fb51a92b23c45a1b9f6967d0fd8002a0ec375f Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Mon, 15 Jun 2026 06:47:44 -0400 Subject: [PATCH 10/31] address suggested nits --- src/librustdoc/json/mod.rs | 68 +++++++++++-------- .../rustdoc-json/intra-doc-links/non_page.rs | 3 + 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 6994e852d6d15..f161b31f94dcb 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -14,6 +14,7 @@ use std::io::{BufWriter, Write, stdout}; use std::path::PathBuf; use std::rc::Rc; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -129,24 +130,23 @@ impl<'tcx> JsonRenderer<'tcx> { paths } - #[allow(rustc::potential_query_instability)] fn add_intra_doc_link_paths(&self, paths: &mut FxHashMap) { // The link target IDs were already interned when the `links` maps were emitted. // This only fills missing summaries in `paths`, where JSON object order is not meaningful. - for link in self.cache.intra_doc_links.values().flatten() { + #[allow(rustc::potential_query_instability)] + let links = self.cache.intra_doc_links.values(); + for link in links.flatten() { let Some(UrlFragment::Item(item_id)) = link.fragment.as_ref() else { continue; }; let item_id = *item_id; let id = self.id_from_item_default(item_id.into()); - if paths.contains_key(&id) || item_id.is_local() && !self.index.contains_key(&id) { + if paths.contains_key(&id) || (item_id.is_local() && !self.index.contains_key(&id)) { continue; } - let Some(path) = self.path_for_link_target(link.page_id, item_id) else { - continue; - }; + let path = self.path_for_link_target(link.page_id, item_id); let kind = ItemType::from_def_id(item_id, self.tcx); paths.insert( id, @@ -159,30 +159,44 @@ impl<'tcx> JsonRenderer<'tcx> { } } - fn path_for_link_target(&self, page_id: DefId, item_id: DefId) -> Option> { - self.path_from_cached_parent(item_id).or_else(|| { - let mut path = self.path_from_cached_parent(page_id)?; - path.push(self.tcx.opt_item_name(item_id)?.to_string()); - Some(path) - }) - } - - fn path_from_cached_parent(&self, item_id: DefId) -> Option> { - let mut suffix = Vec::new(); - let mut current = item_id; - - loop { - if let Some((path, _)) = - self.cache.paths.get(¤t).or_else(|| self.cache.external_paths.get(¤t)) - { - let mut path = path.iter().map(|s| s.to_string()).collect::>(); - path.extend(suffix.into_iter().rev()); - return Some(path); + fn path_for_link_target(&self, page_id: DefId, item_id: DefId) -> Vec { + let parent_id = self.tcx.parent(item_id); + // Inherent items have an unnamed impl parent, while variant fields have one extra named + // parent between themselves and their page. + let (mut path, variant_id) = match self.tcx.def_kind(parent_id) { + DefKind::Impl { .. } => ( + self.cached_path(page_id).expect("intra-doc link page should have a cached path"), + None, + ), + DefKind::Variant => { + (self.path_for_named_item(self.tcx.parent(parent_id)), Some(parent_id)) } + _ => (self.path_for_named_item(parent_id), None), + }; - suffix.push(self.tcx.opt_item_name(current)?.to_string()); - current = self.tcx.opt_parent(current)?; + if let Some(variant_id) = variant_id { + path.push(self.tcx.item_name(variant_id).to_string()); } + path.push(self.tcx.item_name(item_id).to_string()); + path + } + + fn path_for_named_item(&self, item_id: DefId) -> Vec { + self.cached_path(item_id).unwrap_or_else(|| { + let kind = ItemType::from_def_id(item_id, self.tcx); + clean::inline::get_item_path(self.tcx, item_id, kind) + .into_iter() + .map(|name| name.to_string()) + .collect() + }) + } + + fn cached_path(&self, item_id: DefId) -> Option> { + self.cache + .paths + .get(&item_id) + .or_else(|| self.cache.external_paths.get(&item_id)) + .map(|(path, _)| path.iter().map(|name| name.to_string()).collect()) } } diff --git a/tests/rustdoc-json/intra-doc-links/non_page.rs b/tests/rustdoc-json/intra-doc-links/non_page.rs index 780907c944f71..a395c02099afe 100644 --- a/tests/rustdoc-json/intra-doc-links/non_page.rs +++ b/tests/rustdoc-json/intra-doc-links/non_page.rs @@ -3,6 +3,7 @@ //! [`Struct::struct_field`] //! [`Enum::Variant`] +//! [`Enum::StructVariant::field`] //! [`Trait::AssocType`] //! [`Trait::ASSOC_CONST`] //! [`Trait::method`] @@ -25,6 +26,7 @@ // Regression test for : // link target IDs for associated items need matching `paths` entries. //@ has "$.paths[*].path" '["non_page", "Struct", "struct_field"]' +//@ has "$.paths[*].path" '["non_page", "Enum", "StructVariant", "field"]' //@ has "$.paths[*].path" '["non_page", "Trait", "AssocType"]' //@ has "$.paths[*].path" '["non_page", "Trait", "ASSOC_CONST"]' //@ has "$.paths[*].path" '["non_page", "Trait", "method"]' @@ -38,6 +40,7 @@ pub struct Struct { pub enum Enum { Variant(), + StructVariant { field: i32 }, } pub trait Trait { From c78d0a7cb9cc17f89c9ec68b0516e33a5cce647e Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Thu, 16 Jul 2026 07:51:44 -0400 Subject: [PATCH 11/31] test with IDs as suggested --- .../rustdoc-json/intra-doc-links/non_page.rs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/rustdoc-json/intra-doc-links/non_page.rs b/tests/rustdoc-json/intra-doc-links/non_page.rs index a395c02099afe..19c8011399db2 100644 --- a/tests/rustdoc-json/intra-doc-links/non_page.rs +++ b/tests/rustdoc-json/intra-doc-links/non_page.rs @@ -25,14 +25,23 @@ // Regression test for : // link target IDs for associated items need matching `paths` entries. -//@ has "$.paths[*].path" '["non_page", "Struct", "struct_field"]' -//@ has "$.paths[*].path" '["non_page", "Enum", "StructVariant", "field"]' -//@ has "$.paths[*].path" '["non_page", "Trait", "AssocType"]' -//@ has "$.paths[*].path" '["non_page", "Trait", "ASSOC_CONST"]' -//@ has "$.paths[*].path" '["non_page", "Trait", "method"]' -//@ has "$.paths[*].path" '["alloc", "vec", "Vec", "push"]' -//@ has "$.paths[*].path" '["core", "io", "error", "ErrorKind", "NotFound"]' -//@ has "$.paths[*].path" '["std", "usize", "MAX"]' +//@ jq_set crate = '.index[] | select(.name == "non_page")' +//@ jq_set struct_field_link = '$crate.links["`Struct::struct_field`"]' +//@ jq_set variant_field_link = '$crate.links["`Enum::StructVariant::field`"]' +//@ jq_set assoc_type_link = '$crate.links["`Trait::AssocType`"]' +//@ jq_set assoc_const_link = '$crate.links["`Trait::ASSOC_CONST`"]' +//@ jq_set method_link = '$crate.links["`Trait::method`"]' +//@ jq_set vec_push_link = '$crate.links["`std::vec::Vec::push`"]' +//@ jq_set error_kind_link = '$crate.links["`std::io::ErrorKind::NotFound`"]' +//@ jq_set usize_max_link = '$crate.links["`usize::MAX`"]' +//@ jq_is '.paths["\($struct_field_link)"].path' '["non_page", "Struct", "struct_field"]' +//@ jq_is '.paths["\($variant_field_link)"].path' '["non_page", "Enum", "StructVariant", "field"]' +//@ jq_is '.paths["\($assoc_type_link)"].path' '["non_page", "Trait", "AssocType"]' +//@ jq_is '.paths["\($assoc_const_link)"].path' '["non_page", "Trait", "ASSOC_CONST"]' +//@ jq_is '.paths["\($method_link)"].path' '["non_page", "Trait", "method"]' +//@ jq_is '.paths["\($vec_push_link)"].path' '["alloc", "vec", "Vec", "push"]' +//@ jq_is '.paths["\($error_kind_link)"].path' '["core", "io", "error", "ErrorKind", "NotFound"]' +//@ jq_is '.paths["\($usize_max_link)"].path' '["std", "usize", "MAX"]' pub struct Struct { pub struct_field: i32, From da5e0cfaa0605179cc8859456b9a2fdb215d675f Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 1 Jul 2026 17:55:15 +1000 Subject: [PATCH 12/31] Add splat mangling bug tests (flaky?) --- tests/ui/splat/splat-mangling.default.stderr | 4 ++++ tests/ui/splat/splat-mangling.rs | 24 ++++++++++++++++++++ tests/ui/splat/splat-mangling.v0.stderr | 4 ++++ 3 files changed, 32 insertions(+) create mode 100644 tests/ui/splat/splat-mangling.default.stderr create mode 100644 tests/ui/splat/splat-mangling.rs create mode 100644 tests/ui/splat/splat-mangling.v0.stderr diff --git a/tests/ui/splat/splat-mangling.default.stderr b/tests/ui/splat/splat-mangling.default.stderr new file mode 100644 index 0000000000000..e4ba3be9c5cd9 --- /dev/null +++ b/tests/ui/splat/splat-mangling.default.stderr @@ -0,0 +1,4 @@ +error: symbol `_RNvMNtCsCRATE_HASH_4core6optionINtB2_6OptionFTlEEuE6unwrapCsCRATE_HASH_14splat_mangling` is already defined + +error: aborting due to 1 previous error + diff --git a/tests/ui/splat/splat-mangling.rs b/tests/ui/splat/splat-mangling.rs new file mode 100644 index 0000000000000..4bb75a50a5c59 --- /dev/null +++ b/tests/ui/splat/splat-mangling.rs @@ -0,0 +1,24 @@ +//! Test that splat influences symbol mangling. +//@ revisions: default legacy v0 +//@ [default] compile-flags: -C opt-level=0 +//@ [legacy] compile-flags: -C opt-level=0 -Z unstable-options -Csymbol-mangling-version=legacy +//@ [v0] compile-flags: -C opt-level=0 -Z unstable-options -Csymbol-mangling-version=v0 +//@ [default] build-fail +//@ [legacy] run-fail +//@ [v0] build-fail +//@ incremental + +#![allow(incomplete_features)] +#![feature(splat)] + +fn main() { + // Bug #158603 regression test variants + #[rustfmt::skip] + let _x: fn(#[splat] (i32,)) = None.unwrap(); + + //@ [default] regex-error-pattern: symbol `.*Option.*unwrap.*splat_mangling` is already defined + //@ [v0] regex-error-pattern: symbol `.*Option.*unwrap.*splat_mangling` is already defined + //[default,v0]~? ERROR: is already defined + let x: fn((i32,)) = None.unwrap(); + x((1,)); +} diff --git a/tests/ui/splat/splat-mangling.v0.stderr b/tests/ui/splat/splat-mangling.v0.stderr new file mode 100644 index 0000000000000..e4ba3be9c5cd9 --- /dev/null +++ b/tests/ui/splat/splat-mangling.v0.stderr @@ -0,0 +1,4 @@ +error: symbol `_RNvMNtCsCRATE_HASH_4core6optionINtB2_6OptionFTlEEuE6unwrapCsCRATE_HASH_14splat_mangling` is already defined + +error: aborting due to 1 previous error + From cbb216962bf221a0a0b48f66bd904b061485f1e1 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 7 Jul 2026 11:18:41 +1000 Subject: [PATCH 13/31] Implement v0 symbol mangling for splat --- compiler/rustc_symbol_mangling/src/v0.rs | 11 +- compiler/rustc_type_ir/src/ty_kind.rs | 4 + tests/ui/splat/splat-mangling-issue-158644.rs | 18 +++ tests/ui/splat/splat-mangling.default.stderr | 146 +++++++++++++++++- tests/ui/splat/splat-mangling.legacy.stderr | 146 ++++++++++++++++++ tests/ui/splat/splat-mangling.rs | 102 ++++++++++-- tests/ui/splat/splat-mangling.v0.stderr | 146 +++++++++++++++++- 7 files changed, 555 insertions(+), 18 deletions(-) create mode 100644 tests/ui/splat/splat-mangling-issue-158644.rs create mode 100644 tests/ui/splat/splat-mangling.legacy.stderr diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index b186aae5222da..f89f052fd72bb 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -566,6 +566,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { } ty::FnPtr(sig_tys, hdr) => { + let splatted_arg_index = hdr.splatted().map(usize::from); let sig = sig_tys.with(hdr); self.push("F"); self.wrap_binder(&sig, |p, sig| { @@ -585,7 +586,15 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { } } } - for &ty in sig.inputs() { + for (i, &ty) in sig.inputs().iter().enumerate() { + if splatted_arg_index == Some(i) { + // The splat feature is unstable and its mangling is subject to change + // FIXME(splat): + // - for efficiency we might want to use a letter that can't occur in any type, rather than + // taking an unused letter + // - splat isn't implemented for legacy mangling + p.push("w"); + } ty.print(p)?; } if sig.c_variadic() { diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 68eebb1122928..d3406f4ec7a72 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1403,6 +1403,10 @@ impl FnHeader { self.fn_sig_kind.abi() } + pub fn splatted(self) -> Option { + self.fn_sig_kind.splatted() + } + /// Create a new safe FnHeader with the `extern "Rust"` ABI, that isn't C-style variadic or splatted. pub fn dummy() -> Self { Self { fn_sig_kind: FnSigKind::dummy() } diff --git a/tests/ui/splat/splat-mangling-issue-158644.rs b/tests/ui/splat/splat-mangling-issue-158644.rs new file mode 100644 index 0000000000000..337670ea3f179 --- /dev/null +++ b/tests/ui/splat/splat-mangling-issue-158644.rs @@ -0,0 +1,18 @@ +//! Test that splat influences symbol mangling, regression test for #158644 +//@ revisions: default legacy v0 +//@ [default] compile-flags: -C opt-level=0 +//@ [legacy] compile-flags: -C opt-level=0 -Z unstable-options -Csymbol-mangling-version=legacy +//@ [v0] compile-flags: -C opt-level=0 -Z unstable-options -Csymbol-mangling-version=v0 +//@ run-fail +//@ incremental + +#![allow(incomplete_features)] +#![feature(splat)] + +fn main() { + #[rustfmt::skip] + let _x: fn(#[splat] (i32,)) = None.unwrap(); + + let x: fn((i32,)) = None.unwrap(); + x((1,)); +} diff --git a/tests/ui/splat/splat-mangling.default.stderr b/tests/ui/splat/splat-mangling.default.stderr index e4ba3be9c5cd9..ebe82cea89b62 100644 --- a/tests/ui/splat/splat-mangling.default.stderr +++ b/tests/ui/splat/splat-mangling.default.stderr @@ -1,4 +1,146 @@ -error: symbol `_RNvMNtCsCRATE_HASH_4core6optionINtB2_6OptionFTlEEuE6unwrapCsCRATE_HASH_14splat_mangling` is already defined +error: symbol-name(_RMNvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwThmEEuE) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: demangling(>) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFThmEEuE) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs0_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwTThmEEEuE) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs1_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFTThmEEEuE) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs2_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypePFwTmaEEuE) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs3_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypePFTmaEEuE) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs4_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwTmaEdEuE) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs5_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFTmaEdEuE) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors diff --git a/tests/ui/splat/splat-mangling.legacy.stderr b/tests/ui/splat/splat-mangling.legacy.stderr new file mode 100644 index 0000000000000..b1ecd890478e9 --- /dev/null +++ b/tests/ui/splat/splat-mangling.legacy.stderr @@ -0,0 +1,146 @@ +error: symbol-name(_ZN14splat_mangling4main66Type$LT$fn$LP$$C$$u20$$u23$$u5b$splat$u5d$$LP$u8$C$u32$RP$$RP$$GT$17hCRATE_HASHE) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(splat_mangling::main::Type::hCRATE_HASH) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(splat_mangling::main::Type) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN14splat_mangling4main38Type$LT$fn$LP$$LP$u8$C$u32$RP$$RP$$GT$17hCRATE_HASHE) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(splat_mangling::main::Type::hCRATE_HASH) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(splat_mangling::main::Type) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN14splat_mangling4main77Type$LT$fn$LP$$C$$u20$$u23$$u5b$splat$u5d$$LP$$LP$u8$C$u32$RP$$C$$RP$$RP$$GT$17hCRATE_HASHE) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(splat_mangling::main::Type::hCRATE_HASH) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(splat_mangling::main::Type) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN14splat_mangling4main49Type$LT$fn$LP$$LP$$LP$u8$C$u32$RP$$C$$RP$$RP$$GT$17hCRATE_HASHE) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(splat_mangling::main::Type::hCRATE_HASH) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(splat_mangling::main::Type) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN14splat_mangling4main80Type$LT$$BP$const$u20$fn$LP$$C$$u20$$u23$$u5b$splat$u5d$$LP$u32$C$i8$RP$$RP$$GT$17hCRATE_HASHE) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(splat_mangling::main::Type<*const fn(, #[splat](u32,i8))>::hCRATE_HASH) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(splat_mangling::main::Type<*const fn(, #[splat](u32,i8))>) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN14splat_mangling4main52Type$LT$$BP$const$u20$fn$LP$$LP$u32$C$i8$RP$$RP$$GT$17hCRATE_HASHE) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(splat_mangling::main::Type<*const fn((u32,i8))>::hCRATE_HASH) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(splat_mangling::main::Type<*const fn((u32,i8))>) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN14splat_mangling4main72Type$LT$fn$LP$$C$$u20$$u23$$u5b$splat$u5d$$LP$u32$C$i8$RP$$C$f64$RP$$GT$17hCRATE_HASHE) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(splat_mangling::main::Type::hCRATE_HASH) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(splat_mangling::main::Type) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_ZN14splat_mangling4main44Type$LT$fn$LP$$LP$u32$C$i8$RP$$C$f64$RP$$GT$17hCRATE_HASHE) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(splat_mangling::main::Type::hCRATE_HASH) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(splat_mangling::main::Type) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors + diff --git a/tests/ui/splat/splat-mangling.rs b/tests/ui/splat/splat-mangling.rs index 4bb75a50a5c59..0de330d5f0f65 100644 --- a/tests/ui/splat/splat-mangling.rs +++ b/tests/ui/splat/splat-mangling.rs @@ -1,24 +1,100 @@ -//! Test that splat influences symbol mangling. +//! Test for splat symbol mangling. //@ revisions: default legacy v0 //@ [default] compile-flags: -C opt-level=0 //@ [legacy] compile-flags: -C opt-level=0 -Z unstable-options -Csymbol-mangling-version=legacy //@ [v0] compile-flags: -C opt-level=0 -Z unstable-options -Csymbol-mangling-version=v0 -//@ [default] build-fail -//@ [legacy] run-fail -//@ [v0] build-fail -//@ incremental +//@ build-fail + +// CRATE_HASH normalization doesn't seem to work on some of these symbol logs +//@ normalize-stderr: "splat_mangling\[([0-9a-f]{16})\]::" -> "splat_mangling[CRATE_HASH]::" +//@ normalize-stderr: "h([0-9a-f]{16})E\)" -> "hCRATE_HASHE)" +//@ normalize-stderr: "::h([0-9a-f]{16})\)" -> "::hCRATE_HASH)" #![allow(incomplete_features)] -#![feature(splat)] +#![feature(splat, rustc_attrs)] fn main() { - // Bug #158603 regression test variants + struct Type(T); + + // FIXME(rustfmt): the attribute gets deleted by rustfmt + #[rustfmt::skip] + // FIXME(splat, legacy mangling): the first comma is in the wrong place + #[rustc_dump_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN14splat_mangling4main66Type$LT$fn$LP$$C$$u20$$u23$$u5b$splat$u5d$$LP$u8$C$u32$RP$$RP$$GT + //[legacy]~| ERROR demangling(splat_mangling::main::Type:: + //[legacy]~| ERROR demangling-alt(splat_mangling::main::Type) + //[v0,default]~^^^^ ERROR symbol-name(_RMNvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwThmEEuE) + //[v0,default]~| ERROR demangling(>) + impl Type {} + + #[rustfmt::skip] + #[rustc_dump_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN14splat_mangling4main38Type$LT$fn$LP$$LP$u8$C$u32$RP$$RP$$GT + //[legacy]~| ERROR demangling(splat_mangling::main::Type:: + //[legacy]~| ERROR demangling-alt(splat_mangling::main::Type) + //[v0,default]~^^^^ ERROR symbol-name(_RMs_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFThmEEuE) + //[v0,default]~| ERROR demangling(>) + impl Type {} + + #[rustfmt::skip] + #[rustc_dump_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN14splat_mangling4main77Type$LT$fn$LP$$C$$u20$$u23$$u5b$splat$u5d$$LP$$LP$u8$C$u32$RP$$C$$RP$$RP$$GT + //[legacy]~| ERROR demangling(splat_mangling::main::Type:: + //[legacy]~| ERROR demangling-alt(splat_mangling::main::Type) + //[v0,default]~^^^^ ERROR symbol-name(_RMs0_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwTThmEEEuE) + //[v0,default]~| ERROR demangling(>) + impl Type {} + #[rustfmt::skip] - let _x: fn(#[splat] (i32,)) = None.unwrap(); + #[rustc_dump_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN14splat_mangling4main49Type$LT$fn$LP$$LP$$LP$u8$C$u32$RP$$C$$RP$$RP$$GT + //[legacy]~| ERROR demangling(splat_mangling::main::Type:: + //[legacy]~| ERROR demangling-alt(splat_mangling::main::Type) + //[v0,default]~^^^^ ERROR symbol-name(_RMs1_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFTThmEEEuE) + //[v0,default]~| ERROR demangling(>) + impl Type {} - //@ [default] regex-error-pattern: symbol `.*Option.*unwrap.*splat_mangling` is already defined - //@ [v0] regex-error-pattern: symbol `.*Option.*unwrap.*splat_mangling` is already defined - //[default,v0]~? ERROR: is already defined - let x: fn((i32,)) = None.unwrap(); - x((1,)); + #[rustfmt::skip] + #[rustc_dump_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN14splat_mangling4main80Type$LT$$BP$const$u20$fn$LP$$C$$u20$$u23$$u5b$splat$u5d$$LP$u32$C$i8$RP$$RP$$GT + //[legacy]~| ERROR demangling(splat_mangling::main::Type<*const fn(, #[splat](u32,i8))>:: + //[legacy]~| ERROR demangling-alt(splat_mangling::main::Type<*const fn(, #[splat](u32,i8))>) + //[v0,default]~^^^^ ERROR symbol-name(_RMs2_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypePFwTmaEEuE) + //[v0,default]~| ERROR demangling(>) + impl Type<*const fn(#[splat] (u32, i8))> {} + + #[rustfmt::skip] + #[rustc_dump_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN14splat_mangling4main52Type$LT$$BP$const$u20$fn$LP$$LP$u32$C$i8$RP$$RP$$GT + //[legacy]~| ERROR demangling(splat_mangling::main::Type<*const fn((u32,i8))>:: + //[legacy]~| ERROR demangling-alt(splat_mangling::main::Type<*const fn((u32,i8))>) + //[v0,default]~^^^^ ERROR symbol-name(_RMs3_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypePFTmaEEuE) + //[v0,default]~| ERROR demangling(>) + impl Type<*const fn((u32, i8))> {} + + #[rustfmt::skip] + #[rustc_dump_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN14splat_mangling4main72Type$LT$fn$LP$$C$$u20$$u23$$u5b$splat$u5d$$LP$u32$C$i8$RP$$C$f64$RP$$GT + //[legacy]~| ERROR demangling(splat_mangling::main::Type:: + //[legacy]~| ERROR demangling-alt(splat_mangling::main::Type) + //[v0,default]~^^^^ ERROR symbol-name(_RMs4_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwTmaEdEuE) + //[v0,default]~| ERROR demangling(>) + impl Type {} + + #[rustfmt::skip] + #[rustc_dump_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN14splat_mangling4main44Type$LT$fn$LP$$LP$u32$C$i8$RP$$C$f64$RP$$GT + //[legacy]~| ERROR demangling(splat_mangling::main::Type:: + //[legacy]~| ERROR demangling-alt(splat_mangling::main::Type) + //[v0,default]~^^^^ ERROR symbol-name(_RMs5_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFTmaEdEuE) + //[v0,default]~| ERROR demangling(>) + impl Type {} } diff --git a/tests/ui/splat/splat-mangling.v0.stderr b/tests/ui/splat/splat-mangling.v0.stderr index e4ba3be9c5cd9..ebe82cea89b62 100644 --- a/tests/ui/splat/splat-mangling.v0.stderr +++ b/tests/ui/splat/splat-mangling.v0.stderr @@ -1,4 +1,146 @@ -error: symbol `_RNvMNtCsCRATE_HASH_4core6optionINtB2_6OptionFTlEEuE6unwrapCsCRATE_HASH_14splat_mangling` is already defined +error: symbol-name(_RMNvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwThmEEuE) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: demangling(>) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:22:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFThmEEuE) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:32:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs0_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwTThmEEEuE) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:42:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs1_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFTThmEEEuE) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:52:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs2_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypePFwTmaEEuE) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:62:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs3_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypePFTmaEEuE) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:72:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs4_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFwTmaEdEuE) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:82:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RMs5_NvCsCRATE_HASH_14splat_mangling4mainINtB_4TypeFTmaEdEuE) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/splat-mangling.rs:92:5 + | +LL | #[rustc_dump_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors From 553dbd7c46a47684fff30cdac7b84d9d99e210ad Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 14 Jul 2026 11:46:44 +1000 Subject: [PATCH 14/31] Doc splat mangling in the reference --- src/doc/rustc/src/symbol-mangling/v0.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md index 89d10658bb7e8..db7276e2cce0d 100644 --- a/src/doc/rustc/src/symbol-mangling/v0.md +++ b/src/doc/rustc/src/symbol-mangling/v0.md @@ -704,6 +704,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re [array-type]: #array-type [slice-type]: #slice-type [tuple-type]: #tuple-type +[splatted-type]: #splatted-type [ref-type]: #ref-type [mut-ref-type]: #mut-ref-type [const-ptr-type]: #const-ptr-type @@ -717,6 +718,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re >    | *[array-type]* \ >    | *[slice-type]* \ >    | *[tuple-type]* \ +>    | *[splatted-type]* \ >    | *[ref-type]* \ >    | *[mut-ref-type]* \ >    | *[const-ptr-type]* \ @@ -776,6 +778,14 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`. Note that a zero-length tuple (unit) is encoded with the `u` *[basic-type]*. +* `w` — A [splatted type][tracking-splat] `#[splat] T`. + + > splatted-type → `w` {*[type]*} + + The tag `w` is followed by the *[type]* being splatted. + + Note that the splat feature is unstable and subject to change or removal. + * `R` — A [reference][reference-shared-reference] `&T`. > ref-type → `R` *[lifetime]*opt *[type]* @@ -1268,3 +1278,4 @@ The compiler has some latitude in how an entity is encoded as long as the symbol [reference-traits]: ../../reference/items/traits.html [reference-tuple]: ../../reference/types/tuple.html [reference-types]: ../../reference/types.html +[tracking-splat]: https://github.com/rust-lang/rust/issues/153629 From a34aad0e4c362d862f437d53f9015c39d11b3f78 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 14 Jul 2026 12:02:16 +1000 Subject: [PATCH 15/31] Fix typo in symbol-mangling/v0.md --- src/doc/rustc/src/symbol-mangling/v0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md index db7276e2cce0d..982e372943766 100644 --- a/src/doc/rustc/src/symbol-mangling/v0.md +++ b/src/doc/rustc/src/symbol-mangling/v0.md @@ -842,7 +842,7 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`. [fn-sig]: #fn-sig [abi]: #abi -* `W` — A [pattern-type][pattern-tpye] `u32 is 0..100`. +* `W` — A [pattern-type][pattern-type] `u32 is 0..100`. > pattern-type → `W` *[pattern-kind]* > > pattern-kind → \ From e09b8878215c40710f7218a7eaefeffe7ee6486e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 20 Jul 2026 10:49:36 +0200 Subject: [PATCH 16/31] fix feature gate --- library/portable-simd/crates/std_float/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs index 4714881bcdad3..d9499e539365f 100644 --- a/library/portable-simd/crates/std_float/src/lib.rs +++ b/library/portable-simd/crates/std_float/src/lib.rs @@ -1,18 +1,17 @@ -#![feature(impl_restriction)] #![cfg_attr( feature = "as_crate", feature(core_intrinsics), feature(portable_simd), feature(f16), + feature(impl_restriction), allow(internal_features) )] +use core::intrinsics::simd as intrinsics; #[cfg(not(feature = "as_crate"))] use core::simd; + #[cfg(feature = "as_crate")] use core_simd::simd; - -use core::intrinsics::simd as intrinsics; - use simd::Simd; /// This trait provides a possibly-temporary implementation of float functions From b045903e32d5650c6713f4030e81a1703ff03614 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 20 Jul 2026 10:49:53 +0200 Subject: [PATCH 17/31] remove now-dead `Sealed` trait --- library/std/src/lib.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index a2582355d6794..a912060a74ce2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -808,25 +808,6 @@ include!("../../core/src/primitive_docs.rs"); #[unstable(feature = "restricted_std", issue = "none")] mod __restricted_std_workaround {} -// FIXME(jhpratt) This is currently only used by portable SIMD. Once rust-lang/portable-simd#529 is -// merged, this should be able to be removed. -mod sealed { - /// This trait being unreachable from outside the crate - /// prevents outside implementations of our extension traits. - /// This allows adding more trait methods in the future. - #[unstable(feature = "sealed", issue = "none")] - pub trait Sealed {} -} - -macro_rules! impl_sealed { - ($($t:ty)*) => {$( - /// Allows implementations within `std`. - #[unstable(feature = "sealed", issue = "none")] - impl crate::sealed::Sealed for $t {} - )*} -} -impl_sealed! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 f32 f64 } - #[cfg(test)] #[allow(dead_code)] // Not used in all configurations. pub(crate) mod test_helpers; From 76298612b0d72a6a664ec50a4fd3af496a5c2160 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 20 Jul 2026 12:17:33 +0200 Subject: [PATCH 18/31] fix simd tests that use `without_provenance{_mut}` --- src/tools/miri/tests/pass/intrinsics/portable-simd-ptrs.rs | 2 +- ...r.enumerated_loop.runtime-optimized.after.panic-unwind.mir | 2 +- ...iter.forward_loop.runtime-optimized.after.panic-unwind.mir | 4 ++-- ...iter.reverse_loop.runtime-optimized.after.panic-unwind.mir | 2 +- ...r.slice_iter_next.runtime-optimized.after.panic-unwind.mir | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd-ptrs.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd-ptrs.rs index 096ec78da1a0e..df5cdaacfa869 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd-ptrs.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd-ptrs.rs @@ -8,5 +8,5 @@ fn main() { // Pointer casts let _val: Simd<*const u8, 4> = Simd::<*const i32, 4>::splat(ptr::null()).cast(); let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_provenance(); - let _ptrs = Simd::<*const i32, 4>::with_exposed_provenance(addrs); + let _ptrs: Simd<*const i32, 4> = std::simd::ptr::with_exposed_provenance(addrs); } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-unwind.mir index 034416c173b49..bdb72abeac7e4 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-unwind.mir @@ -35,7 +35,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 7 { } scope 11 (inlined std::ptr::without_provenance::) { - scope 12 (inlined without_provenance_mut::) { + scope 12 (inlined std::ptr::without_provenance_mut::) { } } scope 13 (inlined NonNull::::as_ptr) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.runtime-optimized.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.runtime-optimized.after.panic-unwind.mir index 3bcd93396f614..dc5feaa1344b0 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.runtime-optimized.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.runtime-optimized.after.panic-unwind.mir @@ -34,7 +34,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 25 (inlined without_provenance_mut::) { + scope 25 (inlined std::ptr::without_provenance_mut::) { } } scope 20 (inlined std::ptr::const_ptr::::addr) { @@ -77,7 +77,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 7 { } scope 11 (inlined std::ptr::without_provenance::) { - scope 12 (inlined without_provenance_mut::) { + scope 12 (inlined std::ptr::without_provenance_mut::) { } } scope 13 (inlined NonNull::::as_ptr) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.runtime-optimized.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.runtime-optimized.after.panic-unwind.mir index d0b125be28d4f..c11eab18521dd 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.runtime-optimized.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.runtime-optimized.after.panic-unwind.mir @@ -103,7 +103,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 7 { } scope 11 (inlined std::ptr::without_provenance::) { - scope 12 (inlined without_provenance_mut::) { + scope 12 (inlined std::ptr::without_provenance_mut::) { } } scope 13 (inlined NonNull::::as_ptr) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.runtime-optimized.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.runtime-optimized.after.panic-unwind.mir index 7596384ac4a89..889d7c1e69afb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.runtime-optimized.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.runtime-optimized.after.panic-unwind.mir @@ -21,7 +21,7 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } } } - scope 10 (inlined without_provenance_mut::) { + scope 10 (inlined std::ptr::without_provenance_mut::) { } } scope 5 (inlined std::ptr::const_ptr::::addr) { From f32f69b3c9fd6885c6e905071be99dded66da9e0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 20 Jul 2026 18:26:30 +0200 Subject: [PATCH 19/31] disable `portable_simd` miri test that needs additional intrinsic support --- src/tools/miri/tests/pass/intrinsics/portable-simd.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index ac7838247f288..e507e92624bde 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -766,6 +766,11 @@ fn simd_swizzle() { } fn simd_swizzle_dyn() { + // FIXME: needs llvm.neon.tbl2 support, see https://github.com/rust-lang/miri/pull/5219. + if cfg!(target_arch = "aarch64") { + return; + } + fn check_swizzle_dyn() { assert_eq!( Simd::::default().swizzle_dyn(Simd::::default()), From 002c50aec5bfb0b8789db3486bd3a02b24e759e1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 18 Jul 2026 15:02:34 +0200 Subject: [PATCH 20/31] Bring runtime symbols `static`s on par with foreign functions --- compiler/rustc_lint/src/lints.rs | 2 +- compiler/rustc_lint/src/runtime_symbols.rs | 48 ++++++++++++++++------ tests/ui/lint/runtime-symbols-unix.stderr | 2 +- tests/ui/lint/runtime-symbols.rs | 6 +++ tests/ui/lint/runtime-symbols.stderr | 30 +++++++++----- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7ea5635034a27..290f82808b4ca 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -864,7 +864,7 @@ pub(crate) enum RedefiningRuntimeSymbolsDiag<'tcx> { )] #[note( "expected `{$expected_fn_sig}` - found `static {$symbol_name}: {$static_ty}`" + found `{$static_ty}`" )] #[help( "either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = \"{$symbol_name}\")]`" diff --git a/compiler/rustc_lint/src/runtime_symbols.rs b/compiler/rustc_lint/src/runtime_symbols.rs index a8fbddb693bab..7657d55ac8489 100644 --- a/compiler/rustc_lint/src/runtime_symbols.rs +++ b/compiler/rustc_lint/src/runtime_symbols.rs @@ -203,34 +203,58 @@ fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId return; }; + // Get the expected symbol function signature + let lang_sig = cx.tcx.normalize_erasing_regions( + cx.typing_env(), + cx.tcx.fn_sig(expected_def_id).instantiate_identity(), + ); + // Get the static type - let static_ty = cx.tcx.type_of(did).instantiate_identity().skip_norm_wip(); + let outer_user_sig = cx.tcx.type_of(did).instantiate_identity().skip_norm_wip(); // Peel Option<...> and get the inner type (see std weak! macro with #[linkage = "extern_weak"]) - let inner_static_ty: Ty<'_> = match static_ty.kind() { + let user_sig: Ty<'_> = match outer_user_sig.kind() { ty::Adt(def, args) if Some(def.did()) == cx.tcx.lang_items().option_type() => { args.type_at(0) } - _ => static_ty, + _ => outer_user_sig, }; - // Get the expected symbol function signature - let lang_sig = cx.tcx.normalize_erasing_regions( - cx.typing_env(), - cx.tcx.fn_sig(expected_def_id).instantiate_identity(), - ); + let user_sig = if let ty::FnPtr(sig_tys, hdr) = user_sig.kind() { + sig_tys.with(*hdr) + } else { + // not a function pointer, report an error - let expected = Ty::new_fn_ptr(cx.tcx, lang_sig); + let lang_sig = Ty::new_fn_ptr(cx.tcx, lang_sig); + cx.emit_span_lint( + INVALID_RUNTIME_SYMBOL_DEFINITIONS, + sp, + RedefiningRuntimeSymbolsDiag::Static { + static_ty: user_sig, + symbol_name: symbol_name.to_string(), + expected_fn_sig: lang_sig, + }, + ); + return; + }; + + // Compare the two signatures with an inference context + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); + let cause = rustc_middle::traits::ObligationCause::misc(sp, did); + let result = infcx.at(&cause, cx.param_env).eq(DefineOpaqueTypes::No, lang_sig, user_sig); // Compare the expected function signature with the static type, report an error if they don't match - if expected != inner_static_ty { + if result.is_err() { + let user_sig = Ty::new_fn_ptr(cx.tcx, user_sig); + let lang_sig = Ty::new_fn_ptr(cx.tcx, lang_sig); + cx.emit_span_lint( INVALID_RUNTIME_SYMBOL_DEFINITIONS, sp, RedefiningRuntimeSymbolsDiag::Static { - static_ty, + static_ty: user_sig, symbol_name: symbol_name.to_string(), - expected_fn_sig: expected, + expected_fn_sig: lang_sig, }, ); } diff --git a/tests/ui/lint/runtime-symbols-unix.stderr b/tests/ui/lint/runtime-symbols-unix.stderr index 7ef765c29684d..acc29779f2074 100644 --- a/tests/ui/lint/runtime-symbols-unix.stderr +++ b/tests/ui/lint/runtime-symbols-unix.stderr @@ -36,7 +36,7 @@ LL | pub static close: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: expected `unsafe extern "C" fn(i32) -> i32` - found `static close: ()` + found `()` = help: either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = "close")]` error: invalid definition of the runtime `malloc` symbol used by the standard library diff --git a/tests/ui/lint/runtime-symbols.rs b/tests/ui/lint/runtime-symbols.rs index 9b03f43c8cfaf..ddcae715af3af 100644 --- a/tests/ui/lint/runtime-symbols.rs +++ b/tests/ui/lint/runtime-symbols.rs @@ -25,6 +25,12 @@ fn invalid() { pub static strlen: () = (); //~^ ERROR invalid definition of the runtime `strlen` symbol + extern "C" { + #[link_name = "strlen"] + static strlen2: Option; + //~^ ERROR invalid definition of the runtime `strlen` symbol + } + // ABI mismatch: Rust ABI instead of C ABI #[no_mangle] pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void { diff --git a/tests/ui/lint/runtime-symbols.stderr b/tests/ui/lint/runtime-symbols.stderr index 712f6532c1a59..099a0f77b097c 100644 --- a/tests/ui/lint/runtime-symbols.stderr +++ b/tests/ui/lint/runtime-symbols.stderr @@ -36,11 +36,21 @@ LL | pub static strlen: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: expected `unsafe extern "C" fn(*const U8) -> usize` - found `static strlen: ()` + found `()` + = help: either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = "strlen")]` + +error: invalid definition of the runtime `strlen` symbol used by the standard library + --> $DIR/runtime-symbols.rs:30:9 + | +LL | static strlen2: Option; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(*const U8) -> usize` + found `unsafe extern "C" fn(*const U8)` = help: either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = "strlen")]` error: invalid definition of the runtime `memcpy` symbol used by the standard library - --> $DIR/runtime-symbols.rs:30:5 + --> $DIR/runtime-symbols.rs:36:5 | LL | pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +60,7 @@ LL | pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcpy")]`, or `#[link_name = "memcpy"]` error: invalid definition of the runtime `bcmp` symbol used by the standard library - --> $DIR/runtime-symbols.rs:37:5 + --> $DIR/runtime-symbols.rs:43:5 | LL | pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: usize, _: ...) -> c_int { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +70,7 @@ LL | pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "bcmp")]`, or `#[link_name = "bcmp"]` error: invalid definition of the runtime `bcmp` symbol used by the standard library - --> $DIR/runtime-symbols.rs:44:5 + --> $DIR/runtime-symbols.rs:50:5 | LL | pub extern "C" fn bcmp_(s1: *const c_void, s2: *const c_void, n: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +80,7 @@ LL | pub extern "C" fn bcmp_(s1: *const c_void, s2: *const c_void, n: usize) = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "bcmp")]`, or `#[link_name = "bcmp"]` warning: suspicious definition of the runtime `memcpy` symbol used by the standard library - --> $DIR/runtime-symbols.rs:50:5 + --> $DIR/runtime-symbols.rs:56:5 | LL | pub extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +92,7 @@ LL | pub extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: i64) = note: `#[warn(suspicious_runtime_symbol_definitions)]` on by default warning: suspicious definition of the runtime `memmove` symbol used by the standard library - --> $DIR/runtime-symbols.rs:56:5 + --> $DIR/runtime-symbols.rs:62:5 | LL | pub extern "C" fn memmove(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +103,7 @@ LL | pub extern "C" fn memmove(dest: *mut c_void, src: *const c_void, n: i64 = help: allow this lint if the signature is compatible warning: suspicious definition of the runtime `memset` symbol used by the standard library - --> $DIR/runtime-symbols.rs:62:9 + --> $DIR/runtime-symbols.rs:68:9 | LL | fn memset(s: *mut c_void, c: c_int, n: usize) -> f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +114,7 @@ LL | fn memset(s: *mut c_void, c: c_int, n: usize) -> f64; = help: allow this lint if the signature is compatible warning: suspicious definition of the runtime `bcmp` symbol used by the standard library - --> $DIR/runtime-symbols.rs:67:5 + --> $DIR/runtime-symbols.rs:73:5 | LL | pub extern "C" fn bcmp_(s1: *const U8, s2: *const U8, n: usize) -> c_int { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -115,7 +125,7 @@ LL | pub extern "C" fn bcmp_(s1: *const U8, s2: *const U8, n: usize) -> c_in = help: allow this lint if the signature is compatible warning: suspicious definition of the runtime `strlen` symbol used by the standard library - --> $DIR/runtime-symbols.rs:73:5 + --> $DIR/runtime-symbols.rs:79:5 | LL | pub extern "C" fn strlen(s: *const u64) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -125,5 +135,5 @@ LL | pub extern "C" fn strlen(s: *const u64) -> usize { = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]` = help: allow this lint if the signature is compatible -error: aborting due to 7 previous errors; 5 warnings emitted +error: aborting due to 8 previous errors; 5 warnings emitted From 7c5c34fafb19bc799f5c954bcf2d92f291b5a74c Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 18 Jul 2026 17:18:30 +0200 Subject: [PATCH 21/31] Remove the `static` items specific diagnostic for runtime symbols lints --- compiler/rustc_lint/src/lints.rs | 15 ++------------- compiler/rustc_lint/src/runtime_symbols.rs | 12 ++++++------ tests/ui/lint/runtime-symbols-unix.stderr | 2 +- tests/ui/lint/runtime-symbols.stderr | 4 ++-- 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 290f82808b4ca..b084b412417c5 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -846,7 +846,7 @@ pub(crate) enum RedefiningRuntimeSymbolsDiag<'tcx> { #[help( "either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = \"{$symbol_name}\")]`, or `#[link_name = \"{$symbol_name}\"]`" )] - FnDefInvalid { symbol_name: String, expected_fn_sig: Ty<'tcx>, found_fn_sig: Ty<'tcx> }, + Invalid { symbol_name: String, expected_fn_sig: Ty<'tcx>, found_fn_sig: Ty<'tcx> }, #[diag( "suspicious definition of the runtime `{$symbol_name}` symbol used by the standard library" )] @@ -858,18 +858,7 @@ pub(crate) enum RedefiningRuntimeSymbolsDiag<'tcx> { "either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = \"{$symbol_name}\")]`, or `#[link_name = \"{$symbol_name}\"]`" )] #[help("allow this lint if the signature is compatible")] - FnDefSuspicious { symbol_name: String, expected_fn_sig: Ty<'tcx>, found_fn_sig: Ty<'tcx> }, - #[diag( - "invalid definition of the runtime `{$symbol_name}` symbol used by the standard library" - )] - #[note( - "expected `{$expected_fn_sig}` - found `{$static_ty}`" - )] - #[help( - "either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = \"{$symbol_name}\")]`" - )] - Static { symbol_name: String, static_ty: Ty<'tcx>, expected_fn_sig: Ty<'tcx> }, + Suspicious { symbol_name: String, expected_fn_sig: Ty<'tcx>, found_fn_sig: Ty<'tcx> }, } // drop_forget_useless.rs diff --git a/compiler/rustc_lint/src/runtime_symbols.rs b/compiler/rustc_lint/src/runtime_symbols.rs index 7657d55ac8489..44ddc81f275bf 100644 --- a/compiler/rustc_lint/src/runtime_symbols.rs +++ b/compiler/rustc_lint/src/runtime_symbols.rs @@ -174,7 +174,7 @@ fn check_fn(cx: &LateContext<'_>, symbol_name: &str, sig: FnSig<'_>, did: LocalD cx.emit_span_lint( INVALID_RUNTIME_SYMBOL_DEFINITIONS, sig.span, - RedefiningRuntimeSymbolsDiag::FnDefInvalid { + RedefiningRuntimeSymbolsDiag::Invalid { symbol_name: symbol_name.to_string(), found_fn_sig: actual, expected_fn_sig: expected, @@ -184,7 +184,7 @@ fn check_fn(cx: &LateContext<'_>, symbol_name: &str, sig: FnSig<'_>, did: LocalD cx.emit_span_lint( SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, sig.span, - RedefiningRuntimeSymbolsDiag::FnDefSuspicious { + RedefiningRuntimeSymbolsDiag::Suspicious { symbol_name: symbol_name.to_string(), found_fn_sig: actual, expected_fn_sig: expected, @@ -229,9 +229,9 @@ fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId cx.emit_span_lint( INVALID_RUNTIME_SYMBOL_DEFINITIONS, sp, - RedefiningRuntimeSymbolsDiag::Static { - static_ty: user_sig, + RedefiningRuntimeSymbolsDiag::Invalid { symbol_name: symbol_name.to_string(), + found_fn_sig: user_sig, expected_fn_sig: lang_sig, }, ); @@ -251,9 +251,9 @@ fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId cx.emit_span_lint( INVALID_RUNTIME_SYMBOL_DEFINITIONS, sp, - RedefiningRuntimeSymbolsDiag::Static { - static_ty: user_sig, + RedefiningRuntimeSymbolsDiag::Invalid { symbol_name: symbol_name.to_string(), + found_fn_sig: user_sig, expected_fn_sig: lang_sig, }, ); diff --git a/tests/ui/lint/runtime-symbols-unix.stderr b/tests/ui/lint/runtime-symbols-unix.stderr index acc29779f2074..22995d9febd70 100644 --- a/tests/ui/lint/runtime-symbols-unix.stderr +++ b/tests/ui/lint/runtime-symbols-unix.stderr @@ -37,7 +37,7 @@ LL | pub static close: () = (); | = note: expected `unsafe extern "C" fn(i32) -> i32` found `()` - = help: either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = "close")]` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "close")]`, or `#[link_name = "close"]` error: invalid definition of the runtime `malloc` symbol used by the standard library --> $DIR/runtime-symbols-unix.rs:30:9 diff --git a/tests/ui/lint/runtime-symbols.stderr b/tests/ui/lint/runtime-symbols.stderr index 099a0f77b097c..2e4709f36e38a 100644 --- a/tests/ui/lint/runtime-symbols.stderr +++ b/tests/ui/lint/runtime-symbols.stderr @@ -37,7 +37,7 @@ LL | pub static strlen: () = (); | = note: expected `unsafe extern "C" fn(*const U8) -> usize` found `()` - = help: either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = "strlen")]` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]` error: invalid definition of the runtime `strlen` symbol used by the standard library --> $DIR/runtime-symbols.rs:30:9 @@ -47,7 +47,7 @@ LL | static strlen2: Option; | = note: expected `unsafe extern "C" fn(*const U8) -> usize` found `unsafe extern "C" fn(*const U8)` - = help: either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = "strlen")]` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]` error: invalid definition of the runtime `memcpy` symbol used by the standard library --> $DIR/runtime-symbols.rs:36:5 From f50b20da76382340340083e75842c2e7f6d93b3a Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 18 Jul 2026 17:34:38 +0200 Subject: [PATCH 22/31] Merge checking for static and foreign functions --- compiler/rustc_lint/src/runtime_symbols.rs | 95 ++++++++++------------ tests/ui/lint/runtime-symbols-unix.rs | 8 ++ tests/ui/lint/runtime-symbols-unix.stderr | 24 +++++- 3 files changed, 75 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_lint/src/runtime_symbols.rs b/compiler/rustc_lint/src/runtime_symbols.rs index 44ddc81f275bf..6efe30a696a70 100644 --- a/compiler/rustc_lint/src/runtime_symbols.rs +++ b/compiler/rustc_lint/src/runtime_symbols.rs @@ -1,7 +1,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, CanonicalSymbol, FnSig, ForeignItemKind}; use rustc_infer::infer::DefineOpaqueTypes; -use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::ty::{self, Instance, PolyFnSig, Ty}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{Span, Symbol}; use rustc_trait_selection::infer::TyCtxtInferExt; @@ -154,44 +154,7 @@ fn check_fn(cx: &LateContext<'_>, symbol_name: &str, sig: FnSig<'_>, did: LocalD .tcx .normalize_erasing_regions(cx.typing_env(), cx.tcx.fn_sig(did).instantiate_identity()); - // Compare the two signatures with an inference context - let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); - let cause = rustc_middle::traits::ObligationCause::misc(sig.span, did); - let result = infcx.at(&cause, cx.param_env).eq(DefineOpaqueTypes::No, lang_sig, user_sig); - - // If they don't match, emit our own mismatch signatures - if let Err(_terr) = result { - // Create fn pointers for diagnostics purpose - let expected = Ty::new_fn_ptr(cx.tcx, lang_sig); - let actual = Ty::new_fn_ptr(cx.tcx, user_sig); - - if lang_sig.abi() != user_sig.abi() - || lang_sig.c_variadic() != user_sig.c_variadic() - || lang_sig.inputs().skip_binder().len() != user_sig.inputs().skip_binder().len() - || (!lang_sig.output().skip_binder().is_unit() - && user_sig.output().skip_binder().is_unit()) - { - cx.emit_span_lint( - INVALID_RUNTIME_SYMBOL_DEFINITIONS, - sig.span, - RedefiningRuntimeSymbolsDiag::Invalid { - symbol_name: symbol_name.to_string(), - found_fn_sig: actual, - expected_fn_sig: expected, - }, - ); - } else { - cx.emit_span_lint( - SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, - sig.span, - RedefiningRuntimeSymbolsDiag::Suspicious { - symbol_name: symbol_name.to_string(), - found_fn_sig: actual, - expected_fn_sig: expected, - }, - ); - }; - } + check(cx, symbol_name, did, sig.span, lang_sig, user_sig); } fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId, sp: Span) { @@ -238,24 +201,54 @@ fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId return; }; + // Compare the signatures and report a warning/error depending on the mismatch + check(cx, symbol_name, did, sp, lang_sig, user_sig); +} + +fn check<'tcx>( + cx: &LateContext<'tcx>, + symbol_name: &str, + did: LocalDefId, + sp: Span, + lang_sig: PolyFnSig<'tcx>, + user_sig: PolyFnSig<'tcx>, +) { // Compare the two signatures with an inference context let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let cause = rustc_middle::traits::ObligationCause::misc(sp, did); let result = infcx.at(&cause, cx.param_env).eq(DefineOpaqueTypes::No, lang_sig, user_sig); - // Compare the expected function signature with the static type, report an error if they don't match + // If they don't match, emit our own mismatch signatures if result.is_err() { - let user_sig = Ty::new_fn_ptr(cx.tcx, user_sig); - let lang_sig = Ty::new_fn_ptr(cx.tcx, lang_sig); + // Create fn pointers for diagnostics purpose + let expected = Ty::new_fn_ptr(cx.tcx, lang_sig); + let actual = Ty::new_fn_ptr(cx.tcx, user_sig); - cx.emit_span_lint( - INVALID_RUNTIME_SYMBOL_DEFINITIONS, - sp, - RedefiningRuntimeSymbolsDiag::Invalid { - symbol_name: symbol_name.to_string(), - found_fn_sig: user_sig, - expected_fn_sig: lang_sig, - }, - ); + if lang_sig.abi() != user_sig.abi() + || lang_sig.c_variadic() != user_sig.c_variadic() + || lang_sig.inputs().skip_binder().len() != user_sig.inputs().skip_binder().len() + || (!lang_sig.output().skip_binder().is_unit() + && user_sig.output().skip_binder().is_unit()) + { + cx.emit_span_lint( + INVALID_RUNTIME_SYMBOL_DEFINITIONS, + sp, + RedefiningRuntimeSymbolsDiag::Invalid { + symbol_name: symbol_name.to_string(), + found_fn_sig: actual, + expected_fn_sig: expected, + }, + ); + } else { + cx.emit_span_lint( + SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, + sp, + RedefiningRuntimeSymbolsDiag::Suspicious { + symbol_name: symbol_name.to_string(), + found_fn_sig: actual, + expected_fn_sig: expected, + }, + ); + }; } } diff --git a/tests/ui/lint/runtime-symbols-unix.rs b/tests/ui/lint/runtime-symbols-unix.rs index 517cf765195f3..bbf57f5582ff3 100644 --- a/tests/ui/lint/runtime-symbols-unix.rs +++ b/tests/ui/lint/runtime-symbols-unix.rs @@ -51,6 +51,14 @@ fn suspicious() { pub fn exit(code: f32) -> !; //~^ WARN suspicious definition of the runtime `exit` symbol + + #[link_name = "exit"] + pub static exit2: Option !>; + //~^ WARN suspicious definition of the runtime `exit` symbol + + #[link_name = "exit"] + pub static exit3: unsafe extern "C" fn(f32) -> !; + //~^ WARN suspicious definition of the runtime `exit` symbol } } diff --git a/tests/ui/lint/runtime-symbols-unix.stderr b/tests/ui/lint/runtime-symbols-unix.stderr index 22995d9febd70..a806fb3f02b50 100644 --- a/tests/ui/lint/runtime-symbols-unix.stderr +++ b/tests/ui/lint/runtime-symbols-unix.stderr @@ -113,5 +113,27 @@ LL | pub fn exit(code: f32) -> !; = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "exit")]`, or `#[link_name = "exit"]` = help: allow this lint if the signature is compatible -error: aborting due to 8 previous errors; 3 warnings emitted +warning: suspicious definition of the runtime `exit` symbol used by the standard library + --> $DIR/runtime-symbols-unix.rs:56:9 + | +LL | pub static exit2: Option !>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(i32) -> !` + found `unsafe extern "C" fn(f32) -> !` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "exit")]`, or `#[link_name = "exit"]` + = help: allow this lint if the signature is compatible + +warning: suspicious definition of the runtime `exit` symbol used by the standard library + --> $DIR/runtime-symbols-unix.rs:60:9 + | +LL | pub static exit3: unsafe extern "C" fn(f32) -> !; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(i32) -> !` + found `unsafe extern "C" fn(f32) -> !` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "exit")]`, or `#[link_name = "exit"]` + = help: allow this lint if the signature is compatible + +error: aborting due to 8 previous errors; 5 warnings emitted From 778a9dfcc900f5e7a2ff911e4aeabb98ed89bcef Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 18 Jul 2026 23:46:59 +0200 Subject: [PATCH 23/31] Check only foreign statics with `#[linkage = "..."]` --- compiler/rustc_lint/src/runtime_symbols.rs | 5 ++- tests/ui/lint/runtime-symbols-unix.rs | 6 ++-- tests/ui/lint/runtime-symbols-unix.stderr | 37 ++++++++-------------- tests/ui/lint/runtime-symbols.rs | 3 ++ tests/ui/lint/runtime-symbols.stderr | 26 +++++++-------- 5 files changed, 35 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_lint/src/runtime_symbols.rs b/compiler/rustc_lint/src/runtime_symbols.rs index 6efe30a696a70..913a22b58edfe 100644 --- a/compiler/rustc_lint/src/runtime_symbols.rs +++ b/compiler/rustc_lint/src/runtime_symbols.rs @@ -125,7 +125,10 @@ impl<'tcx> LateLintPass<'tcx> for RuntimeSymbols { check_fn(cx, &symbol_name.name, fn_sig, did); } ForeignItemKind::Static(..) => { - check_static(cx, &symbol_name.name, did, item.span); + // We only check static with #[linkage = "..."] attribute (see std weak! macro) + if cx.tcx.codegen_fn_attrs(did).import_linkage.is_some() { + check_static(cx, &symbol_name.name, did, item.span); + } } ForeignItemKind::Type => return, } diff --git a/tests/ui/lint/runtime-symbols-unix.rs b/tests/ui/lint/runtime-symbols-unix.rs index bbf57f5582ff3..fcb7540be6a3b 100644 --- a/tests/ui/lint/runtime-symbols-unix.rs +++ b/tests/ui/lint/runtime-symbols-unix.rs @@ -4,6 +4,7 @@ //@ edition: 2021 //@ normalize-stderr: "\*const [iu]8" -> "*const U8" +#![feature(linkage)] #![feature(c_variadic)] #![allow(clashing_extern_declarations)] // we are voluntarily testing different definitions @@ -53,12 +54,9 @@ fn suspicious() { //~^ WARN suspicious definition of the runtime `exit` symbol #[link_name = "exit"] + #[linkage = "weak"] pub static exit2: Option !>; //~^ WARN suspicious definition of the runtime `exit` symbol - - #[link_name = "exit"] - pub static exit3: unsafe extern "C" fn(f32) -> !; - //~^ WARN suspicious definition of the runtime `exit` symbol } } diff --git a/tests/ui/lint/runtime-symbols-unix.stderr b/tests/ui/lint/runtime-symbols-unix.stderr index a806fb3f02b50..11fed56a7e785 100644 --- a/tests/ui/lint/runtime-symbols-unix.stderr +++ b/tests/ui/lint/runtime-symbols-unix.stderr @@ -1,5 +1,5 @@ error: invalid definition of the runtime `open` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:14:5 + --> $DIR/runtime-symbols-unix.rs:15:5 | LL | pub fn open() {} | ^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | pub fn open() {} = note: `#[deny(invalid_runtime_symbol_definitions)]` on by default error: invalid definition of the runtime `read` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:18:9 + --> $DIR/runtime-symbols-unix.rs:19:9 | LL | pub fn read(); | ^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | pub fn read(); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "read")]`, or `#[link_name = "read"]` error: invalid definition of the runtime `write` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:21:9 + --> $DIR/runtime-symbols-unix.rs:22:9 | LL | pub fn write(); | ^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | pub fn write(); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "write")]`, or `#[link_name = "write"]` error: invalid definition of the runtime `close` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:26:5 + --> $DIR/runtime-symbols-unix.rs:27:5 | LL | pub static close: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | pub static close: () = (); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "close")]`, or `#[link_name = "close"]` error: invalid definition of the runtime `malloc` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:30:9 + --> $DIR/runtime-symbols-unix.rs:31:9 | LL | pub fn malloc(); | ^^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | pub fn malloc(); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "malloc")]`, or `#[link_name = "malloc"]` error: invalid definition of the runtime `realloc` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:33:9 + --> $DIR/runtime-symbols-unix.rs:34:9 | LL | pub fn realloc(); | ^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | pub fn realloc(); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "realloc")]`, or `#[link_name = "realloc"]` error: invalid definition of the runtime `free` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:36:9 + --> $DIR/runtime-symbols-unix.rs:37:9 | LL | pub fn free(); | ^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | pub fn free(); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "free")]`, or `#[link_name = "free"]` error: invalid definition of the runtime `exit` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:39:9 + --> $DIR/runtime-symbols-unix.rs:40:9 | LL | pub fn exit(); | ^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | pub fn exit(); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "exit")]`, or `#[link_name = "exit"]` warning: suspicious definition of the runtime `open` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:46:9 + --> $DIR/runtime-symbols-unix.rs:47:9 | LL | pub fn open(path: *const U8, oflag: usize, ...) -> c_int; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | pub fn open(path: *const U8, oflag: usize, ...) -> c_int; = note: `#[warn(suspicious_runtime_symbol_definitions)]` on by default warning: suspicious definition of the runtime `free` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:49:9 + --> $DIR/runtime-symbols-unix.rs:50:9 | LL | pub fn free(ptr: *const U8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | pub fn free(ptr: *const U8); = help: allow this lint if the signature is compatible warning: suspicious definition of the runtime `exit` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:52:9 + --> $DIR/runtime-symbols-unix.rs:53:9 | LL | pub fn exit(code: f32) -> !; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +114,7 @@ LL | pub fn exit(code: f32) -> !; = help: allow this lint if the signature is compatible warning: suspicious definition of the runtime `exit` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:56:9 + --> $DIR/runtime-symbols-unix.rs:58:9 | LL | pub static exit2: Option !>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,16 +124,5 @@ LL | pub static exit2: Option !>; = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "exit")]`, or `#[link_name = "exit"]` = help: allow this lint if the signature is compatible -warning: suspicious definition of the runtime `exit` symbol used by the standard library - --> $DIR/runtime-symbols-unix.rs:60:9 - | -LL | pub static exit3: unsafe extern "C" fn(f32) -> !; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: expected `unsafe extern "C" fn(i32) -> !` - found `unsafe extern "C" fn(f32) -> !` - = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "exit")]`, or `#[link_name = "exit"]` - = help: allow this lint if the signature is compatible - -error: aborting due to 8 previous errors; 5 warnings emitted +error: aborting due to 8 previous errors; 4 warnings emitted diff --git a/tests/ui/lint/runtime-symbols.rs b/tests/ui/lint/runtime-symbols.rs index ddcae715af3af..9f7ff98e73b03 100644 --- a/tests/ui/lint/runtime-symbols.rs +++ b/tests/ui/lint/runtime-symbols.rs @@ -3,6 +3,7 @@ //@ edition: 2021 //@ normalize-stderr: "\*const [iu]8" -> "*const U8" +#![feature(linkage)] #![feature(c_variadic)] #![allow(clashing_extern_declarations)] // we are voluntarily testing different definitions @@ -27,6 +28,7 @@ fn invalid() { extern "C" { #[link_name = "strlen"] + #[linkage = "weak"] static strlen2: Option; //~^ ERROR invalid definition of the runtime `strlen` symbol } @@ -94,6 +96,7 @@ fn valid() { fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; + #[linkage = "linkonce"] static strlen: Option usize>; } } diff --git a/tests/ui/lint/runtime-symbols.stderr b/tests/ui/lint/runtime-symbols.stderr index 2e4709f36e38a..6adc96460c42e 100644 --- a/tests/ui/lint/runtime-symbols.stderr +++ b/tests/ui/lint/runtime-symbols.stderr @@ -1,5 +1,5 @@ error: invalid definition of the runtime `memmove` symbol used by the standard library - --> $DIR/runtime-symbols.rs:13:5 + --> $DIR/runtime-symbols.rs:14:5 | LL | pub fn memmove() {} | ^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | pub fn memmove() {} = note: `#[deny(invalid_runtime_symbol_definitions)]` on by default error: invalid definition of the runtime `memset` symbol used by the standard library - --> $DIR/runtime-symbols.rs:17:9 + --> $DIR/runtime-symbols.rs:18:9 | LL | pub fn memset(); | ^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | pub fn memset(); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memset")]`, or `#[link_name = "memset"]` error: invalid definition of the runtime `memcmp` symbol used by the standard library - --> $DIR/runtime-symbols.rs:20:9 + --> $DIR/runtime-symbols.rs:21:9 | LL | pub fn memcmp(); | ^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | pub fn memcmp(); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcmp")]`, or `#[link_name = "memcmp"]` error: invalid definition of the runtime `strlen` symbol used by the standard library - --> $DIR/runtime-symbols.rs:25:5 + --> $DIR/runtime-symbols.rs:26:5 | LL | pub static strlen: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | pub static strlen: () = (); = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]` error: invalid definition of the runtime `strlen` symbol used by the standard library - --> $DIR/runtime-symbols.rs:30:9 + --> $DIR/runtime-symbols.rs:32:9 | LL | static strlen2: Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | static strlen2: Option; = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]` error: invalid definition of the runtime `memcpy` symbol used by the standard library - --> $DIR/runtime-symbols.rs:36:5 + --> $DIR/runtime-symbols.rs:38:5 | LL | pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcpy")]`, or `#[link_name = "memcpy"]` error: invalid definition of the runtime `bcmp` symbol used by the standard library - --> $DIR/runtime-symbols.rs:43:5 + --> $DIR/runtime-symbols.rs:45:5 | LL | pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: usize, _: ...) -> c_int { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "bcmp")]`, or `#[link_name = "bcmp"]` error: invalid definition of the runtime `bcmp` symbol used by the standard library - --> $DIR/runtime-symbols.rs:50:5 + --> $DIR/runtime-symbols.rs:52:5 | LL | pub extern "C" fn bcmp_(s1: *const c_void, s2: *const c_void, n: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | pub extern "C" fn bcmp_(s1: *const c_void, s2: *const c_void, n: usize) = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "bcmp")]`, or `#[link_name = "bcmp"]` warning: suspicious definition of the runtime `memcpy` symbol used by the standard library - --> $DIR/runtime-symbols.rs:56:5 + --> $DIR/runtime-symbols.rs:58:5 | LL | pub extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | pub extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: i64) = note: `#[warn(suspicious_runtime_symbol_definitions)]` on by default warning: suspicious definition of the runtime `memmove` symbol used by the standard library - --> $DIR/runtime-symbols.rs:62:5 + --> $DIR/runtime-symbols.rs:64:5 | LL | pub extern "C" fn memmove(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | pub extern "C" fn memmove(dest: *mut c_void, src: *const c_void, n: i64 = help: allow this lint if the signature is compatible warning: suspicious definition of the runtime `memset` symbol used by the standard library - --> $DIR/runtime-symbols.rs:68:9 + --> $DIR/runtime-symbols.rs:70:9 | LL | fn memset(s: *mut c_void, c: c_int, n: usize) -> f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +114,7 @@ LL | fn memset(s: *mut c_void, c: c_int, n: usize) -> f64; = help: allow this lint if the signature is compatible warning: suspicious definition of the runtime `bcmp` symbol used by the standard library - --> $DIR/runtime-symbols.rs:73:5 + --> $DIR/runtime-symbols.rs:75:5 | LL | pub extern "C" fn bcmp_(s1: *const U8, s2: *const U8, n: usize) -> c_int { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL | pub extern "C" fn bcmp_(s1: *const U8, s2: *const U8, n: usize) -> c_in = help: allow this lint if the signature is compatible warning: suspicious definition of the runtime `strlen` symbol used by the standard library - --> $DIR/runtime-symbols.rs:79:5 + --> $DIR/runtime-symbols.rs:81:5 | LL | pub extern "C" fn strlen(s: *const u64) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From b663a947c706f5116bbecfb6650e398d41081eb6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 21 Jul 2026 16:29:39 +1000 Subject: [PATCH 24/31] Remove `early_exit` closures There are two `early_exit` closures in `run_compiler` that ensure `abort_if_errors` is called on all the early exit paths. However, these early exit paths all occur in the closure passed to `interface::run_compiler`. And what does `interface::run_compiler` do after calling the passed-in closure? It calls `finish_diagnostic` (always) and then `abort_if_errors` (if the closure didn't panic). So we can drop the `early_exit` calls and get the same behaviour. --- compiler/rustc_driver_impl/src/lib.rs | 36 +++++++++------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index a3cb2fa80f63b..027cad0d8cc51 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -231,28 +231,21 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) let sess = &compiler.sess; let codegen_backend = &*compiler.codegen_backend; - // This is used for early exits unrelated to errors. E.g. when just - // printing some information without compiling, or exiting immediately - // after parsing, etc. - let early_exit = || { - sess.dcx().abort_if_errors(); - }; - // This implements `-Whelp`. It should be handled very early, like // `--help`/`-Zhelp`/`-Chelp`. This is the earliest it can run, because // it must happen after lints are registered, during session creation. if sess.opts.describe_lints { describe_lints(sess, registered_lints); - return early_exit(); + return; } // We have now handled all help options, exit if help_only { - return early_exit(); + return; } if print_crate_info(codegen_backend, sess, has_input) == Compilation::Stop { - return early_exit(); + return; } if !has_input { @@ -261,12 +254,12 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) if !sess.opts.unstable_opts.ls.is_empty() { list_metadata(sess, &*codegen_backend.metadata_loader()); - return early_exit(); + return; } if sess.opts.unstable_opts.link_only { process_rlink(sess, compiler); - return early_exit(); + return; } // Parse the crate root source code (doesn't parse submodules yet) @@ -285,28 +278,23 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) pretty::print(sess, pp_mode, pretty::PrintExtra::AfterParsing { krate: &krate }); } trace!("finished pretty-printing"); - return early_exit(); + return; } if callbacks.after_crate_root_parsing(compiler, &mut krate) == Compilation::Stop { - return early_exit(); + return; } if sess.opts.unstable_opts.parse_crate_root_only { - return early_exit(); + return; } let linker = create_and_enter_global_ctxt(compiler, krate, |tcx| { - let early_exit = || { - sess.dcx().abort_if_errors(); - None - }; - // Make sure name resolution and macro expansion is run. let _ = tcx.resolver_for_lowering(); if callbacks.after_expansion(compiler, tcx) == Compilation::Stop { - return early_exit(); + return None; } passes::write_dep_info(tcx); @@ -316,11 +304,11 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) if sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1 { - return early_exit(); + return None; } if sess.opts.unstable_opts.no_analysis { - return early_exit(); + return None; } tcx.ensure_ok().analysis(()); @@ -330,7 +318,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) } if callbacks.after_analysis(compiler, tcx) == Compilation::Stop { - return early_exit(); + return None; } if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { From a235d0d0d019d33c029dbaad92c7ad13911f9292 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 21 Jul 2026 18:05:48 +1000 Subject: [PATCH 25/31] Use two local variables --- compiler/rustc_driver_impl/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 027cad0d8cc51..4411ecb4f128b 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -321,13 +321,13 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) return None; } - if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { + if sess.opts.output_types.contains_key(&OutputType::Mir) { if let Err(error) = pretty::emit_mir(tcx) { tcx.dcx().emit_fatal(CantEmitMIR { error }); } } - let linker = Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend); + let linker = Linker::codegen_and_build_linker(tcx, codegen_backend); tcx.report_unused_features(); From 8ae35e20e8bce2c4af0449ac86e35fae353082d1 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Tue, 21 Jul 2026 12:42:50 +0200 Subject: [PATCH 26/31] Remove the `cfg(not(no_global_oom_handling))` from `Drop` impl --- library/alloc/src/sync.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index bb46f14fb9a36..9c6b43ba6c8ee 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4327,7 +4327,6 @@ impl UniqueArcUninit { } } -#[cfg(not(no_global_oom_handling))] impl Drop for UniqueArcUninit { fn drop(&mut self) { // SAFETY: From e547ba4ed76a469ff53481e0446fbf0fb35f70cf Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 21 Jul 2026 12:58:28 +0200 Subject: [PATCH 27/31] relax `f16` `LOG_APPROX` when running tests under Miri --- library/coretests/tests/num/floats.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/coretests/tests/num/floats.rs b/library/coretests/tests/num/floats.rs index 1d7956b41c9d1..cc1d1a0b673dc 100644 --- a/library/coretests/tests/num/floats.rs +++ b/library/coretests/tests/num/floats.rs @@ -79,7 +79,7 @@ impl TestableFloat for f16 { const EXP_APPROX: Self = if cfg!(miri) { 5e-1 } else { 1e-2 }; // for values on the order of 150, 4 ULP are more than 0.1... const POWI_APPROX: Self = if cfg!(miri) { 1e-1 } else { Self::APPROX }; const LN_APPROX: Self = 1e-2; - const LOG_APPROX: Self = 1e-2; + const LOG_APPROX: Self = if cfg!(miri) { 1e-1 } else { 1e-2 }; const LOG2_APPROX: Self = 1e-2; const LOG10_APPROX: Self = 1e-2; const ASINH_APPROX: Self = 1e-2; From 3feb78f7ba67790f70ddbadd3d59f54207a737fa Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 21 Jul 2026 13:54:12 +0200 Subject: [PATCH 28/31] define a `Simd` type in `minicore` --- tests/assembly-llvm/asm/aarch64-types.rs | 47 +--------- tests/assembly-llvm/asm/amdgpu-vec-types.rs | 94 +++---------------- tests/assembly-llvm/asm/amdgpu-vec-types2.rs | 51 ++-------- tests/assembly-llvm/asm/arm-modifiers.rs | 8 +- tests/assembly-llvm/asm/arm-types.rs | 41 +------- tests/assembly-llvm/asm/hexagon-types.rs | 12 +-- .../assembly-llvm/asm/loongarch-modifiers.rs | 41 +------- tests/assembly-llvm/asm/powerpc-types.rs | 23 +---- tests/assembly-llvm/asm/s390x-types.rs | 16 +--- tests/assembly-llvm/asm/x86-types.rs | 62 +----------- tests/assembly-llvm/asm/xtensa-types.rs | 3 +- tests/assembly-llvm/s390x-vector-abi.rs | 12 +-- tests/assembly-llvm/simd-bitmask.rs | 22 ++--- tests/assembly-llvm/simd-intrinsic-gather.rs | 18 ++-- .../assembly-llvm/simd-intrinsic-mask-load.rs | 31 ++---- .../simd-intrinsic-mask-reduce.rs | 5 +- .../simd-intrinsic-mask-store.rs | 23 +---- tests/assembly-llvm/simd-intrinsic-scatter.rs | 14 +-- tests/assembly-llvm/simd-intrinsic-select.rs | 41 ++------ tests/auxiliary/minicore.rs | 56 +++++++++++ tests/codegen-llvm/align-byval-vector.rs | 12 +-- tests/codegen-llvm/simd/array-repeat.rs | 7 +- tests/codegen-llvm/transmute-scalar.rs | 7 +- 23 files changed, 153 insertions(+), 493 deletions(-) diff --git a/tests/assembly-llvm/asm/aarch64-types.rs b/tests/assembly-llvm/asm/aarch64-types.rs index fde0aad946951..21f9294dc647b 100644 --- a/tests/assembly-llvm/asm/aarch64-types.rs +++ b/tests/assembly-llvm/asm/aarch64-types.rs @@ -7,60 +7,17 @@ //@ [arm64ec] needs-llvm-components: aarch64 //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, repr_simd, f16, f128)] +#![feature(no_core, f16, f128)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; type ptr = *mut u8; -#[repr(simd)] -pub struct i8x8([i8; 8]); -#[repr(simd)] -pub struct i16x4([i16; 4]); -#[repr(simd)] -pub struct i32x2([i32; 2]); -#[repr(simd)] -pub struct i64x1([i64; 1]); -#[repr(simd)] -pub struct f16x4([f16; 4]); -#[repr(simd)] -pub struct f32x2([f32; 2]); -#[repr(simd)] -pub struct f64x1([f64; 1]); -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f16x8([f16; 8]); -#[repr(simd)] -pub struct f32x4([f32; 4]); -#[repr(simd)] -pub struct f64x2([f64; 2]); - -impl Copy for i8x8 {} -impl Copy for i16x4 {} -impl Copy for i32x2 {} -impl Copy for i64x1 {} -impl Copy for f16x4 {} -impl Copy for f32x2 {} -impl Copy for f64x1 {} -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f16x8 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} - extern "C" { fn extern_func(); static extern_static: u8; diff --git a/tests/assembly-llvm/asm/amdgpu-vec-types.rs b/tests/assembly-llvm/asm/amdgpu-vec-types.rs index 64d643d91530e..1613e603fca49 100644 --- a/tests/assembly-llvm/asm/amdgpu-vec-types.rs +++ b/tests/assembly-llvm/asm/amdgpu-vec-types.rs @@ -8,7 +8,7 @@ //@ needs-rust-lld // ignore-tidy-linelength -#![feature(abi_gpu_kernel, no_core, asm_experimental_arch, repr_simd, f16)] +#![feature(abi_gpu_kernel, no_core, asm_experimental_arch, f16)] #![crate_type = "rlib"] #![no_core] #![allow( @@ -21,89 +21,25 @@ )] extern crate minicore; +use minicore::simd::*; use minicore::*; type ptr = *mut u8; -#[repr(simd)] -pub struct i16x2([i16; 2]); -#[repr(simd)] -pub struct f16x2([f16; 2]); - -#[repr(simd)] -pub struct i16x4([i16; 4]); -#[repr(simd)] -pub struct f16x4([f16; 4]); -#[repr(simd)] -pub struct i32x2([i32; 2]); -#[repr(simd)] -pub struct f32x2([f32; 2]); - -#[repr(simd)] -pub struct i32x3([i32; 3]); -#[repr(simd)] -pub struct f32x3([f32; 3]); - -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct f16x8([f16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct f32x4([f32; 4]); - -#[repr(simd)] -pub struct i32x5([i32; 5]); -#[repr(simd)] -pub struct f32x5([f32; 5]); - -#[repr(simd)] -pub struct i32x6([i32; 6]); -#[repr(simd)] -pub struct f32x6([f32; 6]); - -#[repr(simd)] -pub struct i32x7([i32; 7]); -#[repr(simd)] -pub struct f32x7([f32; 7]); - -#[repr(simd)] -pub struct i16x16([i16; 16]); -#[repr(simd)] -pub struct f16x16([f16; 16]); -#[repr(simd)] -pub struct i32x8([i32; 8]); -#[repr(simd)] -pub struct f32x8([f32; 8]); - -#[repr(simd)] -pub struct i32x10([i32; 10]); -#[repr(simd)] -pub struct f32x10([f32; 10]); - -#[repr(simd)] -pub struct i16x32([i16; 32]); -#[repr(simd)] -pub struct f16x32([f16; 32]); -#[repr(simd)] -pub struct i32x16([i32; 16]); -#[repr(simd)] -pub struct f32x16([f32; 16]); - -macro_rules! impl_copy { - ($($ty:ident)*) => { - $( - impl Copy for $ty {} - )* - }; -} +type i32x3 = Simd; +type f32x3 = Simd; + +type i32x5 = Simd; +type f32x5 = Simd; + +type i32x6 = Simd; +type f32x6 = Simd; + +type i32x7 = Simd; +type f32x7 = Simd; -impl_copy!( - i16x2 f16x2 i16x4 f16x4 i32x2 f32x2 i32x3 f32x3 i16x8 f16x8 i32x4 f32x4 - i32x5 f32x5 i32x6 f32x6 i32x7 f32x7 i16x16 f16x16 i32x8 f32x8 i32x10 f32x10 - i16x32 f16x32 i32x16 f32x16 -); +type i32x10 = Simd; +type f32x10 = Simd; macro_rules! check { ($func:ident $ty:ident $class:ident $mov:literal) => { diff --git a/tests/assembly-llvm/asm/amdgpu-vec-types2.rs b/tests/assembly-llvm/asm/amdgpu-vec-types2.rs index 1257abe932b0b..de68dc84d1ffc 100644 --- a/tests/assembly-llvm/asm/amdgpu-vec-types2.rs +++ b/tests/assembly-llvm/asm/amdgpu-vec-types2.rs @@ -11,7 +11,7 @@ // Tests for different gfx versions that do not fit in gfx11 and 12 -#![feature(abi_gpu_kernel, no_core, asm_experimental_arch, repr_simd, f16)] +#![feature(abi_gpu_kernel, no_core, asm_experimental_arch, f16)] #![crate_type = "rlib"] #![no_core] #![allow( @@ -24,54 +24,19 @@ )] extern crate minicore; +use minicore::simd::*; use minicore::*; type ptr = *mut u8; -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct f32x4([f32; 4]); +type i32x9 = Simd; +type f32x9 = Simd; -#[repr(simd)] -pub struct i32x9([i32; 9]); -#[repr(simd)] -pub struct f32x9([f32; 9]); +type i32x11 = Simd; +type f32x11 = Simd; -#[repr(simd)] -pub struct i32x11([i32; 11]); -#[repr(simd)] -pub struct f32x11([f32; 11]); - -#[repr(simd)] -pub struct i32x12([i32; 12]); -#[repr(simd)] -pub struct f32x12([f32; 12]); - -#[repr(simd)] -pub struct i16x32([i16; 32]); -#[repr(simd)] -pub struct f16x32([f16; 32]); -#[repr(simd)] -pub struct i32x16([i32; 16]); -#[repr(simd)] -pub struct f32x16([f32; 16]); - -#[repr(simd)] -pub struct f32x32([f32; 32]); - -macro_rules! impl_copy { - ($($ty:ident)*) => { - $( - impl Copy for $ty {} - )* - }; -} - -impl_copy!( - i32x4 f32x4 i32x9 f32x9 i32x11 f32x11 i32x12 f32x12 i16x32 f16x32 - i32x16 f32x16 f32x32 -); +type i32x12 = Simd; +type f32x12 = Simd; macro_rules! check { ($func:ident $ty:ident $class:ident $mov:literal) => { diff --git a/tests/assembly-llvm/asm/arm-modifiers.rs b/tests/assembly-llvm/asm/arm-modifiers.rs index 2f090b706ccd7..2ba0e21c9f106 100644 --- a/tests/assembly-llvm/asm/arm-modifiers.rs +++ b/tests/assembly-llvm/asm/arm-modifiers.rs @@ -6,19 +6,15 @@ //@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: arm -#![feature(no_core, repr_simd)] +#![feature(no_core)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; -#[repr(simd)] -pub struct f32x4([f32; 4]); - -impl Copy for f32x4 {} - macro_rules! check { ($func:ident $modifier:literal $reg:ident $ty:ident $mov:literal) => { // -Copt-level=3 and extern "C" guarantee that the selected register is always r0/s0/d0/q0 diff --git a/tests/assembly-llvm/asm/arm-types.rs b/tests/assembly-llvm/asm/arm-types.rs index 2022c86ef2e04..4cf945c5959b6 100644 --- a/tests/assembly-llvm/asm/arm-types.rs +++ b/tests/assembly-llvm/asm/arm-types.rs @@ -9,54 +9,17 @@ //@[neon] filecheck-flags: --check-prefix d32 //@ needs-llvm-components: arm -#![feature(no_core, repr_simd, f16)] +#![feature(no_core, f16)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; type ptr = *mut u8; -#[repr(simd)] -pub struct i8x8([i8; 8]); -#[repr(simd)] -pub struct i16x4([i16; 4]); -#[repr(simd)] -pub struct i32x2([i32; 2]); -#[repr(simd)] -pub struct i64x1([i64; 1]); -#[repr(simd)] -pub struct f16x4([f16; 4]); -#[repr(simd)] -pub struct f32x2([f32; 2]); -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f16x8([f16; 8]); -#[repr(simd)] -pub struct f32x4([f32; 4]); - -impl Copy for i8x8 {} -impl Copy for i16x4 {} -impl Copy for i32x2 {} -impl Copy for i64x1 {} -impl Copy for f16x4 {} -impl Copy for f32x2 {} -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f16x8 {} -impl Copy for f32x4 {} - extern "C" { fn extern_func(); static extern_static: u8; diff --git a/tests/assembly-llvm/asm/hexagon-types.rs b/tests/assembly-llvm/asm/hexagon-types.rs index 258e5b4355e0d..829696153293c 100644 --- a/tests/assembly-llvm/asm/hexagon-types.rs +++ b/tests/assembly-llvm/asm/hexagon-types.rs @@ -5,23 +5,19 @@ //@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: hexagon -#![feature(no_core, repr_simd, asm_experimental_arch)] +#![feature(no_core, asm_experimental_arch)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; type ptr = *const i32; -#[repr(simd)] -pub struct i32x32([i32; 32]); // 1024-bit HVX vector (128B mode) -impl Copy for i32x32 {} - -#[repr(simd)] -pub struct i32x64([i32; 64]); // 2048-bit HVX vector pair (128B mode) -impl Copy for i32x64 {} +type i32x32 = Simd; // 1024-bit HVX vector (128B mode) +type i32x64 = Simd; // 2048-bit HVX vector pair (128B mode) extern "C" { fn extern_func(); diff --git a/tests/assembly-llvm/asm/loongarch-modifiers.rs b/tests/assembly-llvm/asm/loongarch-modifiers.rs index 93a58864ef451..e2d4d53371857 100644 --- a/tests/assembly-llvm/asm/loongarch-modifiers.rs +++ b/tests/assembly-llvm/asm/loongarch-modifiers.rs @@ -13,52 +13,15 @@ //@ compile-flags: -Ctarget-feature=+32s //@ compile-flags: -Zmerge-functions=disabled -#![feature(asm_experimental_reg, no_core, repr_simd)] +#![feature(asm_experimental_reg, no_core)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register)] extern crate minicore; +use minicore::simd::*; use minicore::*; -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f32x4([f32; 4]); -#[repr(simd)] -pub struct f64x2([f64; 2]); -#[repr(simd)] -pub struct i8x32([i8; 32]); -#[repr(simd)] -pub struct i16x16([i16; 16]); -#[repr(simd)] -pub struct i32x8([i32; 8]); -#[repr(simd)] -pub struct i64x4([i64; 4]); -#[repr(simd)] -pub struct f32x8([f32; 8]); -#[repr(simd)] -pub struct f64x4([f64; 4]); - -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} -impl Copy for i8x32 {} -impl Copy for i16x16 {} -impl Copy for i32x8 {} -impl Copy for i64x4 {} -impl Copy for f32x8 {} -impl Copy for f64x4 {} - macro_rules! check { ($func:ident, $ty:ty, $class:ident, $code:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { diff --git a/tests/assembly-llvm/asm/powerpc-types.rs b/tests/assembly-llvm/asm/powerpc-types.rs index 076b216d019e8..211c817a325cb 100644 --- a/tests/assembly-llvm/asm/powerpc-types.rs +++ b/tests/assembly-llvm/asm/powerpc-types.rs @@ -13,12 +13,13 @@ //@[powerpc64_vsx] needs-llvm-components: powerpc //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, repr_simd, asm_experimental_arch)] +#![feature(no_core, asm_experimental_arch)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; #[cfg_attr(altivec, cfg(not(target_feature = "altivec")))] @@ -30,26 +31,6 @@ compile_error!("vsx cfg and target feature mismatch"); type ptr = *const i32; -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f32x4([f32; 4]); -#[repr(simd)] -pub struct f64x2([f64; 2]); - -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} - extern "C" { fn extern_func(); static extern_static: u8; diff --git a/tests/assembly-llvm/asm/s390x-types.rs b/tests/assembly-llvm/asm/s390x-types.rs index 75bcfd5b026f3..f649a6babdc27 100644 --- a/tests/assembly-llvm/asm/s390x-types.rs +++ b/tests/assembly-llvm/asm/s390x-types.rs @@ -7,29 +7,17 @@ //@[s390x_vector] needs-llvm-components: systemz //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, repr_simd, f16, f128)] +#![feature(no_core, f16, f128)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; type ptr = *const i32; -#[repr(simd)] -pub struct Simd([T; N]); - -impl Copy for Simd {} - -type i8x16 = Simd; -type i16x8 = Simd; -type i32x4 = Simd; -type i64x2 = Simd; -type f16x8 = Simd; -type f32x4 = Simd; -type f64x2 = Simd; - extern "C" { fn extern_func(); static extern_static: u8; diff --git a/tests/assembly-llvm/asm/x86-types.rs b/tests/assembly-llvm/asm/x86-types.rs index 9fe7ea00bd939..6e52ab260569d 100644 --- a/tests/assembly-llvm/asm/x86-types.rs +++ b/tests/assembly-llvm/asm/x86-types.rs @@ -9,75 +9,17 @@ //@ compile-flags: -C target-feature=+avx512bw //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, repr_simd, f16, f128)] +#![feature(no_core, f16, f128)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; type ptr = *mut u8; -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i16x8([i16; 8]); -#[repr(simd)] -pub struct i32x4([i32; 4]); -#[repr(simd)] -pub struct i64x2([i64; 2]); -#[repr(simd)] -pub struct f16x8([f16; 8]); -#[repr(simd)] -pub struct f32x4([f32; 4]); -#[repr(simd)] -pub struct f64x2([f64; 2]); - -#[repr(simd)] -pub struct i8x32([i8; 32]); -#[repr(simd)] -pub struct i16x16([i16; 16]); -#[repr(simd)] -pub struct i32x8([i32; 8]); -#[repr(simd)] -pub struct i64x4([i64; 4]); -#[repr(simd)] -pub struct f16x16([f16; 16]); -#[repr(simd)] -pub struct f32x8([f32; 8]); -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct i8x64([i8; 64]); -#[repr(simd)] -pub struct i16x32([i16; 32]); -#[repr(simd)] -pub struct i32x16([i32; 16]); -#[repr(simd)] -pub struct i64x8([i64; 8]); -#[repr(simd)] -pub struct f16x32([f16; 32]); -#[repr(simd)] -pub struct f32x16([f32; 16]); -#[repr(simd)] -pub struct f64x8([f64; 8]); - -macro_rules! impl_copy { - ($($ty:ident)*) => { - $( - impl Copy for $ty {} - )* - }; -} - -impl_copy!( - i8x16 i16x8 i32x4 i64x2 f16x8 f32x4 f64x2 - i8x32 i16x16 i32x8 i64x4 f16x16 f32x8 f64x4 - i8x64 i16x32 i32x16 i64x8 f16x32 f32x16 f64x8 -); - extern "C" { fn extern_func(); static extern_static: u8; diff --git a/tests/assembly-llvm/asm/xtensa-types.rs b/tests/assembly-llvm/asm/xtensa-types.rs index 8a6251e547e63..69c22d22b8b9a 100644 --- a/tests/assembly-llvm/asm/xtensa-types.rs +++ b/tests/assembly-llvm/asm/xtensa-types.rs @@ -4,12 +4,13 @@ //@ min-llvm-version: 22 //@ needs-llvm-components: xtensa -#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)] +#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; type ptr = *mut u8; diff --git a/tests/assembly-llvm/s390x-vector-abi.rs b/tests/assembly-llvm/s390x-vector-abi.rs index c0f770c3f0c35..2227d8c21628b 100644 --- a/tests/assembly-llvm/s390x-vector-abi.rs +++ b/tests/assembly-llvm/s390x-vector-abi.rs @@ -12,7 +12,7 @@ //@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector --cfg no_vector //@[z13_no_vector] needs-llvm-components: systemz -#![feature(no_core, lang_items, repr_simd)] +#![feature(no_core, lang_items)] #![no_core] #![crate_type = "lib"] #![allow(non_camel_case_types)] @@ -20,14 +20,9 @@ // See tests/ui/simd-abi-checks-s390x.rs for test for them. extern crate minicore; +use minicore::simd::{i8x8, i8x16, i8x32}; use minicore::*; -#[repr(simd)] -pub struct i8x8([i8; 8]); -#[repr(simd)] -pub struct i8x16([i8; 16]); -#[repr(simd)] -pub struct i8x32([i8; 32]); #[repr(C)] pub struct Wrapper(T); #[repr(C, align(16))] @@ -37,9 +32,6 @@ pub struct WrapperWithZst(T, PhantomData<()>); #[repr(transparent)] pub struct TransparentWrapper(T); -impl Copy for i8x8 {} -impl Copy for i8x16 {} -impl Copy for i8x32 {} impl Copy for Wrapper {} impl Copy for WrapperAlign16 {} impl Copy for WrapperWithZst {} diff --git a/tests/assembly-llvm/simd-bitmask.rs b/tests/assembly-llvm/simd-bitmask.rs index 98f63c165f352..de3f3b21f6e7c 100644 --- a/tests/assembly-llvm/simd-bitmask.rs +++ b/tests/assembly-llvm/simd-bitmask.rs @@ -17,27 +17,19 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort -#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![feature(no_core, lang_items, intrinsics)] #![no_core] #![allow(non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; -#[repr(simd)] -pub struct m8x16([i8; 16]); - -#[repr(simd)] -pub struct m8x64([i8; 64]); - -#[repr(simd)] -pub struct m32x4([i32; 4]); - -#[repr(simd)] -pub struct m64x2([i64; 2]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); +type m8x16 = i8x16; +type m8x64 = i8x64; +type m32x4 = i32x4; +type m64x2 = i64x2; +type m64x4 = i64x4; #[rustc_intrinsic] unsafe fn simd_bitmask(mask: V) -> B; diff --git a/tests/assembly-llvm/simd-intrinsic-gather.rs b/tests/assembly-llvm/simd-intrinsic-gather.rs index 788b8af52f626..1e8f501b1d7b8 100644 --- a/tests/assembly-llvm/simd-intrinsic-gather.rs +++ b/tests/assembly-llvm/simd-intrinsic-gather.rs @@ -6,21 +6,15 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort -#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![feature(no_core, lang_items, intrinsics)] #![no_core] #![allow(non_camel_case_types)] extern crate minicore; -use minicore::*; +use minicore::simd::*; -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[repr(simd)] -pub struct pf64x4([*const f64; 4]); +type m64x4 = Simd; +type pf64x4 = Simd<*const f64, 4>; #[rustc_intrinsic] unsafe fn simd_gather(values: V, mask: M, pointer: P) -> V; @@ -28,12 +22,12 @@ unsafe fn simd_gather(values: V, mask: M, pointer: P) -> V; // CHECK-LABEL: gather_f64x4 #[no_mangle] pub unsafe extern "C" fn gather_f64x4(mask: m64x4, ptrs: pf64x4) -> f64x4 { - // FIXME: This should also get checked to generate a gather instruction for avx2. + // FIXME(llvm23): This should also get checked to generate a gather instruction for avx2. // Currently llvm scalarizes this code, see https://github.com/llvm/llvm-project/issues/59789 // // x86-avx512-NOT: vpsllq // x86-avx512: vpmovq2m k1, ymm0 // x86-avx512-NEXT: vpxor xmm0, xmm0, xmm0 // x86-avx512-NEXT: vgatherqpd ymm0 {k1}, {{(ymmword)|(qword)}} ptr [1*ymm1] - simd_gather(f64x4([0_f64, 0_f64, 0_f64, 0_f64]), ptrs, mask) + simd_gather(f64x4::from_array([0_f64, 0_f64, 0_f64, 0_f64]), ptrs, mask) } diff --git a/tests/assembly-llvm/simd-intrinsic-mask-load.rs b/tests/assembly-llvm/simd-intrinsic-mask-load.rs index f77cdb6fc6768..e264e9b50895d 100644 --- a/tests/assembly-llvm/simd-intrinsic-mask-load.rs +++ b/tests/assembly-llvm/simd-intrinsic-mask-load.rs @@ -9,30 +9,17 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort -#![feature(no_core, lang_items, repr_simd, intrinsics, adt_const_params)] +#![feature(no_core, lang_items, intrinsics, adt_const_params)] #![no_core] #![allow(non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; -#[repr(simd)] -pub struct i8x16([i8; 16]); - -#[repr(simd)] -pub struct m8x16([i8; 16]); - -#[repr(simd)] -pub struct f32x8([f32; 8]); - -#[repr(simd)] -pub struct m32x8([i32; 8]); - -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); +type m8x16 = i8x16; +type m32x8 = i32x8; +type m64x4 = i64x4; #[rustc_intrinsic] unsafe fn simd_masked_load(mask: M, pointer: P, values: T) -> T; @@ -59,7 +46,7 @@ pub unsafe extern "C" fn load_i8x16(mask: m8x16, pointer: *const i8) -> i8x16 { simd_masked_load::<_, _, _, { SimdAlign::Element }>( mask, pointer, - i8x16([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + i8x16::from_array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), ) } @@ -75,7 +62,7 @@ pub unsafe extern "C" fn load_f32x8(mask: m32x8, pointer: *const f32) -> f32x8 { simd_masked_load::<_, _, _, { SimdAlign::Element }>( mask, pointer, - f32x8([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32]), + f32x8::from_array([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32]), ) } @@ -93,7 +80,7 @@ pub unsafe extern "C" fn load_f32x8_aligned(mask: m32x8, pointer: *const f32) -> simd_masked_load::<_, _, _, { SimdAlign::Vector }>( mask, pointer, - f32x8([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32]), + f32x8::from_array([0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32, 0_f32]), ) } @@ -108,6 +95,6 @@ pub unsafe extern "C" fn load_f64x4(mask: m64x4, pointer: *const f64) -> f64x4 { simd_masked_load::<_, _, _, { SimdAlign::Element }>( mask, pointer, - f64x4([0_f64, 0_f64, 0_f64, 0_f64]), + f64x4::from_array([0_f64, 0_f64, 0_f64, 0_f64]), ) } diff --git a/tests/assembly-llvm/simd-intrinsic-mask-reduce.rs b/tests/assembly-llvm/simd-intrinsic-mask-reduce.rs index d3698fda5fe85..37b22051ea906 100644 --- a/tests/assembly-llvm/simd-intrinsic-mask-reduce.rs +++ b/tests/assembly-llvm/simd-intrinsic-mask-reduce.rs @@ -14,15 +14,14 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort -#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![feature(no_core, lang_items, intrinsics)] #![no_core] #![allow(non_camel_case_types)] extern crate minicore; use minicore::*; -#[repr(simd)] -pub struct mask8x16([i8; 16]); +type mask8x16 = simd::Simd; #[rustc_intrinsic] unsafe fn simd_reduce_all(x: T) -> bool; diff --git a/tests/assembly-llvm/simd-intrinsic-mask-store.rs b/tests/assembly-llvm/simd-intrinsic-mask-store.rs index 20154076836dc..b6c59b860ce80 100644 --- a/tests/assembly-llvm/simd-intrinsic-mask-store.rs +++ b/tests/assembly-llvm/simd-intrinsic-mask-store.rs @@ -9,30 +9,17 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort -#![feature(no_core, lang_items, repr_simd, intrinsics, adt_const_params)] +#![feature(no_core, lang_items, intrinsics, adt_const_params)] #![no_core] #![allow(non_camel_case_types)] extern crate minicore; +use minicore::simd::*; use minicore::*; -#[repr(simd)] -pub struct i8x16([i8; 16]); - -#[repr(simd)] -pub struct m8x16([i8; 16]); - -#[repr(simd)] -pub struct f32x8([f32; 8]); - -#[repr(simd)] -pub struct m32x8([i32; 8]); - -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); +type m8x16 = i8x16; +type m32x8 = i32x8; +type m64x4 = i64x4; #[rustc_intrinsic] unsafe fn simd_masked_store(mask: M, pointer: P, values: T); diff --git a/tests/assembly-llvm/simd-intrinsic-scatter.rs b/tests/assembly-llvm/simd-intrinsic-scatter.rs index 48fabba1ec380..c887314bed355 100644 --- a/tests/assembly-llvm/simd-intrinsic-scatter.rs +++ b/tests/assembly-llvm/simd-intrinsic-scatter.rs @@ -6,21 +6,17 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort -#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![feature(no_core, lang_items, intrinsics)] #![no_core] #![allow(non_camel_case_types)] extern crate minicore; +use minicore::simd::Simd; use minicore::*; -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[repr(simd)] -pub struct pf64x4([*mut f64; 4]); +type f64x4 = Simd; +type m64x4 = Simd; +type pf64x4 = Simd<*mut f64, 4>; #[rustc_intrinsic] unsafe fn simd_scatter(values: V, pointer: P, mask: M); diff --git a/tests/assembly-llvm/simd-intrinsic-select.rs b/tests/assembly-llvm/simd-intrinsic-select.rs index 84ae6568b742a..ca942f82ba5a3 100644 --- a/tests/assembly-llvm/simd-intrinsic-select.rs +++ b/tests/assembly-llvm/simd-intrinsic-select.rs @@ -11,42 +11,19 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort -#![feature(no_core, lang_items, repr_simd, intrinsics)] +#![feature(no_core, lang_items, intrinsics)] #![no_core] #![allow(non_camel_case_types)] extern crate minicore; -use minicore::*; - -#[repr(simd)] -pub struct i8x16([i8; 16]); - -#[repr(simd)] -pub struct m8x16([i8; 16]); - -#[repr(simd)] -pub struct f32x4([f32; 4]); - -#[repr(simd)] -pub struct m32x4([i32; 4]); - -#[repr(simd)] -pub struct f64x2([f64; 2]); - -#[repr(simd)] -pub struct m64x2([i64; 2]); - -#[repr(simd)] -pub struct f64x4([f64; 4]); - -#[repr(simd)] -pub struct m64x4([i64; 4]); - -#[repr(simd)] -pub struct f64x8([f64; 8]); - -#[repr(simd)] -pub struct m64x8([i64; 8]); +use minicore::simd::*; + +type m8x16 = i8x16; +type m32x4 = i32x4; +type m32x8 = i32x8; +type m64x2 = i64x2; +type m64x4 = i64x4; +type m64x8 = i64x8; #[rustc_intrinsic] unsafe fn simd_select(mask: M, a: V, b: V) -> V; diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index d63d48e56903d..e8bfdf80c98e8 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -30,6 +30,7 @@ decl_macro, f16, f128, + repr_simd, transparent_unions, asm_experimental_arch, unboxed_closures @@ -428,3 +429,58 @@ pub enum SimdAlign { } impl ConstParamTy_ for SimdAlign {} + +pub mod simd { + use super::Copy; + + #[repr(simd)] + pub struct Simd(pub [T; N]); + + impl Copy for Simd {} + + impl Simd { + pub fn from_array(arr: [T; N]) -> Self { + Self(arr) + } + } + + pub type f16x2 = Simd; + pub type f16x4 = Simd; + pub type f16x8 = Simd; + pub type f16x16 = Simd; + pub type f16x32 = Simd; + + pub type f32x2 = Simd; + pub type f32x4 = Simd; + pub type f32x8 = Simd; + pub type f32x16 = Simd; + pub type f32x32 = Simd; + + pub type f64x1 = Simd; + pub type f64x2 = Simd; + pub type f64x4 = Simd; + pub type f64x8 = Simd; + + pub type i8x8 = Simd; + pub type i8x16 = Simd; + pub type i8x32 = Simd; + pub type i8x64 = Simd; + + pub type i16x2 = Simd; + pub type i16x4 = Simd; + pub type i16x8 = Simd; + pub type i16x16 = Simd; + pub type i16x32 = Simd; + + pub type i32x2 = Simd; + pub type i32x4 = Simd; + pub type i32x8 = Simd; + pub type i32x16 = Simd; + + pub type i64x1 = Simd; + pub type i64x2 = Simd; + pub type i64x4 = Simd; + pub type i64x8 = Simd; + + pub type u8x16 = Simd; +} diff --git a/tests/codegen-llvm/align-byval-vector.rs b/tests/codegen-llvm/align-byval-vector.rs index 6c478c58da0a3..45f74fff86521 100644 --- a/tests/codegen-llvm/align-byval-vector.rs +++ b/tests/codegen-llvm/align-byval-vector.rs @@ -8,18 +8,16 @@ // Tests that aggregates containing vector types get their alignment increased to 16 on Darwin. -#![feature(no_core, repr_simd, simd_ffi)] +#![feature(no_core, simd_ffi)] #![crate_type = "lib"] #![no_std] #![no_core] #![allow(non_camel_case_types)] extern crate minicore; +use minicore::simd::i32x4; use minicore::*; -#[repr(simd)] -pub struct i32x4([i32; 4]); - #[repr(C)] pub struct Foo { a: i32x4, @@ -44,12 +42,12 @@ extern "C" { } pub fn main() { - unsafe { f(Foo { a: i32x4([1, 2, 3, 4]), b: 0 }) } + unsafe { f(Foo { a: i32x4::from_array([1, 2, 3, 4]), b: 0 }) } unsafe { g(DoubleFoo { - one: Foo { a: i32x4([1, 2, 3, 4]), b: 0 }, - two: Foo { a: i32x4([1, 2, 3, 4]), b: 0 }, + one: Foo { a: i32x4::from_array([1, 2, 3, 4]), b: 0 }, + two: Foo { a: i32x4::from_array([1, 2, 3, 4]), b: 0 }, }) } } diff --git a/tests/codegen-llvm/simd/array-repeat.rs b/tests/codegen-llvm/simd/array-repeat.rs index 691167f866626..c4e7dfaf69d92 100644 --- a/tests/codegen-llvm/simd/array-repeat.rs +++ b/tests/codegen-llvm/simd/array-repeat.rs @@ -9,18 +9,13 @@ //@ [S390X] compile-flags: -Copt-level=3 --target s390x-unknown-linux-gnu -Ctarget-feature=+vector //@ [S390X] needs-llvm-components: systemz #![crate_type = "lib"] -#![feature(repr_simd)] #![feature(no_core)] #![no_std] #![no_core] extern crate minicore; +use minicore::simd::u8x16; use minicore::*; -#[repr(simd)] -pub struct Simd(pub [T; N]); - -pub type u8x16 = Simd; - // Regression test for https://github.com/rust-lang/rust/issues/97804. #[unsafe(no_mangle)] diff --git a/tests/codegen-llvm/transmute-scalar.rs b/tests/codegen-llvm/transmute-scalar.rs index 16adfb663fdbb..57008307b0fcd 100644 --- a/tests/codegen-llvm/transmute-scalar.rs +++ b/tests/codegen-llvm/transmute-scalar.rs @@ -3,10 +3,10 @@ //@ needs-llvm-components: x86 #![crate_type = "lib"] -#![feature(no_core, repr_simd)] +#![feature(no_core)] #![no_core] extern crate minicore; - +use minicore::simd::Simd; use minicore::*; // With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, @@ -108,8 +108,7 @@ pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { unsafe { mem::transmute(b) } } -#[repr(simd)] -struct S([i64; 1]); +type S = Simd; // CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b) // CHECK-NEXT: start: From 602c46252ea6f438075574732bcc8bab18252dc7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 21 Jul 2026 21:38:30 +1000 Subject: [PATCH 29/31] Remove the blanket `#![cfg_attr(test, allow(unused))]` from bootstrap This blanket allow was hiding several unused imports and items in test-only code. It has been replaced with a number of narrower ensures. --- src/bootstrap/Cargo.lock | 23 ------- src/bootstrap/Cargo.toml | 1 - src/bootstrap/src/core/build_steps/llvm.rs | 1 + src/bootstrap/src/core/build_steps/tool.rs | 1 + .../src/core/builder/cli_paths/tests.rs | 6 +- src/bootstrap/src/core/builder/tests.rs | 66 ++++--------------- src/bootstrap/src/core/config/config.rs | 1 + src/bootstrap/src/core/config/tests.rs | 18 ++--- src/bootstrap/src/core/config/toml/llvm.rs | 1 + src/bootstrap/src/core/download.rs | 7 +- src/bootstrap/src/lib.rs | 1 - src/bootstrap/src/utils/build_stamp/tests.rs | 4 +- src/bootstrap/src/utils/cache.rs | 2 +- src/bootstrap/src/utils/cache/tests.rs | 4 +- src/bootstrap/src/utils/cc_detect/tests.rs | 10 +-- src/bootstrap/src/utils/helpers.rs | 1 + src/bootstrap/src/utils/helpers/tests.rs | 1 - src/bootstrap/src/utils/tests/git.rs | 2 - src/bootstrap/src/utils/tests/mod.rs | 12 ++-- 19 files changed, 39 insertions(+), 123 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 973334a8dda45..c05eeb97829b3 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -55,7 +55,6 @@ dependencies = [ "libc", "object", "opener", - "pretty_assertions", "semver", "serde", "serde_derive", @@ -229,12 +228,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - [[package]] name = "digest" version = "0.10.7" @@ -526,16 +519,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" -[[package]] -name = "pretty_assertions" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" -dependencies = [ - "diff", - "yansi", -] - [[package]] name = "proc-macro2" version = "1.0.89" @@ -1144,9 +1127,3 @@ checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" dependencies = [ "lzma-sys", ] - -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index b2e8c42adf48b..cb96af268a6aa 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -85,7 +85,6 @@ features = [ ] [dev-dependencies] -pretty_assertions = "1.4" insta = "1.43" # We care a lot about bootstrap's compile times, so don't include debuginfo for diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 0c7806342a1e6..572df47d3a62c 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -200,6 +200,7 @@ pub const LLVM_INVALIDATION_PATHS: &[&str] = &[ ]; /// Detect whether LLVM sources have been modified locally or not. +#[cfg_attr(test, expect(dead_code))] pub(crate) fn detect_llvm_freshness(config: &Config, is_git: bool) -> PathFreshness { if is_git { config.check_path_modifications(LLVM_INVALIDATION_PATHS) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index e5d24280092d9..ea8a0b581fcb0 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1228,6 +1228,7 @@ impl Step for LlvmBitcodeLinker { } #[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[cfg_attr(test, expect(dead_code))] pub struct LibcxxVersionTool { pub target: TargetSelection, } diff --git a/src/bootstrap/src/core/builder/cli_paths/tests.rs b/src/bootstrap/src/core/builder/cli_paths/tests.rs index 40a37e5cf5631..79137de12981b 100644 --- a/src/bootstrap/src/core/builder/cli_paths/tests.rs +++ b/src/bootstrap/src/core/builder/cli_paths/tests.rs @@ -1,10 +1,8 @@ use std::collections::{BTreeSet, HashSet}; -use std::fs; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::{Arc, Mutex}; use crate::Build; -use crate::core::builder::cli_paths::match_paths_to_steps_and_run; use crate::core::builder::{Builder, StepDescription}; use crate::utils::tests::TestCtx; @@ -34,7 +32,7 @@ fn render_steps_for_cli_args(args_str: &str) -> String { let mut builder = Builder::new(&build); // Tell the builder to log steps that it would run, instead of running them. - let mut buf = Arc::new(Mutex::new(String::new())); + let buf = Arc::new(Mutex::new(String::new())); let buf2 = Arc::clone(&buf); builder.log_cli_step_for_tests = Some(Box::new(move |step_desc, pathsets, targets| { use std::fmt::Write; diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index c8730dd8fa956..02c57023dc354 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1,13 +1,10 @@ // ignore-tidy-file-filelength -use std::env::VarError; -use std::{panic, thread}; +use std::panic; use build_helper::stage0_parser::parse_stage0_file; use llvm::prebuilt_llvm_config; use super::*; -use crate::Flags; -use crate::core::build_steps::doc::DocumentationFormat; use crate::core::builder::cli_paths::PATH_REMAP; use crate::core::config::Config; use crate::utils::cache::ExecutedStep; @@ -17,7 +14,6 @@ use crate::utils::tests::{ConfigBuilder, TestCtx}; static TEST_TRIPLE_1: &str = "i686-unknown-haiku"; static TEST_TRIPLE_2: &str = "i686-unknown-hurd-gnu"; -static TEST_TRIPLE_3: &str = "i686-unknown-netbsd"; fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { configure_with_args(&[cmd], host, target) @@ -27,10 +23,6 @@ fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config { TestCtx::new().config(cmd[0]).args(&cmd[1..]).hosts(host).targets(target).create_config() } -fn first(v: Vec<(A, B)>) -> Vec { - v.into_iter().map(|(a, _)| a).collect::>() -} - fn run_build(paths: &[PathBuf], config: Config) -> Cache { let kind = config.cmd.kind(); let build = Build::new(config); @@ -46,28 +38,6 @@ fn check_cli(paths: [&str; N]) { ); } -macro_rules! std { - ($host:ident => $target:ident, stage = $stage:literal) => { - compile::Std::new( - Compiler::new($stage, TargetSelection::from_user($host)), - TargetSelection::from_user($target), - ) - }; -} - -macro_rules! doc_std { - ($host:ident => $target:ident, stage = $stage:literal) => {{ doc::Std::new($stage, TargetSelection::from_user($target), DocumentationFormat::Html) }}; -} - -macro_rules! rustc { - ($host:ident => $target:ident, stage = $stage:literal) => { - compile::Rustc::new( - Compiler::new($stage, TargetSelection::from_user($host)), - TargetSelection::from_user($target), - ) - }; -} - #[test] fn test_valid() { // make sure multi suite paths are accepted @@ -228,10 +198,7 @@ fn parse_config_download_rustc_at(path: &Path, download_rustc: &str, ci: bool) - } mod dist { - use pretty_assertions::assert_eq; - - use super::{Config, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, first, run_build}; - use crate::Flags; + use super::{Config, TEST_TRIPLE_1, TEST_TRIPLE_2}; use crate::core::builder::tests::host_target; use crate::core::builder::*; @@ -344,7 +311,7 @@ fn test_test_coverage() { // case is the one that failed. println!("Testing case: {cmd:?}"); let config = configure_with_args(cmd, &[], &[TEST_TRIPLE_1]); - let mut cache = run_build(&config.paths.clone(), config); + let cache = run_build(&config.paths.clone(), config); let modes = cache.inspect_all_steps_of_type::(|step, ()| step.mode.as_str()); @@ -507,22 +474,15 @@ fn any_debug() { /// These tests use insta for snapshot testing. /// See bootstrap's README on how to bless the snapshots. mod snapshot { - use std::path::PathBuf; - - use crate::core::build_steps::{compile, dist, doc, test, tool}; - use crate::core::builder::tests::{ - RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, first, host_target, - render_steps, run_build, - }; - use crate::core::builder::{Builder, Kind, StepDescription, StepMetadata}; + use crate::Compiler; + use crate::core::build_steps::test; + use crate::core::builder::tests::{RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, host_target}; + use crate::core::builder::{Kind, StepMetadata}; use crate::core::config::TargetSelection; use crate::core::config::toml::target::{ DefaultLinuxLinkerOverride, with_default_linux_linker_overrides, }; - use crate::utils::cache::Cache; - use crate::utils::helpers::get_host_target; use crate::utils::tests::{ConfigBuilder, TestCtx}; - use crate::{Build, Compiler, Config, Flags, Subcommand}; #[test] fn build_default() { @@ -2426,7 +2386,6 @@ mod snapshot { #[test] fn test_library_tests_only_does_not_build_rustdoc() { let ctx = TestCtx::new(); - let host = TargetSelection::from_user(&host_target()); insta::assert_snapshot!( ctx.config("test").args(&["--tests", "library/core"]).render_steps(), @r" @@ -3257,7 +3216,7 @@ impl ExecutedSteps { } fn fuzzy_metadata_eq(executed: &StepMetadata, to_match: &StepMetadata) -> bool { - let StepMetadata { name, kind, target, built_by: _, stage: _, metadata } = executed; + let StepMetadata { name, kind, target, built_by: _, stage: _, metadata: _ } = executed; *name == to_match.name && *kind == to_match.kind && *target == to_match.target } @@ -3309,8 +3268,6 @@ fn render_steps(steps: &[ExecutedStep], config: RenderConfig) -> String { steps .iter() .filter_map(|step| { - use std::fmt::Write; - let Some(metadata) = &step.metadata else { return None; }; @@ -3324,12 +3281,13 @@ fn render_steps(steps: &[ExecutedStep], config: RenderConfig) -> String { fn render_metadata(metadata: &StepMetadata, config: &RenderConfig) -> String { let mut record = format!("[{}] ", metadata.kind.as_str()); if let Some(compiler) = metadata.built_by { - write!(record, "{} -> ", render_compiler(compiler, config)); + write!(record, "{} -> ", render_compiler(compiler, config)).unwrap(); } let stage = metadata.get_stage().map(|stage| format!("{stage} ")).unwrap_or_default(); - write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target, config)); + write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target, config)) + .unwrap(); if let Some(metadata) = &metadata.metadata { - write!(record, " {metadata}"); + write!(record, " {metadata}").unwrap(); } record } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index eaa9672d2130f..8b8c595882579 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -57,6 +57,7 @@ use crate::core::download::{ }; use crate::utils::channel; use crate::utils::exec::{ExecutionContext, command}; +#[cfg_attr(test, expect(unused_imports))] use crate::utils::helpers::{exe, fail, get_host_target}; use crate::{ CodegenBackendKind, GitInfo, OnceLock, TargetSelection, check_ci_llvm, exit, helpers, t, diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 89046c0eee779..91327057a8183 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -1,13 +1,12 @@ use std::collections::BTreeSet; -use std::fs::{File, remove_file}; +use std::fs; +use std::fs::File; use std::io::Write; -use std::path::{Path, PathBuf}; -use std::{env, fs}; +use std::path::PathBuf; use build_helper::ci::CiEnv; use build_helper::git::PathFreshness; use clap::CommandFactory; -use serde::Deserialize; use super::flags::Flags; use super::toml::change_id::ChangeIdWrapper; @@ -16,11 +15,7 @@ use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; use crate::ChangeId; use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; -use crate::core::build_steps::{llvm, test}; -use crate::core::config::toml::TomlConfig; -use crate::core::config::{ - BootstrapOverrideLld, CompilerBuiltins, StringOrBool, Target, TargetSelection, -}; +use crate::core::config::{BootstrapOverrideLld, CompilerBuiltins, Target, TargetSelection}; use crate::utils::tests::TestCtx; use crate::utils::tests::git::git_test; @@ -28,11 +23,6 @@ pub(crate) fn parse(config: &str) -> Config { TestCtx::new().config("check").with_default_toml_config(config).create_config() } -fn get_toml(file: &Path) -> Result { - let contents = std::fs::read_to_string(file).unwrap(); - toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table)) -} - fn modified(upstream: impl Into, changes: &[&str]) -> PathFreshness { PathFreshness::HasLocalModifications { upstream: upstream.into(), diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs index 5f08884e4ef71..8bc6b4ef2491c 100644 --- a/src/bootstrap/src/core/config/toml/llvm.rs +++ b/src/bootstrap/src/core/config/toml/llvm.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Deserializer}; use crate::core::config::StringOrBool; +#[cfg_attr(test, expect(unused_imports))] use crate::core::config::toml::{Merge, ReplaceOpt, TomlConfig}; use crate::{HashMap, HashSet, PathBuf, define_config, exit}; diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 078012be72c59..76fd2cb0bc14b 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -505,8 +505,8 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo #[cfg(test)] pub(crate) fn maybe_download_rustfmt<'a>( - dwn_ctx: impl AsRef>, - out: &Path, + _dwn_ctx: impl AsRef>, + _out: &Path, ) -> Option { Some(PathBuf::new()) } @@ -574,7 +574,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( } #[cfg(test)] -pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef>, out: &Path) {} +pub(crate) fn download_beta_toolchain<'a>(_dwn_ctx: impl AsRef>, _out: &Path) {} #[cfg(not(test))] pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef>, out: &Path) { @@ -600,6 +600,7 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef( dwn_ctx: impl AsRef>, out: &Path, diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index f08346789e7e8..c487941b34b87 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -15,7 +15,6 @@ //! //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![cfg_attr(test, allow(unused))] use std::cell::Cell; use std::collections::{BTreeSet, HashMap, HashSet}; diff --git a/src/bootstrap/src/utils/build_stamp/tests.rs b/src/bootstrap/src/utils/build_stamp/tests.rs index f150266159a25..ae70c6085e7fb 100644 --- a/src/bootstrap/src/utils/build_stamp/tests.rs +++ b/src/bootstrap/src/utils/build_stamp/tests.rs @@ -1,8 +1,6 @@ -use std::path::PathBuf; - use tempfile::TempDir; -use crate::{BuildStamp, Config, Flags}; +use crate::BuildStamp; #[test] #[should_panic(expected = "prefix can not start or end with '.'")] diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs index 8c5b3529979d7..1de1359abb159 100644 --- a/src/bootstrap/src/utils/cache.rs +++ b/src/bootstrap/src/utils/cache.rs @@ -289,7 +289,7 @@ impl Cache { } #[cfg(test)] - pub fn into_executed_steps(mut self) -> Vec { + pub fn into_executed_steps(self) -> Vec { mem::take(&mut self.executed_steps.borrow_mut()) } } diff --git a/src/bootstrap/src/utils/cache/tests.rs b/src/bootstrap/src/utils/cache/tests.rs index fd0a7cccd60fc..722b66d861b83 100644 --- a/src/bootstrap/src/utils/cache/tests.rs +++ b/src/bootstrap/src/utils/cache/tests.rs @@ -1,6 +1,4 @@ -use std::path::PathBuf; - -use crate::utils::cache::{INTERNER, Internable, Interner, TyIntern}; +use crate::utils::cache::{INTERNER, Interner, TyIntern}; #[test] fn test_string_interning() { diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index 30757a39caa1c..a2f35e6a1030d 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -1,10 +1,10 @@ -use std::path::{Path, PathBuf}; -use std::{env, iter}; +use std::iter; +use std::path::PathBuf; use super::*; +use crate::Build; use crate::core::config::{Target, TargetSelection}; use crate::utils::tests::TestCtx; -use crate::{Build, Config, Flags, t}; #[test] fn test_ndk_compiler_c() { @@ -85,7 +85,7 @@ fn test_default_compiler_wasi() { let wasi_sdk = PathBuf::from("/wasi-sdk"); build.wasi_sdk_path = Some(wasi_sdk.clone()); - let mut cfg = cc::Build::new(); + let cfg = cc::Build::new(); if let Some(result) = default_compiler(&cfg, Language::C, target.clone(), &build) { let expected = { let compiler = format!("{}-clang", target.triple); @@ -104,7 +104,7 @@ fn test_default_compiler_fallback() { let config = TestCtx::new().config("build").create_config(); let build = Build::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); - let mut cfg = cc::Build::new(); + let cfg = cc::Build::new(); let result = default_compiler(&cfg, Language::C, target, &build); assert!(result.is_none(), "default_compiler should return None for generic targets"); } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 394e14c80a1ef..c36d43f0cb5a4 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -595,6 +595,7 @@ pub fn detail_exit(code: i32, is_test: bool) -> ! { } } +#[cfg_attr(test, expect(dead_code))] pub fn fail(s: &str) -> ! { eprintln!("\n\n{s}\n\n"); detail_exit(1, cfg!(test)); diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs index b051a374a0866..cfb1dde2d6ea3 100644 --- a/src/bootstrap/src/utils/helpers/tests.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -7,7 +7,6 @@ use crate::utils::helpers::{ symlink_dir, }; use crate::utils::tests::TestCtx; -use crate::{Config, Flags}; #[test] fn test_make() { diff --git a/src/bootstrap/src/utils/tests/git.rs b/src/bootstrap/src/utils/tests/git.rs index d9dd9ab980088..528452680d70b 100644 --- a/src/bootstrap/src/utils/tests/git.rs +++ b/src/bootstrap/src/utils/tests/git.rs @@ -8,7 +8,6 @@ use build_helper::git::{GitConfig, PathFreshness, check_path_modifications}; pub struct GitCtx { dir: tempfile::TempDir, - pub git_repo: String, pub nightly_branch: String, pub merge_bot_email: String, } @@ -18,7 +17,6 @@ impl GitCtx { let dir = tempfile::TempDir::new().unwrap(); let ctx = Self { dir, - git_repo: "rust-lang/rust".to_string(), nightly_branch: "nightly".to_string(), merge_bot_email: "Merge bot ".to_string(), }; diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index e2a689c0f0ccf..94dfa33455d80 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -1,14 +1,10 @@ //! This module contains shared utilities for bootstrap tests. use std::path::{Path, PathBuf}; -use std::thread; use tempfile::TempDir; -use crate::core::builder::Builder; -use crate::core::config::DryRun; -use crate::utils::helpers::get_host_target; -use crate::{Build, Config, Flags, t}; +use crate::{Config, Flags}; pub mod git; @@ -69,11 +65,11 @@ impl ConfigBuilder { } } - pub fn path(mut self, path: &str) -> Self { + pub fn path(self, path: &str) -> Self { self.arg(path) } - pub fn paths(mut self, paths: &[&str]) -> Self { + pub fn paths(self, paths: &[&str]) -> Self { self.args(paths) } @@ -90,7 +86,7 @@ impl ConfigBuilder { } /// Set the specified target to be treated as a no_std target. - pub fn override_target_no_std(mut self, target: &str) -> Self { + pub fn override_target_no_std(self, target: &str) -> Self { self.args(&["--set", &format!("target.{target}.no-std=true")]) } From 0b0c55f6fef40c6d2135979b84fa9228e1c19c7d Mon Sep 17 00:00:00 2001 From: Yukang Date: Tue, 21 Jul 2026 23:14:20 +0800 Subject: [PATCH 30/31] Add layout cycle hang regression test --- ...lized-gat-projection-cycle-issue-153205.rs | 27 +++++++++++++++++++ ...d-gat-projection-cycle-issue-153205.stderr | 22 +++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tests/ui/layout/uninitialized-gat-projection-cycle-issue-153205.rs create mode 100644 tests/ui/layout/uninitialized-gat-projection-cycle-issue-153205.stderr diff --git a/tests/ui/layout/uninitialized-gat-projection-cycle-issue-153205.rs b/tests/ui/layout/uninitialized-gat-projection-cycle-issue-153205.rs new file mode 100644 index 0000000000000..d37764238e6b4 --- /dev/null +++ b/tests/ui/layout/uninitialized-gat-projection-cycle-issue-153205.rs @@ -0,0 +1,27 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/153205. +//! An uninitialized recursive GAT projection used to hang during optimized MIR processing +//! instead of reporting the layout cycle. + +//@ build-fail +//@ compile-flags: -O + +trait Apply { + type Output; +} + +struct Identity; + +impl Apply for Identity { + type Output = T; +} + +struct Thing(A::Output); +//~^ ERROR cycle detected when computing layout of `Thing` + +fn foo() { + let _x: Thing; +} + +fn main() { + foo::(); +} diff --git a/tests/ui/layout/uninitialized-gat-projection-cycle-issue-153205.stderr b/tests/ui/layout/uninitialized-gat-projection-cycle-issue-153205.stderr new file mode 100644 index 0000000000000..b3246edfa751e --- /dev/null +++ b/tests/ui/layout/uninitialized-gat-projection-cycle-issue-153205.stderr @@ -0,0 +1,22 @@ +error[E0391]: cycle detected when computing layout of `Thing` + --> $DIR/uninitialized-gat-projection-cycle-issue-153205.rs:18:1 + | +LL | struct Thing(A::Output); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing layout of `::Output>`... + --> $DIR/uninitialized-gat-projection-cycle-issue-153205.rs:9:5 + | +LL | type Output; + | ^^^^^^^^^^^^^^ + = note: ...which again requires computing layout of `Thing`, completing the cycle +note: cycle used when optimizing MIR for `main` + --> $DIR/uninitialized-gat-projection-cycle-issue-153205.rs:25:1 + | +LL | fn main() { + | ^^^^^^^^^ + = note: for more information, see and + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. From 7f2417bcc2bc0505f80c9ab6bfb26e99c1661337 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 20 Jul 2026 15:36:33 -0500 Subject: [PATCH 31/31] Refactor is_opsem_inhabited --- .../rustc_middle/src/ty/inhabitedness/mod.rs | 251 ++++++++---------- 1 file changed, 116 insertions(+), 135 deletions(-) diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 8e5316bab8fbb..42485a17f1011 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -51,7 +51,7 @@ use rustc_type_ir::TyKind::*; use tracing::instrument; use crate::query::Providers; -use crate::ty::{self, DefId, Ty, TyCtxt, TypeVisitableExt, VariantDef, Visibility}; +use crate::ty::{self, DefId, Ty, TyCtxt, TypeVisitableExt, TypingEnv, VariantDef, Visibility}; pub mod inhabited_predicate; @@ -221,10 +221,7 @@ impl<'tcx> Ty<'tcx> { /// Beyond that, the value returned by this function is not a stable guarantee. pub fn is_opsem_inhabited(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { // Handle simple cases directly, use the query with its cache for the rest. - is_opsem_inhabited_recursor(self, tcx, &mut (), /* stop_at_ref */ false, &|ty, _, _| { - // ADT handler: stop recursing, invoke the query. - tcx.is_opsem_inhabited_raw(typing_env.as_query_input(ty)) - }) + OpsemInhabitedCtx { tcx, typing_env, seen: None, stop_at_ref: false }.is_inhabited_ty(self) } } @@ -249,109 +246,129 @@ fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedP } } -/// Recurse over a type to determine whether it is inhabited on the opsem level. +/// Context for computing whether a type is inhabited on the opsem level. /// See `is_opsem_inhabited` above for the spec of what we compute. -/// -/// When we encounter an ADT, we call `adt_handler`, giving it as its last argument a closure that -/// it can invoke to continue the recursion. This lets us share the logic for "simple" cases -/// (i.e., everything except for ADTs) between `Ty::is_opsem_inhabited` and the query. -/// -/// `seen` is used to detect infinite recursion: the set contains all ADTs that we encountered -/// on our path to the current type. -/// If `stop_at_ref` is true, we stop recursing at the next reference we encounter. -fn is_opsem_inhabited_recursor<'tcx, SEEN>( - ty: Ty<'tcx>, +struct OpsemInhabitedCtx<'tcx> { tcx: TyCtxt<'tcx>, - seen: &mut SEEN, + typing_env: TypingEnv<'tcx>, + /// IDs of ADTs that have been encountered in the current stack. + /// It's `None` unless we are inside the `is_opsem_inhabited_raw` query, + /// which is only invoked for more complex types. + seen: Option>, + /// If an ADT is encountered recursively within itself, then `stop_at_ref` + /// is set to `true`, and then any nested references are considered inhabited. stop_at_ref: bool, - adt_handler: &impl Fn( - Ty<'tcx>, - &mut SEEN, - &dyn Fn(Ty<'tcx>, &mut SEEN, /* stop_at_ref */ bool) -> bool, - ) -> bool, -) -> bool { - match *ty.kind() { - // Trivially (un)inhabited types - ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Bool - | ty::Char - | ty::Str - | ty::Foreign(..) - | ty::RawPtr(..) - | ty::FnPtr(..) - | ty::FnDef(..) => true, - ty::Dynamic(..) => true, // We can't reason about traits, assume they are inhabited - ty::Slice(..) => true, // Slices can always be empty - ty::Never => false, +} - // Types where we recurse - ty::Ref(_, pointee, _) => { - if stop_at_ref { - // Bailing out here is safe as the layout code always considers references - // inhabited, so the implication ("layout uninhabited => opsem uninhabited") - // is upheld. - return true; +impl<'tcx> OpsemInhabitedCtx<'tcx> { + /// See `is_opsem_inhabited` above for the spec of what we compute. + fn is_inhabited_ty(&mut self, ty: Ty<'tcx>) -> bool { + let tcx = self.tcx; + match *ty.kind() { + // Trivially (un)inhabited types + ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Bool + | ty::Char + | ty::Str + | ty::Foreign(..) + | ty::RawPtr(..) + | ty::FnPtr(..) + | ty::FnDef(..) => true, + ty::Dynamic(..) => true, // We can't reason about traits, assume they are inhabited + ty::Slice(..) => true, // Slices can always be empty + ty::Never => false, + + // Types where we recurse + ty::Ref(_, pointee, _) => { + if self.stop_at_ref { + // Bailing out here is safe as the layout code always considers references + // inhabited, so the implication ("layout uninhabited => opsem uninhabited") + // is upheld. + return true; + } + self.is_inhabited_ty(pointee) + } + ty::Tuple(tys) => tys.iter().all(|ty| self.is_inhabited_ty(ty)), + ty::Array(elem, len) => { + len.try_to_target_usize(tcx).unwrap() == 0 || self.is_inhabited_ty(elem) + } + ty::Pat(inner, _pat) => self.is_inhabited_ty(inner), + ty::Closure(_def, args) => { + let args = args.as_closure(); + args.upvar_tys().iter().all(|ty| self.is_inhabited_ty(ty)) + } + ty::Coroutine(_def, args) => { + let args = args.as_coroutine(); + args.upvar_tys().iter().all(|ty| self.is_inhabited_ty(ty)) + } + ty::CoroutineClosure(_def, args) => { + let args = args.as_coroutine_closure(); + args.upvar_tys().iter().all(|ty| self.is_inhabited_ty(ty)) + } + ty::UnsafeBinder(base) => { + let base = tcx.instantiate_bound_regions_with_erased((*base).into()); + self.is_inhabited_ty(base) + } + ty::Adt(..) => self.is_inhabited_adt_ty(ty), + + ty::Error(_error_guaranteed) => { + // We have a token proving there was an error, so we can return a dummy value. + true + } + + ty::Infer(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Param(..) + | ty::Alias(..) + | ty::CoroutineWitness(..) => { + bug!("non-normalized type in `is_opsem_uninhabited`: `{ty}`") } - is_opsem_inhabited_recursor(pointee, tcx, seen, stop_at_ref, adt_handler) - } - ty::Tuple(tys) => tys - .iter() - .all(|ty| is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler)), - ty::Array(elem, len) => { - len.try_to_target_usize(tcx).unwrap() == 0 - || is_opsem_inhabited_recursor(elem, tcx, seen, stop_at_ref, adt_handler) - } - ty::Pat(inner, _pat) => { - is_opsem_inhabited_recursor(inner, tcx, seen, stop_at_ref, adt_handler) - } - ty::Closure(_def, args) => { - let args = args.as_closure(); - args.upvar_tys() - .iter() - .all(|ty| is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler)) - } - ty::Coroutine(_def, args) => { - let args = args.as_coroutine(); - args.upvar_tys() - .iter() - .all(|ty| is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler)) - } - ty::CoroutineClosure(_def, args) => { - let args = args.as_coroutine_closure(); - args.upvar_tys() - .iter() - .all(|ty| is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler)) } - ty::UnsafeBinder(base) => { - let base = tcx.instantiate_bound_regions_with_erased((*base).into()); - is_opsem_inhabited_recursor(base, tcx, seen, stop_at_ref, adt_handler) + } + + fn is_inhabited_adt_ty(&mut self, ty: Ty<'tcx>) -> bool { + let ty::Adt(adt_def, adt_args) = *ty.kind() else { + unreachable! {} + }; + let Self { tcx, typing_env, .. } = *self; + + if adt_def.is_union() { + // Unions are always inhabited. + return true; } - ty::Adt(..) => { - // ADTs need a special handler to avoid infinite recursion. That handler is meant to - // call back into the recursor. Ideally it'd just call `is_opsem_inhabited_recursor` but - // then it would have to pass itself as the adt_handler argument which is not possible - // in Rust... so we provide the handler with a callback that it can use to continue the - // recursion with the same `adt_handler`. - adt_handler(ty, seen, &|ty, seen, stop_at_ref| { - is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler) + + let Some(seen) = self.seen.as_mut() else { + // stop recursing, invoke the query. + return tcx.is_opsem_inhabited_raw(typing_env.as_query_input(ty)); + }; + + let new_adt = seen.insert(adt_def.did()); + // If we have seen this ADT before, stop at the next reference to avoid infinite + // recursion. We can't stop here since we have to ensure that "layout uninhabited" + // implies "opsem uninhabited". References are always layout-inhabited so the + // implication is vacuously true. + let stop_at_ref_prev = self.stop_at_ref; + self.stop_at_ref |= !new_adt; + + // We are inhabited if in some variant all fields are inhabited. + let inhabited = adt_def.variants().iter().any(|variant| { + variant.fields.iter().all(|field| { + let ty = field.ty(tcx, adt_args); + let ty = tcx.normalize_erasing_regions(typing_env, ty); + self.is_inhabited_ty(ty) }) - } + }); - ty::Error(_error_guaranteed) => { - // We have a token proving there was an error, so we can return a dummy value. - true + self.stop_at_ref = stop_at_ref_prev; + // Remove the type again so that we allow it to appear on other branches. + if new_adt { + self.seen.as_mut().unwrap().remove(&adt_def.did()); } - ty::Infer(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Param(..) - | ty::Alias(..) - | ty::CoroutineWitness(..) => { - bug!("non-normalized type in `is_opsem_uninhabited`: `{ty}`") - } + inhabited } } @@ -366,42 +383,6 @@ fn is_opsem_inhabited_raw<'tcx>( "the query should only be invoked by `Ty::is_opsem_inhabited`" ); - is_opsem_inhabited_recursor( - ty, - tcx, - &mut FxHashSet::::default(), - /* stop_at_ref */ false, - &|ty, seen, rec| { - let ty::Adt(adt_def, adt_args) = *ty.kind() else { - unreachable! {} - }; - if adt_def.is_union() { - // Unions are always inhabited. - return true; - } - - let new_adt = seen.insert(adt_def.did()); - // If we have seen this ADT before, stop at the next reference to avoid infinite - // recursion. We can't stop here since we have to ensure that "layout uninhabited" - // implies "opsem uninhabited". References are always layout-inhabited so the - // implication is vacuously true. - let stop_at_ref = !new_adt; - - // We are inhabited if in some variant all fields are inhabited. - let inhabited = adt_def.variants().iter().any(|variant| { - variant.fields.iter().all(|field| { - let ty = field.ty(tcx, adt_args); - let ty = tcx.normalize_erasing_regions(typing_env, ty); - rec(ty, seen, stop_at_ref) - }) - }); - - // Remove the type again so that we allow it to appear on other branches. - if new_adt { - seen.remove(&adt_def.did()); - } - - inhabited - }, - ) + OpsemInhabitedCtx { tcx, typing_env, seen: Some(FxHashSet::default()), stop_at_ref: false } + .is_inhabited_adt_ty(ty) }