Skip to content

Commit c628ac4

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 8718f75 commit c628ac4

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
@@ -614,6 +614,15 @@ impl VisitorState {
614614
}
615615
}
616616

617+
/// Whether the type is used in a static variable.
618+
fn is_in_static(self) -> bool {
619+
let ret = self.contains(Self::STATIC);
620+
if ret {
621+
assert!(!self.contains(Self::FUNC));
622+
}
623+
ret
624+
}
625+
617626
/// Whether the type is used in a function.
618627
fn is_in_function(self) -> bool {
619628
let ret = self.contains(Self::FUNC);
@@ -1179,11 +1188,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11791188
// Primitive types with a stable representation.
11801189
ty::Bool => FfiSafe,
11811190

1182-
ty::Slice(_) => FfiResult::new_with_reason(
1183-
ty,
1184-
fluent::lint_improper_ctypes_slice_reason,
1185-
Some(fluent::lint_improper_ctypes_slice_help),
1186-
),
1191+
ty::Slice(inner_ty) => {
1192+
// ty::Slice is used for !Sized arrays, since they are the pointee for actual slices
1193+
let slice_is_actually_array = match outer_ty.map(|ty| ty.kind()) {
1194+
None => state.is_in_static(),
1195+
// this should have been caught a layer up, in visit_indirection
1196+
Some(ty::Ref(..) | ty::RawPtr(..)) => false,
1197+
Some(ty::Adt(..)) => ty.boxed_ty().is_none(),
1198+
Some(ty::Tuple(..)) => true,
1199+
Some(ty::FnPtr(..)) => false,
1200+
// this is supposed to cause a compile error that prevents this lint
1201+
// from being reached, but oh well
1202+
Some(ty::Array(..) | ty::Slice(_)) => true,
1203+
Some(ty @ _) => bug!("unexpected ty_kind around a slice: {:?}", ty),
1204+
};
1205+
if slice_is_actually_array {
1206+
self.visit_type(state, Some(ty), inner_ty)
1207+
} else {
1208+
FfiResult::new_with_reason(
1209+
ty,
1210+
fluent::lint_improper_ctypes_slice_reason,
1211+
Some(fluent::lint_improper_ctypes_slice_help),
1212+
)
1213+
}
1214+
}
11871215

11881216
ty::Dynamic(..) => {
11891217
FfiResult::new_with_reason(ty, fluent::lint_improper_ctypes_dyn, None)
@@ -1239,7 +1267,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12391267
}
12401268

12411269
ty::Array(inner_ty, _) => {
1242-
if state.is_in_function() && matches!(outer_ty.map(|ty| ty.kind()), None) {
1270+
if state.is_in_function()
1271+
&& matches!(outer_ty.map(|ty| ty.kind()), None | Some(ty::FnPtr(..)))
1272+
{
12431273
// C doesn't really support passing arrays by value - the only way to pass an array by value
12441274
// is through a struct.
12451275
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)