Skip to content

Commit 26a7e89

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

File tree

2 files changed

+18
-27
lines changed

2 files changed

+18
-27
lines changed

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -316,22 +316,17 @@ fn check_struct_for_power_alignment<'tcx>(
316316
item: &'tcx hir::Item<'tcx>,
317317
adt_def: AdtDef<'tcx>,
318318
) {
319-
let tcx = cx.tcx;
320319
// repr(C) structs also with packed or aligned representation
321320
// should be ignored.
322-
if adt_def.repr().c()
323-
&& !adt_def.repr().packed()
324-
&& adt_def.repr().align.is_none()
325-
&& tcx.sess.target.os == "aix"
326-
&& !adt_def.all_fields().next().is_none()
327-
{
321+
debug_assert!(adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none());
322+
if cx.tcx.sess.target.os == "aix" && !adt_def.all_fields().next().is_none() {
328323
let struct_variant_data = item.expect_struct().2;
329324
for field_def in struct_variant_data.fields().iter().skip(1) {
330325
// Struct fields (after the first field) are checked for the
331326
// power alignment rule, as fields after the first are likely
332327
// to be the fields that are misaligned.
333328
let def_id = field_def.def_id;
334-
let ty = tcx.type_of(def_id).instantiate_identity();
329+
let ty = cx.tcx.type_of(def_id).instantiate_identity();
335330
if check_arg_for_power_alignment(cx, ty) {
336331
cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
337332
}
@@ -1161,7 +1156,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11611156
// takes priority over transparent_with_all_zst_fields
11621157
if let FfiUnsafe(explanations) = ffires_accumulator {
11631158
// we assume the repr() of this ADT is either non-packed C or transparent.
1164-
debug_assert!(def.repr().c() || def.repr().transparent() || def.repr().int.is_some());
1159+
debug_assert!(
1160+
(def.repr().c() && !def.repr().packed())
1161+
|| def.repr().transparent()
1162+
|| def.repr().int.is_some()
1163+
);
11651164

11661165
if def.repr().transparent() || matches!(def.adt_kind(), AdtKind::Enum) {
11671166
let field_ffires = FfiUnsafe(explanations).wrap_all(
@@ -1231,7 +1230,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12311230
) -> FfiResult<'tcx> {
12321231
debug_assert!(matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union));
12331232

1234-
if !def.repr().c() && !def.repr().transparent() {
1233+
if !((def.repr().c() && !def.repr().packed()) || def.repr().transparent()) {
1234+
// FIXME(ctypes) packed reprs prevent C compatibility, right?
12351235
return FfiResult::new_with_reason(
12361236
ty,
12371237
if def.is_struct() {
@@ -1307,7 +1307,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13071307
}
13081308
// Check for a repr() attribute to specify the size of the
13091309
// discriminant.
1310-
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() {
1310+
if !(def.repr().c() && !def.repr().packed())
1311+
&& !def.repr().transparent()
1312+
&& def.repr().int.is_none()
1313+
{
13111314
// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
13121315
if let Some(inner_ty) = repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty) {
13131316
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)