Skip to content

Commit 41aa64b

Browse files
committed
ImproperCTypes: don't consider packed reprs
`[repr(C,packed)]` structs shouldn't be considered FFI-safe
1 parent f4b9440 commit 41aa64b

File tree

2 files changed

+19
-24
lines changed

2 files changed

+19
-24
lines changed

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -251,22 +251,21 @@ fn check_struct_for_power_alignment<'tcx>(
251251
item: &'tcx hir::Item<'tcx>,
252252
adt_def: AdtDef<'tcx>,
253253
) {
254-
let tcx = cx.tcx;
255-
256254
// Only consider structs (not enums or unions) on AIX.
257-
if tcx.sess.target.os != "aix" || !adt_def.is_struct() {
255+
if cx.tcx.sess.target.os != "aix" || !adt_def.is_struct() {
258256
return;
259257
}
260258

261259
// The struct must be repr(C), but ignore it if it explicitly specifies its alignment with
262260
// either `align(N)` or `packed(N)`.
263-
if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none() {
261+
debug_assert!(adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none());
262+
if cx.tcx.sess.target.os == "aix" && !adt_def.all_fields().next().is_none() {
264263
let struct_variant_data = item.expect_struct().2;
265264
for field_def in struct_variant_data.fields().iter().skip(1) {
266265
// Struct fields (after the first field) are checked for the
267266
// power alignment rule, as fields after the first are likely
268267
// to be the fields that are misaligned.
269-
let ty = tcx.type_of(field_def.def_id).instantiate_identity();
268+
let ty = cx.tcx.type_of(field_def.def_id).instantiate_identity();
270269
if check_arg_for_power_alignment(cx, ty) {
271270
cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
272271
}
@@ -1060,7 +1059,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
10601059
// otherwise, having all fields be phantoms
10611060
// takes priority over transparent_with_all_zst_fields
10621061
if let FfiUnsafe(explanations) = ffires_accumulator {
1063-
debug_assert!(def.repr().c() || def.repr().transparent() || def.repr().int.is_some());
1062+
debug_assert!(
1063+
(def.repr().c() && !def.repr().packed())
1064+
|| def.repr().transparent()
1065+
|| def.repr().int.is_some()
1066+
);
10641067

10651068
if def.repr().transparent() || matches!(def.adt_kind(), AdtKind::Enum) {
10661069
let field_ffires = FfiUnsafe(explanations).wrap_all(
@@ -1130,7 +1133,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11301133
) -> FfiResult<'tcx> {
11311134
debug_assert!(matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union));
11321135

1133-
if !def.repr().c() && !def.repr().transparent() {
1136+
if !((def.repr().c() && !def.repr().packed()) || def.repr().transparent()) {
1137+
// FIXME(ctypes) packed reprs prevent C compatibility, right?
11341138
return FfiResult::new_with_reason(
11351139
ty,
11361140
if def.is_struct() {
@@ -1202,7 +1206,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12021206
}
12031207
// Check for a repr() attribute to specify the size of the
12041208
// discriminant.
1205-
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() {
1209+
if !(def.repr().c() && !def.repr().packed())
1210+
&& !def.repr().transparent()
1211+
&& def.repr().int.is_none()
1212+
{
12061213
// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
12071214
if let Some(inner_ty) = repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty) {
12081215
return self.visit_type(state.get_next(ty), inner_ty);

tests/ui/lint/improper-ctypes/repr-rust-is-undefined.stderr

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,13 @@ error: `extern` block uses type `B`, which is not FFI-safe
2323
LL | fn bar(x: B);
2424
| ^ not FFI-safe
2525
|
26-
= note: this struct/enum/union (`B`) is FFI-unsafe due to a `A` field
26+
= help: consider adding a `#[repr(C)]` (not `#[repr(C,packed)]`) or `#[repr(transparent)]` attribute to `B`
27+
= note: `B` has unspecified layout
2728
note: the type is defined here
2829
--> $DIR/repr-rust-is-undefined.rs:13:1
2930
|
3031
LL | struct B {
3132
| ^^^^^^^^
32-
= help: consider adding a `#[repr(C)]` (not `#[repr(C,packed)]`) or `#[repr(transparent)]` attribute to `A`
33-
= note: `A` has unspecified layout
34-
note: the type is defined here
35-
--> $DIR/repr-rust-is-undefined.rs:8:1
36-
|
37-
LL | struct A {
38-
| ^^^^^^^^
3933

4034
error: `extern` block uses type `A`, which is not FFI-safe
4135
--> $DIR/repr-rust-is-undefined.rs:37:15
@@ -57,19 +51,13 @@ error: `extern` block uses type `B`, which is not FFI-safe
5751
LL | fn quux(x: B2);
5852
| ^^ not FFI-safe
5953
|
60-
= note: this struct/enum/union (`B`) is FFI-unsafe due to a `A` field
54+
= help: consider adding a `#[repr(C)]` (not `#[repr(C,packed)]`) or `#[repr(transparent)]` attribute to `B`
55+
= note: `B` has unspecified layout
6156
note: the type is defined here
6257
--> $DIR/repr-rust-is-undefined.rs:13:1
6358
|
6459
LL | struct B {
6560
| ^^^^^^^^
66-
= help: consider adding a `#[repr(C)]` (not `#[repr(C,packed)]`) or `#[repr(transparent)]` attribute to `A`
67-
= note: `A` has unspecified layout
68-
note: the type is defined here
69-
--> $DIR/repr-rust-is-undefined.rs:8:1
70-
|
71-
LL | struct A {
72-
| ^^^^^^^^
7361

7462
error: `extern` block uses type `D`, which is not FFI-safe
7563
--> $DIR/repr-rust-is-undefined.rs:40:16

0 commit comments

Comments
 (0)