[improper_ctypes] Use a 'help:' line for possible fixes

This commit is contained in:
Robin Kruppe 2018-02-11 21:31:42 +01:00
parent 1f0e1a0439
commit 7ac5e96f4a
2 changed files with 156 additions and 80 deletions

View File

@ -353,13 +353,18 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
}
struct FfiError {
message: &'static str,
help: Option<&'static str>,
}
enum FfiResult {
FfiSafe,
FfiPhantom,
FfiUnsafe(&'static str),
FfiBadStruct(DefId, &'static str),
FfiBadUnion(DefId, &'static str),
FfiBadEnum(DefId, &'static str),
FfiUnsafe(FfiError),
FfiBadStruct(DefId, FfiError),
FfiBadUnion(DefId, FfiError),
FfiBadEnum(DefId, FfiError),
}
/// Check if this enum can be safely exported based on the
@ -434,14 +439,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
match def.adt_kind() {
AdtKind::Struct => {
if !def.repr.c() && !def.repr.transparent() {
return FfiUnsafe("found struct without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
return FfiUnsafe(FfiError {
message: "found struct without foreign-function-safe \
representation annotation in foreign module",
help: Some("consider adding a #[repr(C)] attribute to the type"),
});
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe("found zero-size struct in foreign module, consider \
adding a member to this struct");
return FfiUnsafe(FfiError {
message: "found zero-size struct in foreign module",
help: Some("consider adding a member to this struct"),
});
}
// We can't completely trust repr(C) and repr(transparent) markings;
@ -471,8 +480,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
return r;
}
FfiUnsafe(s) => {
return FfiBadStruct(def.did, s);
FfiUnsafe(err) => {
return FfiBadStruct(def.did, err);
}
}
}
@ -481,14 +490,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
AdtKind::Union => {
if !def.repr.c() {
return FfiUnsafe("found union without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
return FfiUnsafe(FfiError {
message: "found union without foreign-function-safe \
representation annotation in foreign module",
help: Some("consider adding a #[repr(C)] attribute to the type"),
});
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe("found zero-size union in foreign module, consider \
adding a member to this union");
return FfiUnsafe(FfiError {
message: "found zero-size union in foreign module",
help: Some("consider adding a member to this union"),
});
}
let mut all_phantom = true;
@ -505,8 +518,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
return r;
}
FfiUnsafe(s) => {
return FfiBadUnion(def.did, s);
FfiUnsafe(err) => {
return FfiBadUnion(def.did, err);
}
}
}
@ -524,10 +537,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if !def.repr.c() && def.repr.int.is_none() {
// Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, def, substs) {
return FfiUnsafe("found enum without foreign-function-safe \
representation annotation in foreign \
module, consider adding a #[repr(...)] \
attribute to the type");
return FfiUnsafe(FfiError {
message: "found enum without foreign-function-safe \
representation annotation in foreign module",
help: Some("consider adding a #[repr(...)] attribute \
to the type"),
});
}
}
@ -535,7 +550,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if !is_ffi_safe(int_ty) {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
return FfiUnsafe(FfiError {
message: "enum has unexpected #[repr(...)] attribute",
help: None,
});
}
// Enum with an explicitly sized discriminant; either
@ -558,11 +576,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
return r;
}
FfiPhantom => {
return FfiBadEnum(def.did,
"Found phantom data in enum variant");
return FfiBadEnum(def.did, FfiError {
message: "Found phantom data in enum variant",
help: None,
});
}
FfiUnsafe(s) => {
return FfiBadEnum(def.did, s);
FfiUnsafe(err) => {
return FfiBadEnum(def.did, err);
}
}
}
@ -573,43 +593,57 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
ty::TyChar => {
FfiUnsafe("found Rust type `char` in foreign module, while \
`u32` or `libc::wchar_t` should be used")
FfiUnsafe(FfiError {
message: "found Rust type `char` in foreign module",
help: Some("consider using `u32` or `libc::wchar_t`"),
})
}
ty::TyInt(ast::IntTy::I128) => {
FfiUnsafe("found Rust type `i128` in foreign module, but \
128-bit integers don't currently have a known \
stable ABI")
FfiUnsafe(FfiError {
message: "found Rust type `i128` in foreign module, but 128-bit \
integers don't currently have a known stable ABI",
help: None,
})
}
ty::TyUint(ast::UintTy::U128) => {
FfiUnsafe("found Rust type `u128` in foreign module, but \
128-bit integers don't currently have a known \
stable ABI")
FfiUnsafe(FfiError {
message: "found Rust type `u128` in foreign module, but 128-bit \
integers don't currently have a known stable ABI",
help: None,
})
}
// Primitive types with a stable representation.
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TySlice(_) => {
FfiUnsafe("found Rust slice type in foreign module, \
consider using a raw pointer instead")
FfiUnsafe(FfiError {
message: "found Rust slice type in foreign module",
help: Some("consider using a raw pointer instead"),
})
}
ty::TyDynamic(..) => {
FfiUnsafe("found Rust trait type in foreign module, \
consider using a raw pointer instead")
FfiUnsafe(FfiError {
message: "found Rust trait type in foreign module",
help: Some("consider using a raw pointer instead"),
})
}
ty::TyStr => {
FfiUnsafe("found Rust type `str` in foreign module; \
consider using a `*const libc::c_char`")
FfiUnsafe(FfiError {
message: "found Rust type `str` in foreign module",
help: Some("consider using a `*const libc::c_char`"),
})
}
ty::TyTuple(..) => {
FfiUnsafe("found Rust tuple type in foreign module; \
consider using a struct instead")
FfiUnsafe(FfiError {
message: "found Rust tuple type in foreign module",
help: Some("consider using a struct instead"),
})
}
ty::TyRawPtr(ref m) |
@ -620,9 +654,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
ty::TyFnPtr(sig) => {
match sig.abi() {
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
return FfiUnsafe("found function pointer with Rust calling convention in \
foreign module; consider using an `extern` function \
pointer")
return FfiUnsafe(FfiError {
message: "found function pointer with Rust calling convention in \
foreign module",
help: Some("consider using an `extern` function pointer"),
})
}
_ => {}
}
@ -676,34 +712,45 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
&format!("found zero-sized type composed only \
of phantom-data in a foreign-function."));
}
FfiResult::FfiUnsafe(s) => {
self.cx.span_lint(IMPROPER_CTYPES, sp, s);
FfiResult::FfiUnsafe(err) => {
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, err.message);
if let Some(s) = err.help {
diag.help(s);
}
diag.emit();
}
FfiResult::FfiBadStruct(_, s) => {
FfiResult::FfiBadStruct(_, err) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in struct \
marked #[repr(C)]: {}",
s));
let msg = format!("found non-foreign-function-safe member in struct \
marked #[repr(C)]: {}", err.message);
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
if let Some(s) = err.help {
diag.help(s);
}
diag.emit();
}
FfiResult::FfiBadUnion(_, s) => {
FfiResult::FfiBadUnion(_, err) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in union \
marked #[repr(C)]: {}",
s));
let msg = format!("found non-foreign-function-safe member in union \
marked #[repr(C)]: {}", err.message);
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
if let Some(s) = err.help {
diag.help(s);
}
diag.emit();
}
FfiResult::FfiBadEnum(_, s) => {
FfiResult::FfiBadEnum(_, err) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant variant.
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in enum: {}",
s));
let msg = format!("found non-foreign-function-safe member in enum: {}",
err.message);
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
if let Some(s) = err.help {
diag.help(s);
}
diag.emit();
}
}
}

