about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_lint/types.rs177
-rw-r--r--src/test/ui/lint-ctypes.stderr59
2 files changed, 156 insertions, 80 deletions
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<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();
             }
         }
     }
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<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