From fc5abd61e840899d719a4b7cc70bc4df1b1565ef Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 29 Apr 2026 22:58:34 -0400 Subject: [PATCH 1/3] `repr(transparent)`: don't consider most length-0 arrays trivial MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this PR, an array type is considered trivial for the purpose of `repr(transparent)` only if its element type is—we emit the `repr_transparent_non_zst_fields` FCW otherwise. This has two benefits: ## Forbid non-portable definitions Some types have alignment 1 only on certain platforms. Prior to this PR, the following snippet would compile on AVR, and *only* on AVR: ```rust #[repr(transparent)] struct Foo(i32, [u16; 0]); ``` After this PR, the above now fails to compile on any target. ## FFI and CFI compatibility We want to add support for Control Flow Integrity to Rust at some point. There are some good reasons to want CFI to consider `*const [u8; 0]` and `*const [u8; 1]` compatible with one another. But that means we must consider `*const [u8; 0]` and `*const ()` to be CFI-incompatible. Declaring `[u8; 0]` non-trivial for `repr(transparent)` makes that easier to achieve. See discussion on Zulip: --- .../rustc_hir_analysis/src/check/check.rs | 15 +- .../tests/pass/function_calls/abi_compat.rs | 4 +- tests/codegen-llvm/repr/transparent.rs | 2 +- tests/ui/abi/compatibility.rs | 15 +- .../ui/layout/homogeneous-aggr-transparent.rs | 2 +- tests/ui/repr/repr-transparent-array.rs | 41 ++++++ tests/ui/repr/repr-transparent-array.stderr | 137 ++++++++++++++++++ 7 files changed, 205 insertions(+), 11 deletions(-) create mode 100644 tests/ui/repr/repr-transparent-array.rs create mode 100644 tests/ui/repr/repr-transparent-array.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 26c87f14cd737..7e9b92676fbd3 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1709,6 +1709,10 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) "`repr(C)` types", "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.", ), + UnsuitedReason::Array => ( + "array types with non-trivial element types", + "is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations.", + ), }; Diag::new( dcx, @@ -1785,6 +1789,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) NonExhaustive, PrivateField, ReprC, + Array, } fn check_unsuited<'tcx>( @@ -1797,7 +1802,15 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)).unwrap_or(ty); match ty.kind() { ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)), - ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty), + ty::Array(elem_ty, _) => { + let elem_layout = tcx.layout_of(typing_env.as_query_input(*elem_ty)); + let elem_trivial = elem_layout.is_ok_and(|layout| layout.is_1zst()); + if elem_trivial { + check_unsuited(tcx, typing_env, *elem_ty) + } else { + return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::Array }); + } + } ty::Adt(def, args) => { if !def.did().is_local() && !find_attr!(tcx, def.did(), RustcPubTransparent(_)) { let non_exhaustive = def.is_variant_list_non_exhaustive() diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index cd48bd2accb27..5bedc220ab210 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -62,13 +62,13 @@ fn test_abi_newtype() { struct Wrapper2a((), T); #[repr(transparent)] #[derive(Copy, Clone)] - struct Wrapper3(Zst, T, [u8; 0]); + struct Wrapper3(Zst, T, [(); 42]); let t = T::default(); test_abi_compat(t, Wrapper(t)); test_abi_compat(t, Wrapper2(t, ())); test_abi_compat(t, Wrapper2a((), t)); - test_abi_compat(t, Wrapper3(Zst, t, [])); + test_abi_compat(t, Wrapper3(Zst, t, [(); 42])); test_abi_compat(t, mem::MaybeUninit::new(t)); // MaybeUninit is `repr(transparent)` } diff --git a/tests/codegen-llvm/repr/transparent.rs b/tests/codegen-llvm/repr/transparent.rs index 29b627462a4d9..36da81d8ae1ba 100644 --- a/tests/codegen-llvm/repr/transparent.rs +++ b/tests/codegen-llvm/repr/transparent.rs @@ -47,7 +47,7 @@ pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { } #[repr(transparent)] -pub struct WithZeroSizedArray(*const f32, [i8; 0]); +pub struct WithZeroSizedArray(*const f32, [(); 42]); // CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1) #[no_mangle] diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 6071ad9bb435b..a537d333d126a 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -145,11 +145,13 @@ macro_rules! test_abi_compatible { use super::*; // Declaring a `type` doesn't even check well-formedness, so we also declare a function. fn check_wf(_x: $t1, _y: $t2) {} - // Test argument and return value, `Rust` and `C` ABIs. + // Test argument and return value in various ABIs. #[rustc_abi(assert_eq)] type TestRust = (fn($t1) -> $t1, fn($t2) -> $t2); #[rustc_abi(assert_eq)] type TestC = (extern "C" fn($t1) -> $t1, extern "C" fn($t2) -> $t2); + #[rustc_abi(assert_eq)] + type TestSystem = (extern "system" fn($t1) -> $t1, extern "system" fn($t2) -> $t2); } }; } @@ -200,7 +202,8 @@ test_abi_compatible!(isize_int, isize, i64); // Compatibility of 1-ZST. test_abi_compatible!(zst_unit, Zst, ()); -test_abi_compatible!(zst_array, Zst, [u8; 0]); +test_abi_compatible!(zst_array, Zst, [(); 0]); +test_abi_compatible!(zst_array_2, Zst, [(); 42]); test_abi_compatible!(nonzero_int, NonZero, i32); // `#[repr(C)]` enums should not change ABI based on individual variant inhabitedness. @@ -220,7 +223,7 @@ struct TransparentWrapper1(T); #[repr(transparent)] struct TransparentWrapper2((), Zst, T); #[repr(transparent)] -struct TransparentWrapper3(T, [u8; 0], PhantomData); +struct TransparentWrapper3(T, [Zst; 42], PhantomData); #[repr(transparent)] union TransparentWrapperUnion { nothing: (), @@ -299,14 +302,14 @@ macro_rules! test_nonnull { test_abi_compatible!(result_ok_unit, Result<(), $t>, $t); test_abi_compatible!(result_err_zst, Result<$t, Zst>, $t); test_abi_compatible!(result_ok_zst, Result, $t); - test_abi_compatible!(result_err_arr, Result<$t, [i8; 0]>, $t); - test_abi_compatible!(result_ok_arr, Result<[i8; 0], $t>, $t); + test_abi_compatible!(result_err_arr, Result<$t, [(); 42]>, $t); + test_abi_compatible!(result_ok_arr, Result<[(); 42], $t>, $t); test_abi_compatible!(result_err_void, Result<$t, Void>, $t); test_abi_compatible!(result_ok_void, Result, $t); test_abi_compatible!(either_err_zst, Either<$t, Zst>, $t); test_abi_compatible!(either_ok_zst, Either, $t); test_abi_compatible!(either2_err_zst, Either2<$t, Zst>, $t); - test_abi_compatible!(either2_err_arr, Either2<$t, [i8; 0]>, $t); + test_abi_compatible!(either2_err_arr, Either2<$t, [(); 42]>, $t); } } } diff --git a/tests/ui/layout/homogeneous-aggr-transparent.rs b/tests/ui/layout/homogeneous-aggr-transparent.rs index d968d609835f7..2c8c93cdd7c3e 100644 --- a/tests/ui/layout/homogeneous-aggr-transparent.rs +++ b/tests/ui/layout/homogeneous-aggr-transparent.rs @@ -14,7 +14,7 @@ struct Wrapper1(T); #[repr(transparent)] struct Wrapper2((), Zst, T); #[repr(transparent)] -struct Wrapper3(T, [u8; 0], PhantomData); +struct Wrapper3(T, [Zst; 42], PhantomData); #[repr(transparent)] union WrapperUnion { nothing: (), diff --git a/tests/ui/repr/repr-transparent-array.rs b/tests/ui/repr/repr-transparent-array.rs new file mode 100644 index 0000000000000..c724678500684 --- /dev/null +++ b/tests/ui/repr/repr-transparent-array.rs @@ -0,0 +1,41 @@ +#![deny(repr_transparent_non_zst_fields)] + +type SusArray = [u8; 0]; + +type GoodArray = [[(); 0]; 42]; + +pub type Sized = i32; + +#[repr(transparent)] +pub struct T1(SusArray); +#[repr(transparent)] +pub struct T2(GoodArray, SusArray); +#[repr(transparent)] +pub struct T3(SusArray, GoodArray); + +#[repr(transparent)] +pub struct T5(Sized, SusArray); +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T6(SusArray, Sized); +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T8(SusArray, SusArray); // still wrong +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T9([[u8; 0]; 0], SusArray); // still wrong +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/tests/ui/repr/repr-transparent-array.stderr b/tests/ui/repr/repr-transparent-array.stderr new file mode 100644 index 0000000000000..fd45f89360ef6 --- /dev/null +++ b/tests/ui/repr/repr-transparent-array.stderr @@ -0,0 +1,137 @@ +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:17:22 + | +LL | pub struct T5(Sized, SusArray); + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 +note: the lint level is defined here + --> $DIR/repr-transparent-array.rs:1:9 + | +LL | #![deny(repr_transparent_non_zst_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:22:15 + | +LL | pub struct T6(SusArray, Sized); + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:27:19 + | +LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:32:25 + | +LL | pub struct T8(SusArray, SusArray); // still wrong + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:37:29 + | +LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + +error: aborting due to 5 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:17:22 + | +LL | pub struct T5(Sized, SusArray); + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 +note: the lint level is defined here + --> $DIR/repr-transparent-array.rs:1:9 + | +LL | #![deny(repr_transparent_non_zst_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:22:15 + | +LL | pub struct T6(SusArray, Sized); + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 +note: the lint level is defined here + --> $DIR/repr-transparent-array.rs:1:9 + | +LL | #![deny(repr_transparent_non_zst_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:27:19 + | +LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 +note: the lint level is defined here + --> $DIR/repr-transparent-array.rs:1:9 + | +LL | #![deny(repr_transparent_non_zst_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:32:25 + | +LL | pub struct T8(SusArray, SusArray); // still wrong + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 +note: the lint level is defined here + --> $DIR/repr-transparent-array.rs:1:9 + | +LL | #![deny(repr_transparent_non_zst_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:37:29 + | +LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong + | ^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 +note: the lint level is defined here + --> $DIR/repr-transparent-array.rs:1:9 + | +LL | #![deny(repr_transparent_non_zst_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + From 2af89b038c40bbc58c8d9c3e804d3a0b6480ff85 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Thu, 30 Apr 2026 20:34:49 -0400 Subject: [PATCH 2/3] Allow length-0 arrays inside `#[repr(Rust, packed(1))]` Needed to support the `ghost` crate. --- .../rustc_hir_analysis/src/check/check.rs | 43 ++++++++--- tests/ui/repr/repr-transparent-array.rs | 21 ++++++ tests/ui/repr/repr-transparent-array.stderr | 74 ++++++++++++++++--- 3 files changed, 118 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 7e9b92676fbd3..e609c4bcb749f 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1796,19 +1796,34 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, + inside_repr_rust_packed_1: bool, ) -> ControlFlow> { // We can encounter projections during traversal, so ensure the type is normalized. let ty = tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)).unwrap_or(ty); match ty.kind() { - ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)), - ty::Array(elem_ty, _) => { + ty::Tuple(list) => list + .iter() + .try_for_each(|t| check_unsuited(tcx, typing_env, t, inside_repr_rust_packed_1)), + ty::Array(elem_ty, len) => { + // If we are inside a `#[repr(Rust, packed(1))]` ADT, + // the alignment is guaranteed to be 1 and Rust has full control over the ABI. + // Therefore, we can allow any length-0 array. + // This special case is needed to support the `ghost` crate. + if inside_repr_rust_packed_1 + && let ty::ConstKind::Value(v) = len.kind() + && v.try_to_target_usize(tcx) == Some(0) + { + return ControlFlow::Continue(()); + } + let elem_layout = tcx.layout_of(typing_env.as_query_input(*elem_ty)); let elem_trivial = elem_layout.is_ok_and(|layout| layout.is_1zst()); + if elem_trivial { - check_unsuited(tcx, typing_env, *elem_ty) + check_unsuited(tcx, typing_env, *elem_ty, inside_repr_rust_packed_1) } else { - return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::Array }); + ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::Array }) } } ty::Adt(def, args) => { @@ -1827,12 +1842,22 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) }); } } - if def.repr().c() { + + let repr = def.repr(); + + if repr.c() { return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC }); } - def.all_fields() - .map(|field| field.ty(tcx, args)) - .try_for_each(|t| check_unsuited(tcx, typing_env, t)) + + def.all_fields().map(|field| field.ty(tcx, args)).try_for_each(|t| { + check_unsuited( + tcx, + typing_env, + t, + inside_repr_rust_packed_1 + || def.repr().pack.is_some_and(|a| a.bytes() == 1), + ) + }) } _ => ControlFlow::Continue(()), } @@ -1841,7 +1866,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) let mut prev_unsuited_1zst = false; for field in field_infos { if field.trivial - && let Some(unsuited) = check_unsuited(tcx, typing_env, field.ty).break_value() + && let Some(unsuited) = check_unsuited(tcx, typing_env, field.ty, false).break_value() { // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. diff --git a/tests/ui/repr/repr-transparent-array.rs b/tests/ui/repr/repr-transparent-array.rs index c724678500684..7919d66d2557f 100644 --- a/tests/ui/repr/repr-transparent-array.rs +++ b/tests/ui/repr/repr-transparent-array.rs @@ -6,12 +6,23 @@ type GoodArray = [[(); 0]; 42]; pub type Sized = i32; +#[repr(Rust, packed(1))] +pub struct RustPacked1Arr([*const T; 0]); + +#[repr(C, packed(1))] +pub struct CPacked1Arr([*const T; 0]); + +#[repr(Rust, packed(2))] +pub struct RustPacked2Arr([u8; 0]); + #[repr(transparent)] pub struct T1(SusArray); #[repr(transparent)] pub struct T2(GoodArray, SusArray); #[repr(transparent)] pub struct T3(SusArray, GoodArray); +#[repr(transparent)] +pub struct T4(Sized, RustPacked1Arr); #[repr(transparent)] pub struct T5(Sized, SusArray); @@ -38,4 +49,14 @@ pub struct T9([[u8; 0]; 0], SusArray); // still wrong //~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types //~| WARN this was previously accepted by the compiler +#[repr(transparent)] +pub struct T10(Sized, CPacked1Arr); +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T11(Sized, RustPacked2Arr); +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types +//~| WARN this was previously accepted by the compiler + fn main() {} diff --git a/tests/ui/repr/repr-transparent-array.stderr b/tests/ui/repr/repr-transparent-array.stderr index fd45f89360ef6..dddfc6ca8b04c 100644 --- a/tests/ui/repr/repr-transparent-array.stderr +++ b/tests/ui/repr/repr-transparent-array.stderr @@ -1,5 +1,5 @@ error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:17:22 + --> $DIR/repr-transparent-array.rs:28:22 | LL | pub struct T5(Sized, SusArray); | ^^^^^^^^ @@ -14,7 +14,7 @@ LL | #![deny(repr_transparent_non_zst_fields)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:22:15 + --> $DIR/repr-transparent-array.rs:33:15 | LL | pub struct T6(SusArray, Sized); | ^^^^^^^^ @@ -24,7 +24,7 @@ LL | pub struct T6(SusArray, Sized); = note: for more information, see issue #78586 error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:27:19 + --> $DIR/repr-transparent-array.rs:38:19 | LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type | ^^^^^^^^ @@ -34,7 +34,7 @@ LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden = note: for more information, see issue #78586 error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:32:25 + --> $DIR/repr-transparent-array.rs:43:25 | LL | pub struct T8(SusArray, SusArray); // still wrong | ^^^^^^^^ @@ -44,7 +44,7 @@ LL | pub struct T8(SusArray, SusArray); // still wrong = note: for more information, see issue #78586 error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:37:29 + --> $DIR/repr-transparent-array.rs:48:29 | LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong | ^^^^^^^^ @@ -53,11 +53,31 @@ LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 -error: aborting due to 5 previous errors +error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types + --> $DIR/repr-transparent-array.rs:53:23 + | +LL | pub struct T10(Sized, CPacked1Arr); + | ^^^^^^^^^^^^^^^^^ + | + = note: this field contains `CPacked1Arr`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:58:23 + | +LL | pub struct T11(Sized, RustPacked2Arr); + | ^^^^^^^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + +error: aborting due to 7 previous errors Future incompatibility report: Future breakage diagnostic: error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:17:22 + --> $DIR/repr-transparent-array.rs:28:22 | LL | pub struct T5(Sized, SusArray); | ^^^^^^^^ @@ -73,7 +93,7 @@ LL | #![deny(repr_transparent_non_zst_fields)] Future breakage diagnostic: error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:22:15 + --> $DIR/repr-transparent-array.rs:33:15 | LL | pub struct T6(SusArray, Sized); | ^^^^^^^^ @@ -89,7 +109,7 @@ LL | #![deny(repr_transparent_non_zst_fields)] Future breakage diagnostic: error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:27:19 + --> $DIR/repr-transparent-array.rs:38:19 | LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type | ^^^^^^^^ @@ -105,7 +125,7 @@ LL | #![deny(repr_transparent_non_zst_fields)] Future breakage diagnostic: error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:32:25 + --> $DIR/repr-transparent-array.rs:43:25 | LL | pub struct T8(SusArray, SusArray); // still wrong | ^^^^^^^^ @@ -121,7 +141,7 @@ LL | #![deny(repr_transparent_non_zst_fields)] Future breakage diagnostic: error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:37:29 + --> $DIR/repr-transparent-array.rs:48:29 | LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong | ^^^^^^^^ @@ -135,3 +155,35 @@ note: the lint level is defined here LL | #![deny(repr_transparent_non_zst_fields)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Future breakage diagnostic: +error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types + --> $DIR/repr-transparent-array.rs:53:23 + | +LL | pub struct T10(Sized, CPacked1Arr); + | ^^^^^^^^^^^^^^^^^ + | + = note: this field contains `CPacked1Arr`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 +note: the lint level is defined here + --> $DIR/repr-transparent-array.rs:1:9 + | +LL | #![deny(repr_transparent_non_zst_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types + --> $DIR/repr-transparent-array.rs:58:23 + | +LL | pub struct T11(Sized, RustPacked2Arr); + | ^^^^^^^^^^^^^^ + | + = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 +note: the lint level is defined here + --> $DIR/repr-transparent-array.rs:1:9 + | +LL | #![deny(repr_transparent_non_zst_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + From fe0c86e89ebeb74b3a14ada1f3905bc4fcaf30f2 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Thu, 30 Apr 2026 22:56:16 -0400 Subject: [PATCH 3/3] [DO NOT MERGE] Make it a hard error for crater --- .../rustc_hir_analysis/src/check/check.rs | 11 + tests/ui/repr/repr-transparent-array.rs | 62 ------ tests/ui/repr/repr-transparent-array.stderr | 189 ------------------ 3 files changed, 11 insertions(+), 251 deletions(-) delete mode 100644 tests/ui/repr/repr-transparent-array.rs delete mode 100644 tests/ui/repr/repr-transparent-array.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e609c4bcb749f..49ed3e92519e4 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1871,6 +1871,17 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. if non_trivial_count > 0 || prev_unsuited_1zst { + if matches!(unsuited.reason, UnsuitedReason::Array) { + #[derive(Diagnostic)] + #[diag("😱 Crater REGRESSION 😱")] + struct CraterFail { + #[primary_span] + span: Span, + } + + tcx.dcx().emit_err(CraterFail { span: field.span }); + } + tcx.emit_node_span_lint( REPR_TRANSPARENT_NON_ZST_FIELDS, tcx.local_def_id_to_hir_id(adt.did().expect_local()), diff --git a/tests/ui/repr/repr-transparent-array.rs b/tests/ui/repr/repr-transparent-array.rs deleted file mode 100644 index 7919d66d2557f..0000000000000 --- a/tests/ui/repr/repr-transparent-array.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![deny(repr_transparent_non_zst_fields)] - -type SusArray = [u8; 0]; - -type GoodArray = [[(); 0]; 42]; - -pub type Sized = i32; - -#[repr(Rust, packed(1))] -pub struct RustPacked1Arr([*const T; 0]); - -#[repr(C, packed(1))] -pub struct CPacked1Arr([*const T; 0]); - -#[repr(Rust, packed(2))] -pub struct RustPacked2Arr([u8; 0]); - -#[repr(transparent)] -pub struct T1(SusArray); -#[repr(transparent)] -pub struct T2(GoodArray, SusArray); -#[repr(transparent)] -pub struct T3(SusArray, GoodArray); -#[repr(transparent)] -pub struct T4(Sized, RustPacked1Arr); - -#[repr(transparent)] -pub struct T5(Sized, SusArray); -//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types -//~| WARN this was previously accepted by the compiler - -#[repr(transparent)] -pub struct T6(SusArray, Sized); -//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types -//~| WARN this was previously accepted by the compiler - -#[repr(transparent)] -pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type -//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types -//~| WARN this was previously accepted by the compiler - -#[repr(transparent)] -pub struct T8(SusArray, SusArray); // still wrong -//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types -//~| WARN this was previously accepted by the compiler - -#[repr(transparent)] -pub struct T9([[u8; 0]; 0], SusArray); // still wrong -//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types -//~| WARN this was previously accepted by the compiler - -#[repr(transparent)] -pub struct T10(Sized, CPacked1Arr); -//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types -//~| WARN this was previously accepted by the compiler - -#[repr(transparent)] -pub struct T11(Sized, RustPacked2Arr); -//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types -//~| WARN this was previously accepted by the compiler - -fn main() {} diff --git a/tests/ui/repr/repr-transparent-array.stderr b/tests/ui/repr/repr-transparent-array.stderr deleted file mode 100644 index dddfc6ca8b04c..0000000000000 --- a/tests/ui/repr/repr-transparent-array.stderr +++ /dev/null @@ -1,189 +0,0 @@ -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:28:22 - | -LL | pub struct T5(Sized, SusArray); - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 -note: the lint level is defined here - --> $DIR/repr-transparent-array.rs:1:9 - | -LL | #![deny(repr_transparent_non_zst_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:33:15 - | -LL | pub struct T6(SusArray, Sized); - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 - -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:38:19 - | -LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 - -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:43:25 - | -LL | pub struct T8(SusArray, SusArray); // still wrong - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 - -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:48:29 - | -LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 - -error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types - --> $DIR/repr-transparent-array.rs:53:23 - | -LL | pub struct T10(Sized, CPacked1Arr); - | ^^^^^^^^^^^^^^^^^ - | - = note: this field contains `CPacked1Arr`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 - -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:58:23 - | -LL | pub struct T11(Sized, RustPacked2Arr); - | ^^^^^^^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 - -error: aborting due to 7 previous errors - -Future incompatibility report: Future breakage diagnostic: -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:28:22 - | -LL | pub struct T5(Sized, SusArray); - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 -note: the lint level is defined here - --> $DIR/repr-transparent-array.rs:1:9 - | -LL | #![deny(repr_transparent_non_zst_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:33:15 - | -LL | pub struct T6(SusArray, Sized); - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 -note: the lint level is defined here - --> $DIR/repr-transparent-array.rs:1:9 - | -LL | #![deny(repr_transparent_non_zst_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:38:19 - | -LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 -note: the lint level is defined here - --> $DIR/repr-transparent-array.rs:1:9 - | -LL | #![deny(repr_transparent_non_zst_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:43:25 - | -LL | pub struct T8(SusArray, SusArray); // still wrong - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 -note: the lint level is defined here - --> $DIR/repr-transparent-array.rs:1:9 - | -LL | #![deny(repr_transparent_non_zst_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:48:29 - | -LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong - | ^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 -note: the lint level is defined here - --> $DIR/repr-transparent-array.rs:1:9 - | -LL | #![deny(repr_transparent_non_zst_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types - --> $DIR/repr-transparent-array.rs:53:23 - | -LL | pub struct T10(Sized, CPacked1Arr); - | ^^^^^^^^^^^^^^^^^ - | - = note: this field contains `CPacked1Arr`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 -note: the lint level is defined here - --> $DIR/repr-transparent-array.rs:1:9 - | -LL | #![deny(repr_transparent_non_zst_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types - --> $DIR/repr-transparent-array.rs:58:23 - | -LL | pub struct T11(Sized, RustPacked2Arr); - | ^^^^^^^^^^^^^^ - | - = note: this field contains `[u8; 0]`, which is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations. - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #78586 -note: the lint level is defined here - --> $DIR/repr-transparent-array.rs:1:9 - | -LL | #![deny(repr_transparent_non_zst_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -