Skip to content

Commit 7d195f6

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 fe31372 commit 7d195f6

File tree

6 files changed

+49
-20
lines changed

6 files changed

+49
-20
lines changed

compiler/rustc_lint/messages.ftl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,7 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
393393
394394
lint_improper_ctypes_opaque = opaque types have no C equivalent
395395
396-
lint_improper_ctypes_slice_help = consider using a raw pointer instead
397-
396+
lint_improper_ctypes_slice_help = consider using a raw pointer to the slice's first element (and a length) instead
398397
lint_improper_ctypes_slice_reason = slices have no C equivalent
399398
400399
lint_improper_ctypes_str_help = consider using `*const u8` and a length instead

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,15 @@ impl VisitorState {
454454
}
455455
}
456456

457+
/// Whether the type is used in a static variable.
458+
fn is_in_static(self) -> bool {
459+
let ret = (self & Self::STATIC) != Self::None;
460+
if ret {
461+
assert!((self & Self::FUNC) == Self::None);
462+
}
463+
ret
464+
}
465+
457466
/// Whether the type is used in a function.
458467
fn is_in_function(self) -> bool {
459468
let ret = (self & Self::FUNC) != Self::None;
@@ -1030,11 +1039,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
10301039
// Primitive types with a stable representation.
10311040
ty::Bool => FfiSafe,
10321041

1033-
ty::Slice(_) => FfiResult::new_with_reason(
1034-
ty,
1035-
fluent::lint_improper_ctypes_slice_reason,
1036-
Some(fluent::lint_improper_ctypes_slice_help),
1037-
),
1042+
ty::Slice(inner_ty) => {
1043+
// ty::Slice is used for !Sized arrays, since they are the pointee for actual slices
1044+
let slice_is_actually_array = match outer_ty.map(|ty| ty.kind()) {
1045+
None => state.is_in_static(),
1046+
// this should have been caught a layer up, in visit_indirection
1047+
Some(ty::Ref(..) | ty::RawPtr(..)) => false,
1048+
Some(ty::Adt(..)) => ty.boxed_ty().is_none(),
1049+
Some(ty::Tuple(..)) => true,
1050+
Some(ty::FnPtr(..)) => false,
1051+
// this is supposed to cause a compile error that prevents this lint
1052+
// from being reached, but oh well
1053+
Some(ty::Array(..) | ty::Slice(_)) => true,
1054+
Some(ty @ _) => bug!("unexpected ty_kind around a slice: {:?}", ty),
1055+
};
1056+
if slice_is_actually_array {
1057+
self.visit_type(state, Some(ty), inner_ty)
1058+
} else {
1059+
FfiResult::new_with_reason(
1060+
ty,
1061+
fluent::lint_improper_ctypes_slice_reason,
1062+
Some(fluent::lint_improper_ctypes_slice_help),
1063+
)
1064+
}
1065+
}
10381066

10391067
ty::Dynamic(..) => {
10401068
FfiResult::new_with_reason(ty, fluent::lint_improper_ctypes_dyn, None)
@@ -1090,7 +1118,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
10901118
}
10911119

10921120
ty::Array(inner_ty, _) => {
1093-
if state.is_in_function() && matches!(outer_ty.map(|ty| ty.kind()), None) {
1121+
if state.is_in_function()
1122+
&& matches!(outer_ty.map(|ty| ty.kind()), None | Some(ty::FnPtr(..)))
1123+
{
10941124
// C doesn't really support passing arrays by value - the only way to pass an array by value
10951125
// is through a struct.
10961126
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)