Skip to content

Commit d409c7e

Browse files
committed
ImproperCTypes: change handling of slices
correctly handle !Sized arrays at the tail-end of structs and a cosmetic change to the array/slice-related lints,
1 parent 5b9fb7a commit d409c7e

File tree

6 files changed

+46
-28
lines changed

6 files changed

+46
-28
lines changed

compiler/rustc_lint/messages.ftl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,7 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
386386
387387
lint_improper_ctypes_opaque = opaque types have no C equivalent
388388
389-
lint_improper_ctypes_slice_help = consider using a raw pointer instead
390-
389+
lint_improper_ctypes_slice_help = consider using a raw pointer to the slice's first element (and a length) instead
391390
lint_improper_ctypes_slice_reason = slices have no C equivalent
392391
393392
lint_improper_ctypes_str_help = consider using `*const u8` and a length instead

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -659,9 +659,6 @@ bitflags! {
659659
/// To show that there is no outer type, the current type is directly used by a `static`
660660
/// variable or a function/FnPtr
661661
const NO_OUTER_TY = 0b100000;
662-
/// For NO_OUTER_TY cases, show that we are being directly used by a FnPtr specifically
663-
/// FIXME(ctypes): this is only used for "bad behaviour" reproduced for compatibility's sake
664-
const NOOUT_FNPTR = 0b1000000;
665662
}
666663
}
667664

