Skip to content

Commit 2af89b0

Browse files
Allow length-0 arrays inside #[repr(Rust, packed(1))]
Needed to support the `ghost` crate.
1 parent fc5abd6 commit 2af89b0

3 files changed

Lines changed: 118 additions & 20 deletions

File tree

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,19 +1796,34 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
17961796
tcx: TyCtxt<'tcx>,
17971797
typing_env: ty::TypingEnv<'tcx>,
17981798
ty: Ty<'tcx>,
1799+
inside_repr_rust_packed_1: bool,
17991800
) -> ControlFlow<UnsuitedInfo<'tcx>> {
18001801
// We can encounter projections during traversal, so ensure the type is normalized.
18011802
let ty =
18021803
tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)).unwrap_or(ty);
18031804
match ty.kind() {
1804-
ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),
1805-
ty::Array(elem_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+
18061820
let elem_layout = tcx.layout_of(typing_env.as_query_input(*elem_ty));
18071821
let elem_trivial = elem_layout.is_ok_and(|layout| layout.is_1zst());
1822+
18081823
if elem_trivial {
1809-
check_unsuited(tcx, typing_env, *elem_ty)
1824+
check_unsuited(tcx, typing_env, *elem_ty, inside_repr_rust_packed_1)
18101825
} else {
1811-
return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::Array });
1826+
ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::Array })
18121827
}
18131828
}
18141829
ty::Adt(def, args) => {
@@ -1827,12 +1842,22 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
18271842
});
18281843
}
18291844
}
1830-
if def.repr().c() {
1845+
1846+
let repr = def.repr();
1847+
1848+
if repr.c() {
18311849
return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC });
18321850
}
1833-
def.all_fields()
1834-
.map(|field| field.ty(tcx, args))
1835-
.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+
})
18361861
}
18371862
_ => ControlFlow::Continue(()),
18381863
}
@@ -1841,7 +1866,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
18411866
let mut prev_unsuited_1zst = false;
18421867
for field in field_infos {
18431868
if field.trivial
1844-
&& 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()
18451870
{
18461871
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
18471872
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.

tests/ui/repr/repr-transparent-array.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,23 @@ type GoodArray = [[(); 0]; 42];
66

77
pub type Sized = i32;
88

9+
#[repr(Rust, packed(1))]
10+
pub struct RustPacked1Arr<T>([*const T; 0]);
11+
12+
#[repr(C, packed(1))]
13+
pub struct CPacked1Arr<T>([*const T; 0]);
14+
15+
#[repr(Rust, packed(2))]
16+
pub struct RustPacked2Arr([u8; 0]);
17+
918
#[repr(transparent)]
1019
pub struct T1(SusArray);
1120
#[repr(transparent)]
1221
pub struct T2(GoodArray, SusArray);
1322
#[repr(transparent)]
1423
pub struct T3(SusArray, GoodArray);
24+
#[repr(transparent)]
25+
pub struct T4(Sized, RustPacked1Arr<u128>);
1526

1627
#[repr(transparent)]
1728
pub struct T5(Sized, SusArray);
@@ -38,4 +49,14 @@ pub struct T9([[u8; 0]; 0], SusArray); // still wrong
3849
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
3950
//~| WARN this was previously accepted by the compiler
4051

52+
#[repr(transparent)]
53+
pub struct T10(Sized, CPacked1Arr<u128>);
54+
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
55+
//~| WARN this was previously accepted by the compiler
56+
57+
#[repr(transparent)]
58+
pub struct T11(Sized, RustPacked2Arr);
59+
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
60+
//~| WARN this was previously accepted by the compiler
61+
4162
fn main() {}

tests/ui/repr/repr-transparent-array.stderr

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
2-
--> $DIR/repr-transparent-array.rs:17:22
2+
--> $DIR/repr-transparent-array.rs:28:22
33
|
44
LL | pub struct T5(Sized, SusArray);
55
| ^^^^^^^^
@@ -14,7 +14,7 @@ LL | #![deny(repr_transparent_non_zst_fields)]
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1515

1616
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
17-
--> $DIR/repr-transparent-array.rs:22:15
17+
--> $DIR/repr-transparent-array.rs:33:15
1818
|
1919
LL | pub struct T6(SusArray, Sized);
2020
| ^^^^^^^^
@@ -24,7 +24,7 @@ LL | pub struct T6(SusArray, Sized);
2424
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
2525

2626
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
27-
--> $DIR/repr-transparent-array.rs:27:19
27+
--> $DIR/repr-transparent-array.rs:38:19
2828
|
2929
LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type
3030
| ^^^^^^^^
@@ -34,7 +34,7 @@ LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden
3434
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
3535

3636
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
37-
--> $DIR/repr-transparent-array.rs:32:25
37+
--> $DIR/repr-transparent-array.rs:43:25
3838
|
3939
LL | pub struct T8(SusArray, SusArray); // still wrong
4040
| ^^^^^^^^
@@ -44,7 +44,7 @@ LL | pub struct T8(SusArray, SusArray); // still wrong
4444
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
4545

4646
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
47-
--> $DIR/repr-transparent-array.rs:37:29
47+
--> $DIR/repr-transparent-array.rs:48:29
4848
|
4949
LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong
5050
| ^^^^^^^^
@@ -53,11 +53,31 @@ LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong
5353
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
5454
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
5555

56-
error: aborting due to 5 previous errors
56+
error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
57+
--> $DIR/repr-transparent-array.rs:53:23
58+
|
59+
LL | pub struct T10(Sized, CPacked1Arr<u128>);
60+
| ^^^^^^^^^^^^^^^^^
61+
|
62+
= note: this field contains `CPacked1Arr<u128>`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
63+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
64+
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
65+
66+
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
67+
--> $DIR/repr-transparent-array.rs:58:23
68+
|
69+
LL | pub struct T11(Sized, RustPacked2Arr);
70+
| ^^^^^^^^^^^^^^
71+
|
72+
= 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.
73+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
74+
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
75+
76+
error: aborting due to 7 previous errors
5777

5878
Future incompatibility report: Future breakage diagnostic:
5979
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
60-
--> $DIR/repr-transparent-array.rs:17:22
80+
--> $DIR/repr-transparent-array.rs:28:22
6181
|
6282
LL | pub struct T5(Sized, SusArray);
6383
| ^^^^^^^^
@@ -73,7 +93,7 @@ LL | #![deny(repr_transparent_non_zst_fields)]
7393

7494
Future breakage diagnostic:
7595
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
76-
--> $DIR/repr-transparent-array.rs:22:15
96+
--> $DIR/repr-transparent-array.rs:33:15
7797
|
7898
LL | pub struct T6(SusArray, Sized);
7999
| ^^^^^^^^
@@ -89,7 +109,7 @@ LL | #![deny(repr_transparent_non_zst_fields)]
89109

90110
Future breakage diagnostic:
91111
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
92-
--> $DIR/repr-transparent-array.rs:27:19
112+
--> $DIR/repr-transparent-array.rs:38:19
93113
|
94114
LL | pub struct T7(T1, SusArray); // still wrong, even when the array is hidden inside another type
95115
| ^^^^^^^^
@@ -105,7 +125,7 @@ LL | #![deny(repr_transparent_non_zst_fields)]
105125

106126
Future breakage diagnostic:
107127
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
108-
--> $DIR/repr-transparent-array.rs:32:25
128+
--> $DIR/repr-transparent-array.rs:43:25
109129
|
110130
LL | pub struct T8(SusArray, SusArray); // still wrong
111131
| ^^^^^^^^
@@ -121,7 +141,7 @@ LL | #![deny(repr_transparent_non_zst_fields)]
121141

122142
Future breakage diagnostic:
123143
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
124-
--> $DIR/repr-transparent-array.rs:37:29
144+
--> $DIR/repr-transparent-array.rs:48:29
125145
|
126146
LL | pub struct T9([[u8; 0]; 0], SusArray); // still wrong
127147
| ^^^^^^^^
@@ -135,3 +155,35 @@ note: the lint level is defined here
135155
LL | #![deny(repr_transparent_non_zst_fields)]
136156
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
137157

158+
Future breakage diagnostic:
159+
error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
160+
--> $DIR/repr-transparent-array.rs:53:23
161+
|
162+
LL | pub struct T10(Sized, CPacked1Arr<u128>);
163+
| ^^^^^^^^^^^^^^^^^
164+
|
165+
= note: this field contains `CPacked1Arr<u128>`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
166+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
167+
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
168+
note: the lint level is defined here
169+
--> $DIR/repr-transparent-array.rs:1:9
170+
|
171+
LL | #![deny(repr_transparent_non_zst_fields)]
172+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
173+
174+
Future breakage diagnostic:
175+
error: zero-sized fields in `repr(transparent)` cannot contain array types with non-trivial element types
176+
--> $DIR/repr-transparent-array.rs:58:23
177+
|
178+
LL | pub struct T11(Sized, RustPacked2Arr);
179+
| ^^^^^^^^^^^^^^
180+
|
181+
= 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.
182+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
183+
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
184+
note: the lint level is defined here
185+
--> $DIR/repr-transparent-array.rs:1:9
186+
|
187+
LL | #![deny(repr_transparent_non_zst_fields)]
188+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
189+

0 commit comments

Comments
 (0)