From 3b3ba8b5e45eddb8456d3ab3eb82d0d41e32ea77 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Aug 2026 09:33:14 +0200 Subject: [PATCH 1/2] peel_transparent_wrappers only works on non-1ZST --- compiler/rustc_abi/src/layout/ty.rs | 19 +++++++++++++++---- compiler/rustc_codegen_llvm/src/va_arg.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/place.rs | 6 ++++-- .../rustc_codegen_ssa/src/traits/builder.rs | 13 +++++++------ .../src/hir_ty_lowering/cmse.rs | 2 +- compiler/rustc_target/src/callconv/s390x.rs | 3 ++- compiler/rustc_target/src/callconv/wasm.rs | 7 +++++-- compiler/rustc_target/src/callconv/x86.rs | 3 ++- 8 files changed, 38 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index b8928aecf0cc5..0bc8f7e13ee2c 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -247,15 +247,25 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { where Ty: TyAbiInterface<'a, C> + Copy, { - let base = self.peel_transparent_wrappers(cx); + // FIXME: Peeling the wrappers above would not work correctly if we are a 1-ZST. So we make + // `#[rustc_pass_indirectly_in_non_rustic_abis]` a NOP on 1-ZST. In the future, + // `non_1zst_field` should become `non_trivial_abi_field` and + // `#[rustc_pass_indirectly_in_non_rustic_abis]` should make a type have non-trivial ABI. + if self.is_1zst() { + return false; + } + + let base = self.peel_transparent_wrappers_from_non_1zst(cx); Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base) } /// Recursively peel away transparent wrappers, returning the inner value. + /// Will not peel anything if `self` is a 1-ZST! Callers need to either check + /// that the result is not a 1-ZST, or have separate logic for that. /// /// The return value is not `repr(transparent)` and/or does /// not have a non-1zst field. - pub fn peel_transparent_wrappers(mut self, cx: &C) -> Self + pub fn peel_transparent_wrappers_from_non_1zst(mut self, cx: &C) -> Self where Ty: TyAbiInterface<'a, C> + Copy, { @@ -321,12 +331,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { where Ty: TyAbiInterface<'a, C> + Copy, { - let complex = self.peel_transparent_wrappers(cx); + // We're checking for scalar repr below which excludes 1-ZST. + let complex = self.peel_transparent_wrappers_from_non_1zst(cx); if !Ty::is_complex_number_lang_item(complex, cx) { return None; } - let component = complex.field(cx, 0).peel_transparent_wrappers(cx); + let component = complex.field(cx, 0).peel_transparent_wrappers_from_non_1zst(cx); let BackendRepr::Scalar(scalar) = component.backend_repr else { return None; diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 2a02df05f26f5..c6bce87252d16 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -308,7 +308,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( let va_list_addr = list.immediate(); // Peel off any newtype wrappers. - let layout = layout.peel_transparent_wrappers(bx.cx); + let layout = layout.peel_transparent_wrappers_from_non_1zst(bx.cx); // Rust does not currently support any powerpc softfloat targets. let target = &bx.cx.tcx.sess.target; @@ -561,7 +561,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( // #[repr(C)] // struct Foo([Empty; 8], i32); // ``` - let layout = layout.peel_transparent_wrappers(bx.cx); + let layout = layout.peel_transparent_wrappers_from_non_1zst(bx.cx); // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed // in the registers. If not go to step 7. diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 02e125fd31717..486b13cafdccb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -112,7 +112,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, layout: TyAndLayout<'tcx>, ) -> Self { - if layout.peel_transparent_wrappers(bx).deref().is_scalable_vector() { + // Scalable vector are never 1-ZST. FIXME: is that correct? + if layout.peel_transparent_wrappers_from_non_1zst(bx).deref().is_scalable_vector() { Self::alloca_scalable(bx, layout) } else { Self::alloca_size(bx, layout.size, layout) @@ -159,7 +160,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout: TyAndLayout<'tcx>, ) -> Self { PlaceValue::new_sized( - bx.alloca_with_ty(layout.peel_transparent_wrappers(bx)), + // FIXME why is this peeling at all? And why is it redoing the work the caller just did? + bx.alloca_with_ty(layout.peel_transparent_wrappers_from_non_1zst(bx)), layout.align.abi, ) .with_type(layout) diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index b7b694922bcfa..afe3aec13d279 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -539,12 +539,13 @@ pub trait BuilderMethods<'a, 'tcx>: let tt = tt.add_indirection(); let fnc_tree = FncTree { args: vec![tt.clone(), tt], ret: TypeTree::new() }; let bytes = self.const_usize(layout.size.bytes()); - let bytes = if layout.peel_transparent_wrappers(self).ty.is_scalable_vector() { - let vscale = self.vscale(self.type_i64()); - self.mul(vscale, bytes) - } else { - bytes - }; + let bytes = + if layout.peel_transparent_wrappers_from_non_1zst(self).ty.is_scalable_vector() { + let vscale = self.vscale(self.type_i64()); + self.mul(vscale, bytes) + } else { + bytes + }; self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, Some(fnc_tree)); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 675e7e3c2a02a..530706b0653db 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -170,7 +170,7 @@ fn is_valid_cmse_output_layout<'tcx>(cx: LayoutCx<'tcx>, layout: TyAndLayout<'tc // Accept (transparently wrapped) scalar 64-bit primitives. matches!( - layout.peel_transparent_wrappers(&cx).ty.kind(), + layout.peel_transparent_wrappers_from_non_1zst(&cx).ty.kind(), ty::Int(ty::IntTy::I64) | ty::Uint(ty::UintTy::U64) | ty::Float(ty::FloatTy::F64) ) } diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index 0d29bc658b56d..146cfc3c6ee65 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -15,7 +15,8 @@ where // Contrary to X86, trailing padding is allowed on s390x. loop { - layout = layout.peel_transparent_wrappers(cx); + // We're only looking for scalar types that are non-ZST. + layout = layout.peel_transparent_wrappers_from_non_1zst(cx); return match layout.backend_repr { BackendRepr::Scalar(scalar) => match scalar.primitive() { diff --git a/compiler/rustc_target/src/callconv/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs index 3706caa6b6f44..237bc2960b17e 100644 --- a/compiler/rustc_target/src/callconv/wasm.rs +++ b/compiler/rustc_target/src/callconv/wasm.rs @@ -11,7 +11,8 @@ where C: HasDataLayout, { // The base case: a single scalar is a singleton scalar. - if !(layout.is_aggregate() || layout.peel_transparent_wrappers(cx).is_enum()) { + // We're only looking for scalar types that are non-ZST. + if !(layout.is_aggregate() || layout.peel_transparent_wrappers_from_non_1zst(cx).is_enum()) { let BackendRepr::Scalar(scalar) = layout.backend_repr else { return None; }; @@ -62,7 +63,9 @@ where { // An enum that is represented as an integer is not an aggregate to rust, but may still // need to be passed as one if its variants have any (even ZST) fields. - if !(val.layout.is_aggregate() || val.layout.peel_transparent_wrappers(cx).is_enum()) { + if !(val.layout.is_aggregate() + || val.layout.peel_transparent_wrappers_from_non_1zst(cx).is_enum()) + { return false; } diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 3476f41e3bc75..147d499d2c76b 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -15,7 +15,8 @@ where let outer_size = layout.layout.size(); loop { - layout = layout.peel_transparent_wrappers(cx); + // We're only looking for scalar types that are non-ZST. + layout = layout.peel_transparent_wrappers_from_non_1zst(cx); return match layout.backend_repr { BackendRepr::Scalar(scalar) => match scalar.primitive() { From 6e8947a4a5e790d360cc561167b1b84f0eaa288a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Sep 2026 16:14:36 +0200 Subject: [PATCH 2/2] leave a comment for some sve hacks --- compiler/rustc_codegen_ssa/src/mir/place.rs | 6 ++++-- compiler/rustc_codegen_ssa/src/traits/builder.rs | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 486b13cafdccb..1412f64ac2179 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -112,7 +112,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, layout: TyAndLayout<'tcx>, ) -> Self { - // Scalable vector are never 1-ZST. FIXME: is that correct? + // FIXME(rustc_scalable_vector/stdarch_aarch64_sve): Scalable vectors aren't actually sized, + // but we pretend they are. Here we have to hack around that. if layout.peel_transparent_wrappers_from_non_1zst(bx).deref().is_scalable_vector() { Self::alloca_scalable(bx, layout) } else { @@ -160,7 +161,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout: TyAndLayout<'tcx>, ) -> Self { PlaceValue::new_sized( - // FIXME why is this peeling at all? And why is it redoing the work the caller just did? + // FIXME why is this peeling at all? The LLVM type should be the same for the + // transparent wrapper and the inner type. bx.alloca_with_ty(layout.peel_transparent_wrappers_from_non_1zst(bx)), layout.align.abi, ) diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index afe3aec13d279..473a856b05efe 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -540,6 +540,8 @@ pub trait BuilderMethods<'a, 'tcx>: let fnc_tree = FncTree { args: vec![tt.clone(), tt], ret: TypeTree::new() }; let bytes = self.const_usize(layout.size.bytes()); let bytes = + // FIXME(rustc_scalable_vector/stdarch_aarch64_sve): Scalable vectors aren't + // actually sized, but we pretend they are. Here we have to hack around that. if layout.peel_transparent_wrappers_from_non_1zst(self).ty.is_scalable_vector() { let vscale = self.vscale(self.type_i64()); self.mul(vscale, bytes)