@@ -696,7 +693,7 @@ impl EphemeralStateFlags {
696693
/// modify self to change the ephemeral part of the flags
697694
fn from_outer_ty<'tcx>(ty: Ty<'tcx>) -> Self {
698695
match ty.kind() {
699-
ty::FnPtr(..) => Self::NO_OUTER_TY | Self::NOOUT_FNPTR,
696+
ty::FnPtr(..) => Self::NO_OUTER_TY,
700697
k @ (ty::RawPtr(..) | ty::Ref(..)) => {
701698
let mut ret = Self::IN_PTR;
702699
if ty.is_mutable_ptr() {
@@ -740,7 +737,7 @@ impl VisitorState {
740737
} else {
741738
PersistentStateFlags::ARGUMENT_TY_IN_FNPTR
742739
},
743-
ephemeral_flags: EphemeralStateFlags::NO_OUTER_TY | EphemeralStateFlags::NOOUT_FNPTR,
740+
ephemeral_flags: EphemeralStateFlags::NO_OUTER_TY,
744741
}
745742
}
746743

@@ -779,6 +776,15 @@ impl VisitorState {
779776
Self::entry_point(PersistentStateFlags::STATIC_TY)
780777
}
781778

779+
/// Whether the type is used as the type of a static variable.
780+
fn is_direct_in_static(&self) -> bool {
781+
let ret = self.persistent_flags.contains(PersistentStateFlags::STATIC);
782+
if ret {
783+
debug_assert!(!self.persistent_flags.contains(PersistentStateFlags::FUNC));
784+
}
785+
ret && self.ephemeral_flags.contains(EphemeralStateFlags::NO_OUTER_TY)
786+
}
787+
782788
/// Whether the type is used in a function.
783789
fn is_in_function(&self) -> bool {
784790
let ret = self.persistent_flags.contains(PersistentStateFlags::FUNC);
@@ -844,6 +850,12 @@ impl VisitorState {
844850
fn is_raw_pointee(&self) -> bool {
845851
self.ephemeral_flags.contains(EphemeralStateFlags::IN_PTR | EphemeralStateFlags::PTR_RAW)
846852
}
853+
854+
/// Whether the current type directly in the memory layout of the parent ty
855+
#[inline]
856+
fn is_memory_inlined(&self) -> bool {
857+
self.ephemeral_flags.contains(EphemeralStateFlags::MEMORY_INLINED)
858+
}
847859
}
848860

849861
/// Visitor used to recursively traverse MIR types and evaluate FFI-safety.
@@ -1320,11 +1332,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13201332
Some(fluent::lint_improper_ctypes_char_help),
13211333
),
13221334

1323-
ty::Slice(_) => FfiResult::new_with_reason(
1324-
ty,
1325-
fluent::lint_improper_ctypes_slice_reason,
1326-
Some(fluent::lint_improper_ctypes_slice_help),
1327-
),
1335+
ty::Slice(inner_ty) => {
1336+
// ty::Slice is used for !Sized arrays, since they are the pointee for actual slices
1337+
let slice_is_actually_array =
1338+
state.is_memory_inlined() || state.is_direct_in_static();
1339+
1340+
if slice_is_actually_array {
1341+
self.visit_type(state.get_next(ty), inner_ty)
1342+
} else {
1343+
FfiResult::new_with_reason(
1344+
ty,
1345+
fluent::lint_improper_ctypes_slice_reason,
1346+
Some(fluent::lint_improper_ctypes_slice_help),
1347+
)
1348+
}
1349+
}
13281350

13291351
ty::Dynamic(..) => {
13301352
FfiResult::new_with_reason(ty, fluent::lint_improper_ctypes_dyn, None)
@@ -1376,10 +1398,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13761398
}
13771399

13781400
ty::Array(inner_ty, _) => {
1379-
if state.is_direct_in_function()
1380-
// FIXME(ctypes): VVV-this-VVV shouldn't be the case
1381-
&& !state.ephemeral_flags.contains(EphemeralStateFlags::NOOUT_FNPTR)
1382-
{
1401+
if state.is_direct_in_function() {
13831402
// C doesn't really support passing arrays by value - the only way to pass an array by value
13841403
// is through a struct.
13851404
FfiResult::new_with_reason(

tests/ui/lint/extern-C-fnptr-lints-slices.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | pub type F = extern "C" fn(&[u8]);
55
| ^^^^^^^^^^^^^^^^^^^^ not FFI-safe
66
|
77
= note: the function pointer to `for<'a> extern "C" fn(&'a [u8])` is FFI-unsafe due to `&[u8]`
8-
= help: consider using a raw pointer instead
8+
= help: consider using a raw pointer to the slice's first element (and a length) instead
99
= note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
1010
note: the lint level is defined here
1111
--> $DIR/extern-C-fnptr-lints-slices.rs:1:8

tests/ui/lint/improper-ctypes/lint-94223.stderr

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | pub fn bad(f: extern "C" fn([u8])) {}
55
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
66
|
77
= note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
8-
= help: consider using a raw pointer instead
8+
= help: consider using a raw pointer to the slice's first element (and a length) instead
99
= note: slices have no C equivalent
1010
note: the lint level is defined here
1111
--> $DIR/lint-94223.rs:2:36
@@ -20,7 +20,7 @@ LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
2020
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
2121
|
2222
= note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
23-
= help: consider using a raw pointer instead
23+
= help: consider using a raw pointer to the slice's first element (and a length) instead
2424
= note: slices have no C equivalent
2525

2626
error: `extern` callback uses type `[u8]`, which is not FFI-safe
@@ -30,7 +30,7 @@ LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
3030
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
3131
|
3232
= note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
33-
= help: consider using a raw pointer instead
33+
= help: consider using a raw pointer to the slice's first element (and a length) instead
3434
= note: slices have no C equivalent
3535

3636
error: `extern` callback uses type `[u8]`, which is not FFI-safe
@@ -40,7 +40,7 @@ LL | struct BadStruct(extern "C" fn([u8]));
4040
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
4141
|
4242
= note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
43-
= help: consider using a raw pointer instead
43+
= help: consider using a raw pointer to the slice's first element (and a length) instead
4444
= note: slices have no C equivalent
4545

4646
error: `extern` callback uses type `[u8]`, which is not FFI-safe
@@ -50,7 +50,7 @@ LL | A(extern "C" fn([u8])),
5050
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
5151
|
5252
= note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
53-
= help: consider using a raw pointer instead
53+
= help: consider using a raw pointer to the slice's first element (and a length) instead
5454
= note: slices have no C equivalent
5555

5656
error: `extern` callback uses type `[u8]`, which is not FFI-safe
@@ -60,7 +60,7 @@ LL | A(extern "C" fn([u8])),
6060
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
6161
|
6262
= note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
63-
= help: consider using a raw pointer instead
63+
= help: consider using a raw pointer to the slice's first element (and a length) instead
6464
= note: slices have no C equivalent
6565

6666
error: `extern` callback uses type `[u8]`, which is not FFI-safe
@@ -70,7 +70,7 @@ LL | type Foo = extern "C" fn([u8]);
7070
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
7171
|
7272
= note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
73-
= help: consider using a raw pointer instead
73+
= help: consider using a raw pointer to the slice's first element (and a length) instead
7474
= note: slices have no C equivalent
7575

7676
error: `extern` callback uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe

tests/ui/lint/improper-ctypes/lint-ctypes.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: `extern` block uses type `&[u32]`, which is not FFI-safe
44
LL | pub fn slice_type(p: &[u32]);
55
| ^^^^^^ not FFI-safe
66
|
7-
= help: consider using a raw pointer instead
7+
= help: consider using a raw pointer to the slice's first element (and a length) instead
88
= note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
99
note: the lint level is defined here
1010
--> $DIR/lint-ctypes.rs:5:9
@@ -170,7 +170,7 @@ note: the type is defined here
170170
|
171171
LL | pub struct TwoBadTypes<'a> {
172172
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
173-
= help: consider using a raw pointer instead
173+
= help: consider using a raw pointer to the slice's first element (and a length) instead
174174
= note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
175175

176176
error: `extern` block uses type `&UnsizedStructBecauseDyn`, which is not FFI-safe

tests/ui/lint/improper-ctypes/lint-fn.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ error: `extern` fn uses type `&[u32]`, which is not FFI-safe
1919
LL | pub extern "C" fn slice_type(p: &[u32]) { }
2020
| ^^^^^^ not FFI-safe
2121
|
22-
= help: consider using a raw pointer instead
22+
= help: consider using a raw pointer to the slice's first element (and a length) instead
2323
= note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
2424
note: the lint level is defined here
2525
--> $DIR/lint-fn.rs:2:31
@@ -42,7 +42,7 @@ error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
4242
LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
4343
| ^^^^^^^^^ not FFI-safe
4444
|
45-
= help: consider using a raw pointer instead
45+
= help: consider using a raw pointer to the slice's first element (and a length) instead
4646
= note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer
4747

4848
error: `extern` fn uses type `Box<str>`, which is not FFI-safe

0 commit comments

Comments
 (0)