View File

@ -1,4 +1,4 @@
error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type
error: found struct without foreign-function-safe representation annotation in foreign module
--> $DIR/lint-ctypes.rs:54:28
|
54 | pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without
@ -9,36 +9,47 @@ note: lint level defined here
|
11 | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^
= help: consider adding a #[repr(C)] attribute to the type
error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type
error: found struct without foreign-function-safe representation annotation in foreign module
--> $DIR/lint-ctypes.rs:55:28
|
55 | pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without
| ^^^^^^^^^^
|
= help: consider adding a #[repr(C)] attribute to the type
error: found Rust slice type in foreign module, consider using a raw pointer instead
error: found Rust slice type in foreign module
--> $DIR/lint-ctypes.rs:56:26
|
56 | pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type
| ^^^^^^
|
= help: consider using a raw pointer instead
error: found Rust type `str` in foreign module; consider using a `*const libc::c_char`
error: found Rust type `str` in foreign module
--> $DIR/lint-ctypes.rs:57:24
|
57 | pub fn str_type(p: &str); //~ ERROR: found Rust type
| ^^^^
|
= help: consider using a `*const libc::c_char`
error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type
error: found struct without foreign-function-safe representation annotation in foreign module
--> $DIR/lint-ctypes.rs:58:24
|
58 | pub fn box_type(p: Box<u32>); //~ ERROR found struct without
| ^^^^^^^^
|
= help: consider adding a #[repr(C)] attribute to the type
error: found Rust type `char` in foreign module, while `u32` or `libc::wchar_t` should be used
error: found Rust type `char` in foreign module
--> $DIR/lint-ctypes.rs:59:25
|
59 | pub fn char_type(p: char); //~ ERROR found Rust type
| ^^^^
|
= help: consider using `u32` or `libc::wchar_t`
error: found Rust type `i128` in foreign module, but 128-bit integers don't currently have a known stable ABI
--> $DIR/lint-ctypes.rs:60:25
@ -52,29 +63,37 @@ error: found Rust type `u128` in foreign module, but 128-bit integers don't curr
61 | pub fn u128_type(p: u128); //~ ERROR found Rust type
| ^^^^
error: found Rust trait type in foreign module, consider using a raw pointer instead
error: found Rust trait type in foreign module
--> $DIR/lint-ctypes.rs:62:26
|
62 | pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type
| ^^^^^^
|
= help: consider using a raw pointer instead
error: found Rust tuple type in foreign module; consider using a struct instead
error: found Rust tuple type in foreign module
--> $DIR/lint-ctypes.rs:63:26
|
63 | pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type
| ^^^^^^^^^^
|
= help: consider using a struct instead
error: found Rust tuple type in foreign module; consider using a struct instead
error: found Rust tuple type in foreign module
--> $DIR/lint-ctypes.rs:64:27
|
64 | pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type
| ^^^^^^^
|
= help: consider using a struct instead
error: found zero-size struct in foreign module, consider adding a member to this struct
error: found zero-size struct in foreign module
--> $DIR/lint-ctypes.rs:65:25
|
65 | pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct
| ^^^^^^^^
|
= help: consider adding a member to this struct
error: found zero-sized type composed only of phantom-data in a foreign-function.
--> $DIR/lint-ctypes.rs:66:33
@ -88,23 +107,29 @@ error: found zero-sized type composed only of phantom-data in a foreign-function
68 | -> ::std::marker::PhantomData<bool>; //~ ERROR: found zero-sized type
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: found function pointer with Rust calling convention in foreign module; consider using an `extern` function pointer
error: found function pointer with Rust calling convention in foreign module
--> $DIR/lint-ctypes.rs:69:23
|
69 | pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust
| ^^^^^^
|
= help: consider using an `extern` function pointer
error: found function pointer with Rust calling convention in foreign module; consider using an `extern` function pointer
error: found function pointer with Rust calling convention in foreign module
--> $DIR/lint-ctypes.rs:70:24
|
70 | pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust
| ^^^^
|
= help: consider using an `extern` function pointer
error: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type
error: found struct without foreign-function-safe representation annotation in foreign module
--> $DIR/lint-ctypes.rs:71:28
|
71 | pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without
| ^^^^^^^^^^
|
= help: consider adding a #[repr(C)] attribute to the type
error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `i128` in foreign module, but 128-bit integers don't currently have a known stable ABI
--> $DIR/lint-ctypes.rs:72:32
@ -112,17 +137,21 @@ error: found non-foreign-function-safe member in struct marked #[repr(C)]: found
72 | pub fn transparent_i128(p: TransparentI128); //~ ERROR: found Rust type `i128`
| ^^^^^^^^^^^^^^^
error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `str` in foreign module; consider using a `*const libc::c_char`
error: found non-foreign-function-safe member in struct marked #[repr(C)]: found Rust type `str` in foreign module
--> $DIR/lint-ctypes.rs:73:31
|
73 | pub fn transparent_str(p: TransparentStr); //~ ERROR: found Rust type `str`
| ^^^^^^^^^^^^^^
|
= help: consider using a `*const libc::c_char`
error: found non-foreign-function-safe member in struct marked #[repr(C)]: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type
error: found non-foreign-function-safe member in struct marked #[repr(C)]: found struct without foreign-function-safe representation annotation in foreign module
--> $DIR/lint-ctypes.rs:74:30
|
74 | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: found struct without
| ^^^^^^^^^^^^^^^^
|
= help: consider adding a #[repr(C)] attribute to the type
error: aborting due to 20 previous errors