@@ -1709,6 +1709,10 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
17091709 "`repr(C)` types" ,
17101710 "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets." ,
17111711 ) ,
1712+ UnsuitedReason :: Array => (
1713+ "array types with non-trivial element types" ,
1714+ "is an array with a non-trivial element type, so it is not guaranteed to have a trivial ABI in all situations." ,
1715+ ) ,
17121716 } ;
17131717 Diag :: new (
17141718 dcx,
@@ -1785,19 +1789,43 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
17851789 NonExhaustive ,
17861790 PrivateField ,
17871791 ReprC ,
1792+ Array ,
17881793 }
17891794
17901795 fn check_unsuited < ' tcx > (
17911796 tcx : TyCtxt < ' tcx > ,
17921797 typing_env : ty:: TypingEnv < ' tcx > ,
17931798 ty : Ty < ' tcx > ,
1799+ inside_repr_rust_packed_1 : bool ,
17941800 ) -> ControlFlow < UnsuitedInfo < ' tcx > > {
17951801 // We can encounter projections during traversal, so ensure the type is normalized.
17961802 let ty =
17971803 tcx. try_normalize_erasing_regions ( typing_env, Unnormalized :: new_wip ( ty) ) . unwrap_or ( ty) ;
17981804 match ty. kind ( ) {
1799- ty:: Tuple ( list) => list. iter ( ) . try_for_each ( |t| check_unsuited ( tcx, typing_env, t) ) ,
1800- ty:: Array ( ty, _) => check_unsuited ( tcx, typing_env, * ty) ,
1805+ ty:: Tuple ( list) => list
1806+ . iter ( )
1807+ . try_for_each ( |t| check_unsuited ( tcx, typing_env, t, inside_repr_rust_packed_1) ) ,
1808+ ty:: Array ( elem_ty, len) => {
1809+ // If we are inside a `#[repr(Rust, packed(1))]` ADT,
1810+ // the alignment is guaranteed to be 1 and Rust has full control over the ABI.
1811+ // Therefore, we can allow any length-0 array.
1812+ // This special case is needed to support the `ghost` crate.
1813+ if inside_repr_rust_packed_1
1814+ && let ty:: ConstKind :: Value ( v) = len. kind ( )
1815+ && v. try_to_target_usize ( tcx) == Some ( 0 )
1816+ {
1817+ return ControlFlow :: Continue ( ( ) ) ;
1818+ }
1819+
1820+ let elem_layout = tcx. layout_of ( typing_env. as_query_input ( * elem_ty) ) ;
1821+ let elem_trivial = elem_layout. is_ok_and ( |layout| layout. is_1zst ( ) ) ;
1822+
1823+ if elem_trivial {
1824+ check_unsuited ( tcx, typing_env, * elem_ty, inside_repr_rust_packed_1)
1825+ } else {
1826+ ControlFlow :: Break ( UnsuitedInfo { ty, reason : UnsuitedReason :: Array } )
1827+ }
1828+ }
18011829 ty:: Adt ( def, args) => {
18021830 if !def. did ( ) . is_local ( ) && !find_attr ! ( tcx, def. did( ) , RustcPubTransparent ( _) ) {
18031831 let non_exhaustive = def. is_variant_list_non_exhaustive ( )
@@ -1814,12 +1842,22 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
18141842 } ) ;
18151843 }
18161844 }
1817- if def. repr ( ) . c ( ) {
1845+
1846+ let repr = def. repr ( ) ;
1847+
1848+ if repr. c ( ) {
18181849 return ControlFlow :: Break ( UnsuitedInfo { ty, reason : UnsuitedReason :: ReprC } ) ;
18191850 }
1820- def. all_fields ( )
1821- . map ( |field| field. ty ( tcx, args) )
1822- . try_for_each ( |t| check_unsuited ( tcx, typing_env, t) )
1851+
1852+ def. all_fields ( ) . map ( |field| field. ty ( tcx, args) ) . try_for_each ( |t| {
1853+ check_unsuited (
1854+ tcx,
1855+ typing_env,
1856+ t,
1857+ inside_repr_rust_packed_1
1858+ || def. repr ( ) . pack . is_some_and ( |a| a. bytes ( ) == 1 ) ,
1859+ )
1860+ } )
18231861 }
18241862 _ => ControlFlow :: Continue ( ( ) ) ,
18251863 }
@@ -1828,11 +1866,22 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
18281866 let mut prev_unsuited_1zst = false ;
18291867 for field in field_infos {
18301868 if field. trivial
1831- && let Some ( unsuited) = check_unsuited ( tcx, typing_env, field. ty ) . break_value ( )
1869+ && let Some ( unsuited) = check_unsuited ( tcx, typing_env, field. ty , false ) . break_value ( )
18321870 {
18331871 // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
18341872 // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
18351873 if non_trivial_count > 0 || prev_unsuited_1zst {
1874+ if matches ! ( unsuited. reason, UnsuitedReason :: Array ) {
1875+ #[ derive( Diagnostic ) ]
1876+ #[ diag( "😱 Crater REGRESSION 😱" ) ]
1877+ struct CraterFail {
1878+ #[ primary_span]
1879+ span : Span ,
1880+ }
1881+
1882+ tcx. dcx ( ) . emit_err ( CraterFail { span : field. span } ) ;
1883+ }
1884+
18361885 tcx. emit_node_span_lint (
18371886 REPR_TRANSPARENT_NON_ZST_FIELDS ,
18381887 tcx. local_def_id_to_hir_id ( adt. did ( ) . expect_local ( ) ) ,
0 commit comments