diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f734f3182a9..b6e8ae96942 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -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`. 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(); } } } diff --git a/src/test/ui/lint-ctypes.stderr b/src/test/ui/lint-ctypes.stderr index 21aadde8ac8..0f7f7e048e3 100644 --- a/src/test/ui/lint-ctypes.stderr +++ b/src/test/ui/lint-ctypes.stderr @@ -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); //~ 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; //~ 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