]> git.lizzy.rs Git - rust.git/commitdiff
Rewrite the improper_ctypes lint.
authorEli Friedman <eli.friedman@gmail.com>
Thu, 25 Jun 2015 21:48:36 +0000 (14:48 -0700)
committerEli Friedman <eli.friedman@gmail.com>
Fri, 24 Jul 2015 00:03:04 +0000 (17:03 -0700)
Makes the lint a bit more accurate, and improves the quality of the diagnostic
messages by explicitly returning an error message.

The new lint is also a little more aggressive: specifically, it now
rejects tuples, and it recurses into function pointers.

14 files changed:
src/librustc/middle/ty.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_llvm/lib.rs
src/librustc_trans/back/msvc/registry.rs
src/libstd/rt/unwind/gcc.rs
src/libstd/sys/windows/stack_overflow.rs
src/libstd/thread/local.rs
src/test/compile-fail/issue-14309.rs
src/test/compile-fail/issue-16250.rs
src/test/compile-fail/lint-ctypes-enum.rs
src/test/compile-fail/lint-ctypes.rs
src/test/compile-fail/warn-foreign-int-types.rs
src/test/run-make/execution-engine/test.rs

index 17a76f6eed9c5af59e415b23d4791d3d81e7a973..64e707f6264e6cae2bdf35ea569ea228e0fd8962 100644 (file)
@@ -3967,7 +3967,6 @@ mod TC {
         None                                = 0b0000_0000__0000_0000__0000,
 
         // Things that are interior to the value (first nibble):
-        InteriorUnsized                     = 0b0000_0000__0000_0000__0001,
         InteriorUnsafe                      = 0b0000_0000__0000_0000__0010,
         InteriorParam                       = 0b0000_0000__0000_0000__0100,
         // InteriorAll                         = 0b00000000__00000000__1111,
@@ -3977,18 +3976,9 @@ mod TC {
         OwnsDtor                            = 0b0000_0000__0000_0010__0000,
         OwnsAll                             = 0b0000_0000__1111_1111__0000,
 
-        // Things that are reachable by the value in any way (fourth nibble):
-        ReachesBorrowed                     = 0b0000_0010__0000_0000__0000,
-        ReachesMutable                      = 0b0000_1000__0000_0000__0000,
-        ReachesFfiUnsafe                    = 0b0010_0000__0000_0000__0000,
-        ReachesAll                          = 0b0011_1111__0000_0000__0000,
-
         // Things that mean drop glue is necessary
         NeedsDrop                           = 0b0000_0000__0000_0111__0000,
 
-        // Things that prevent values from being considered sized
-        Nonsized                            = 0b0000_0000__0000_0000__0001,
-
         // All bits
         All                                 = 0b1111_1111__1111_1111__1111
     }
@@ -4007,10 +3997,6 @@ pub fn owns_owned(&self) -> bool {
         self.intersects(TC::OwnsOwned)
     }
 
-    pub fn is_sized(&self, _: &ctxt) -> bool {
-        !self.intersects(TC::Nonsized)
-    }
-
     pub fn interior_param(&self) -> bool {
         self.intersects(TC::InteriorParam)
     }
@@ -4019,29 +4005,13 @@ pub fn interior_unsafe(&self) -> bool {
         self.intersects(TC::InteriorUnsafe)
     }
 
-    pub fn interior_unsized(&self) -> bool {
-        self.intersects(TC::InteriorUnsized)
-    }
-
     pub fn needs_drop(&self, _: &ctxt) -> bool {
         self.intersects(TC::NeedsDrop)
     }
 
     /// Includes only those bits that still apply when indirected through a `Box` pointer
     pub fn owned_pointer(&self) -> TypeContents {
-        TC::OwnsOwned | (
-            *self & (TC::OwnsAll | TC::ReachesAll))
-    }
-
-    /// Includes only those bits that still apply when indirected through a reference (`&`)
-    pub fn reference(&self, bits: TypeContents) -> TypeContents {
-        bits | (
-            *self & TC::ReachesAll)
-    }
-
-    /// Includes only those bits that still apply when indirected through a raw pointer (`*`)
-    pub fn unsafe_pointer(&self) -> TypeContents {
-        *self & TC::ReachesAll
+        TC::OwnsOwned | (*self & TC::OwnsAll)
     }
 
     pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
@@ -4129,7 +4099,7 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
             let result = match ty.sty {
                 // usize and isize are ffi-unsafe
                 TyUint(ast::TyUs) | TyInt(ast::TyIs) => {
-                    TC::ReachesFfiUnsafe
+                    TC::None
                 }
 
                 // Scalar and unique types are sendable, and durable
@@ -4140,20 +4110,19 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
                 }
 
                 TyBox(typ) => {
-                    TC::ReachesFfiUnsafe | tc_ty(cx, typ, cache).owned_pointer()
+                    tc_ty(cx, typ, cache).owned_pointer()
                 }
 
-                TyTrait(box TraitTy { ref bounds, .. }) => {
-                    object_contents(bounds) | TC::ReachesFfiUnsafe | TC::Nonsized
+                TyTrait(_) => {
+                    TC::All - TC::InteriorParam
                 }
 
-                TyRawPtr(ref mt) => {
-                    tc_ty(cx, mt.ty, cache).unsafe_pointer()
+                TyRawPtr(_) => {
+                    TC::None
                 }
 
-                TyRef(r, ref mt) => {
-                    tc_ty(cx, mt.ty, cache).reference(borrowed_contents(*r, mt.mutbl)) |
-                        TC::ReachesFfiUnsafe
+                TyRef(_, _) => {
+                    TC::None
                 }
 
                 TyArray(ty, _) => {
@@ -4161,19 +4130,15 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
                 }
 
                 TySlice(ty) => {
-                    tc_ty(cx, ty, cache) | TC::Nonsized
+                    tc_ty(cx, ty, cache)
                 }
-                TyStr => TC::Nonsized,
+                TyStr => TC::None,
 
                 TyStruct(did, substs) => {
                     let flds = cx.struct_fields(did, substs);
                     let mut res =
                         TypeContents::union(&flds[..],
-                                            |f| tc_mt(cx, f.mt, cache));
-
-                    if !cx.lookup_repr_hints(did).contains(&attr::ReprExtern) {
-                        res = res | TC::ReachesFfiUnsafe;
-                    }
+                                            |f| tc_ty(cx, f.mt.ty, cache));
 
                     if cx.has_dtor(did) {
                         res = res | TC::OwnsDtor;
@@ -4182,7 +4147,6 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
                 }
 
                 TyClosure(did, substs) => {
-                    // FIXME(#14449): `borrowed_contents` below assumes `&mut` closure.
                     let param_env = cx.empty_parameter_environment();
                     let infcx = infer::new_infer_ctxt(cx, &cx.tables, Some(param_env), false);
                     let upvars = infcx.closure_upvars(did, substs).unwrap();
@@ -4208,44 +4172,6 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
                         res = res | TC::OwnsDtor;
                     }
 
-                    if !variants.is_empty() {
-                        let repr_hints = cx.lookup_repr_hints(did);
-                        if repr_hints.len() > 1 {
-                            // this is an error later on, but this type isn't safe
-                            res = res | TC::ReachesFfiUnsafe;
-                        }
-
-                        match repr_hints.get(0) {
-                            Some(h) => if !h.is_ffi_safe() {
-                                res = res | TC::ReachesFfiUnsafe;
-                            },
-                            // ReprAny
-                            None => {
-                                res = res | TC::ReachesFfiUnsafe;
-
-                                // We allow ReprAny enums if they are eligible for
-                                // the nullable pointer optimization and the
-                                // contained type is an `extern fn`
-
-                                if variants.len() == 2 {
-                                    let mut data_idx = 0;
-
-                                    if variants[0].args.is_empty() {
-                                        data_idx = 1;
-                                    }
-
-                                    if variants[data_idx].args.len() == 1 {
-                                        match variants[data_idx].args[0].sty {
-                                            TyBareFn(..) => { res = res - TC::ReachesFfiUnsafe; }
-                                            _ => { }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-
-
                     apply_lang_items(cx, did, res)
                 }
 
@@ -4264,14 +4190,6 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
             result
         }
 
-        fn tc_mt<'tcx>(cx: &ctxt<'tcx>,
-                       mt: TypeAndMut<'tcx>,
-                       cache: &mut FnvHashMap<Ty<'tcx>, TypeContents>) -> TypeContents
-        {
-            let mc = TC::ReachesMutable.when(mt.mutbl == MutMutable);
-            mc | tc_ty(cx, mt.ty, cache)
-        }
-
         fn apply_lang_items(cx: &ctxt, did: ast::DefId, tc: TypeContents)
                             -> TypeContents {
             if Some(did) == cx.lang_items.unsafe_cell_type() {
@@ -4280,32 +4198,6 @@ fn apply_lang_items(cx: &ctxt, did: ast::DefId, tc: TypeContents)
                 tc
             }
         }
-
-        /// Type contents due to containing a reference with
-        /// the region `region` and borrow kind `bk`.
-        fn borrowed_contents(region: ty::Region,
-                             mutbl: ast::Mutability)
-                             -> TypeContents {
-            let b = match mutbl {
-                ast::MutMutable => TC::ReachesMutable,
-                ast::MutImmutable => TC::None,
-            };
-            b | (TC::ReachesBorrowed).when(region != ty::ReStatic)
-        }
-
-        fn object_contents(bounds: &ExistentialBounds) -> TypeContents {
-            // These are the type contents of the (opaque) interior. We
-            // make no assumptions (other than that it cannot have an
-            // in-scope type parameter within, which makes no sense).
-            let mut tc = TC::All - TC::InteriorParam;
-            for bound in &bounds.builtin_bounds {
-                tc = tc - match bound {
-                    BoundSync | BoundSend | BoundCopy => TC::None,
-                    BoundSized => TC::Nonsized,
-                };
-            }
-            return tc;
-        }
     }
 
     fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
@@ -4399,10 +4291,6 @@ fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
         result
     }
 
-    pub fn is_ffi_safe(&'tcx self, cx: &ctxt<'tcx>) -> bool {
-        !self.type_contents(cx).intersects(TC::ReachesFfiUnsafe)
-    }
-
     // True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
     pub fn is_instantiable(&'tcx self, cx: &ctxt<'tcx>) -> bool {
         fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<DefId>,
index ae95466e6e675e4fd60682262ed02f8317c0ba5e..6289d50588104bbffa0baf63dd9379b38862e535 100644 (file)
 #![allow(deprecated)]
 
 use metadata::{csearch, decoder};
+use middle::{cfg, def, infer, pat_util, stability, traits};
 use middle::def::*;
-use middle::infer;
 use middle::subst::Substs;
 use middle::ty::{self, Ty};
-use middle::traits;
-use middle::{def, pat_util, stability};
 use middle::const_eval::{eval_const_expr_partial, ConstVal};
 use middle::const_eval::EvalHint::ExprTypeChecked;
-use middle::cfg;
 use rustc::ast_map;
-use util::nodemap::{FnvHashMap, NodeSet};
+use util::nodemap::{FnvHashMap, FnvHashSet, NodeSet};
 use lint::{Level, Context, LintPass, LintArray, Lint};
 
 use std::collections::{HashSet, BitSet};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::{cmp, slice};
 use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
+use std::rc::Rc;
 
 use syntax::{abi, ast};
 use syntax::ast_util::{self, is_shift_binop, local_def};
@@ -405,43 +403,288 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
     cx: &'a Context<'a, 'tcx>
 }
 
+enum FfiResult {
+    FfiSafe,
+    FfiUnsafe(&'static str),
+    FfiBadStruct(ast::DefId, &'static str),
+    FfiBadEnum(ast::DefId, &'static str)
+}
+
+/// Check if this enum can be safely exported based on the
+/// "nullable pointer optimization". Currently restricted
+/// to function pointers and references, but could be
+/// expanded to cover NonZero raw pointers and newtypes.
+/// FIXME: This duplicates code in trans.
+fn is_repr_nullable_ptr<'tcx>(variants: &Vec<Rc<ty::VariantInfo<'tcx>>>) -> bool {
+    if variants.len() == 2 {
+        let mut data_idx = 0;
+
+        if variants[0].args.is_empty() {
+            data_idx = 1;
+        } else if !variants[1].args.is_empty() {
+            return false;
+        }
+
+        if variants[data_idx].args.len() == 1 {
+            match variants[data_idx].args[0].sty {
+                ty::TyBareFn(None, _) => { return true; }
+                ty::TyRef(..) => { return true; }
+                _ => { }
+            }
+        }
+    }
+    false
+}
+
 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
-    fn check_def(&mut self, sp: Span, id: ast::NodeId) {
-        match self.cx.tcx.def_map.borrow().get(&id).unwrap().full_def() {
-            def::DefPrimTy(ast::TyInt(ast::TyIs)) => {
-                self.cx.span_lint(IMPROPER_CTYPES, sp,
-                                  "found rust type `isize` in foreign module, while \
-                                   libc::c_int or libc::c_long should be used");
+    /// Check if the given type is "ffi-safe" (has a stable, well-defined
+    /// representation which can be exported to C code).
+    fn check_type_for_ffi(&self,
+                          cache: &mut FnvHashSet<Ty<'tcx>>,
+                          ty: Ty<'tcx>)
+                          -> FfiResult {
+        use self::FfiResult::*;
+        let cx = &self.cx.tcx;
+
+        // Protect against infinite recursion, for example
+        // `struct S(*mut S);`.
+        // FIXME: A recursion limit is necessary as well, for irregular
+        // recusive types.
+        if !cache.insert(ty) {
+            return FfiSafe;
+        }
+
+        match ty.sty {
+            ty::TyStruct(did, substs) => {
+                if !cx.lookup_repr_hints(did).contains(&attr::ReprExtern) {
+                    return FfiUnsafe(
+                        "found struct without foreign-function-safe \
+                         representation annotation in foreign module, \
+                         consider adding a #[repr(C)] attribute to \
+                         the type");
+                }
+
+                // We can't completely trust repr(C) markings; make sure the
+                // fields are actually safe.
+                let fields = cx.struct_fields(did, substs);
+
+                if fields.is_empty() {
+                    return FfiUnsafe(
+                        "found zero-size struct in foreign module, consider \
+                         adding a member to this struct");
+                }
+
+                for field in fields {
+                    let field_ty = infer::normalize_associated_type(cx, &field.mt.ty);
+                    let r = self.check_type_for_ffi(cache, field_ty);
+                    match r {
+                        FfiSafe => {}
+                        FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
+                        FfiUnsafe(s) => { return FfiBadStruct(did, s); }
+                    }
+                }
+                FfiSafe
             }
-            def::DefPrimTy(ast::TyUint(ast::TyUs)) => {
-                self.cx.span_lint(IMPROPER_CTYPES, sp,
-                                  "found rust type `usize` in foreign module, while \
-                                   libc::c_uint or libc::c_ulong should be used");
+            ty::TyEnum(did, substs) => {
+                let variants = cx.substd_enum_variants(did, substs);
+                if variants.is_empty() {
+                    // Empty enums are okay... although sort of useless.
+                    return FfiSafe
+                }
+
+                // Check for a repr() attribute to specify the size of the
+                // discriminant.
+                let repr_hints = cx.lookup_repr_hints(did);
+                match &**repr_hints {
+                    [] => {
+                        // Special-case types like `Option<extern fn()>`.
+                        if !is_repr_nullable_ptr(&variants) {
+                            return FfiUnsafe(
+                                "found enum without foreign-function-safe \
+                                 representation annotation in foreign module, \
+                                 consider adding a #[repr(...)] attribute to \
+                                 the type")
+                        }
+                    }
+                    [ref hint] => {
+                        if !hint.is_ffi_safe() {
+                            // FIXME: This shouldn't be reachable: we should check
+                            // this earlier.
+                            return FfiUnsafe(
+                                "enum has unexpected #[repr(...)] attribute")
+                        }
+
+                        // Enum with an explicitly sized discriminant; either
+                        // a C-style enum or a discriminated union.
+
+                        // The layout of enum variants is implicitly repr(C).
+                        // FIXME: Is that correct?
+                    }
+                    _ => {
+                        // FIXME: This shouldn't be reachable: we should check
+                        // this earlier.
+                        return FfiUnsafe(
+                            "enum has too many #[repr(...)] attributes");
+                    }
+                }
+
+                // Check the contained variants.
+                for variant in variants {
+                    for arg in &variant.args {
+                        let arg = infer::normalize_associated_type(cx, arg);
+                        let r = self.check_type_for_ffi(cache, arg);
+                        match r {
+                            FfiSafe => {}
+                            FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
+                            FfiUnsafe(s) => { return FfiBadEnum(did, s); }
+                        }
+                    }
+                }
+                FfiSafe
+            }
+
+            ty::TyInt(ast::TyIs) => {
+                FfiUnsafe("found Rust type `isize` in foreign module, while \
+                          `libc::c_int` or `libc::c_long` should be used")
+            }
+            ty::TyUint(ast::TyUs) => {
+                FfiUnsafe("found Rust type `usize` in foreign module, while \
+                          `libc::c_uint` or `libc::c_ulong` should be used")
+            }
+            ty::TyChar => {
+                FfiUnsafe("found Rust type `char` in foreign module, while \
+                           `u32` or `libc::wchar_t` should be used")
+            }
+
+            // Primitive types with a stable representation.
+            ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
+            ty::TyFloat(..) => FfiSafe,
+
+            ty::TyBox(..) => {
+                FfiUnsafe("found Rust type Box<_> in foreign module, \
+                           consider using a raw pointer instead")
+            }
+
+            ty::TySlice(_) => {
+                FfiUnsafe("found Rust slice type in foreign module, \
+                           consider using a raw pointer instead")
+            }
+
+            ty::TyTrait(..) => {
+                FfiUnsafe("found Rust trait type in foreign module, \
+                           consider using a raw pointer instead")
+            }
+
+            ty::TyStr => {
+                FfiUnsafe("found Rust type `str` in foreign module; \
+                           consider using a `*const libc::c_char`")
             }
-            def::DefTy(..) => {
-                let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
-                    Some(&t) => t,
-                    None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
-                };
 
-                if !tty.is_ffi_safe(self.cx.tcx) {
-                    self.cx.span_lint(IMPROPER_CTYPES, sp,
-                                      "found type without foreign-function-safe \
-                                       representation annotation in foreign module, consider \
-                                       adding a #[repr(...)] attribute to the type");
+            ty::TyTuple(_) => {
+                FfiUnsafe("found Rust tuple type in foreign module; \
+                           consider using a struct instead`")
+            }
+
+            ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => {
+                self.check_type_for_ffi(cache, m.ty)
+            }
+
+            ty::TyArray(ty, _) => {
+                self.check_type_for_ffi(cache, ty)
+            }
+
+            ty::TyBareFn(None, bare_fn) => {
+                match bare_fn.abi {
+                    abi::Rust |
+                    abi::RustIntrinsic |
+                    abi::RustCall => {
+                        return FfiUnsafe(
+                            "found function pointer with Rust calling \
+                             convention in foreign module; consider using an \
+                             `extern` function pointer")
+                    }
+                    _ => {}
                 }
+
+                let sig = cx.erase_late_bound_regions(&bare_fn.sig);
+                match sig.output {
+                    ty::FnDiverging => {}
+                    ty::FnConverging(output) => {
+                        if !output.is_nil() {
+                            let r = self.check_type_for_ffi(cache, output);
+                            match r {
+                                FfiSafe => {}
+                                _ => { return r; }
+                            }
+                        }
+                    }
+                }
+                for arg in sig.inputs {
+                    let r = self.check_type_for_ffi(cache, arg);
+                    match r {
+                        FfiSafe => {}
+                        _ => { return r; }
+                    }
+                }
+                FfiSafe
+            }
+
+            ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
+            ty::TyClosure(..) | ty::TyProjection(..) |
+            ty::TyBareFn(Some(_), _) => {
+                panic!("Unexpected type in foreign function")
+            }
+        }
+    }
+
+    fn check_def(&mut self, sp: Span, id: ast::NodeId) {
+        let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
+            Some(&t) => t,
+            None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
+        };
+        let tty = infer::normalize_associated_type(self.cx.tcx, &tty);
+
+        match ImproperCTypesVisitor::check_type_for_ffi(self, &mut FnvHashSet(), tty) {
+            FfiResult::FfiSafe => {}
+            FfiResult::FfiUnsafe(s) => {
+                self.cx.span_lint(IMPROPER_CTYPES, sp, s);
+            }
+            FfiResult::FfiBadStruct(_, s) => {
+                // 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));
+            }
+            FfiResult::FfiBadEnum(_, s) => {
+                // 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));
             }
-            _ => ()
         }
     }
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> {
     fn visit_ty(&mut self, ty: &ast::Ty) {
-        if let ast::TyPath(..) = ty.node {
-            self.check_def(ty.span, ty.id);
+        match ty.node {
+            ast::TyPath(..) |
+            ast::TyBareFn(..) => self.check_def(ty.span, ty.id),
+            ast::TyVec(..) => {
+                self.cx.span_lint(IMPROPER_CTYPES, ty.span,
+                    "found Rust slice type in foreign module, consider \
+                     using a raw pointer instead");
+            }
+            ast::TyFixedLengthVec(ref ty, _) => self.visit_ty(ty),
+            ast::TyTup(..) => {
+                self.cx.span_lint(IMPROPER_CTYPES, ty.span,
+                    "found Rust tuple type in foreign module; \
+                     consider using a struct instead`")
+            }
+            _ => visit::walk_ty(self, ty)
         }
-        visit::walk_ty(self, ty);
     }
 }
 
index 54c1a79e10a9b709a43e8ea5c05d2dce6fd2f6dc..8d6dfb929873064aad959f9c7275ea910d01efb8 100644 (file)
@@ -38,6 +38,7 @@
 #![feature(ref_slice)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
+#![feature(slice_patterns)]
 #![feature(staged_api)]
 #![feature(str_char)]
 
index 83f8619c5eeabd1e2976b976eae81da9891b3adf..9ee046915daca66a4a526b90df3cc8d64998e46f 100644 (file)
@@ -685,7 +685,7 @@ pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint)
     pub fn LLVMGetArrayLength(ArrayTy: TypeRef) -> c_uint;
     pub fn LLVMGetPointerAddressSpace(PointerTy: TypeRef) -> c_uint;
     pub fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef, V: ValueRef)
-                                  -> *const ();
+                                  -> *const c_void;
     pub fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint;
 
     /* Operations on other types */
index 97fd7f99d197e4714f3f08ad5466020a12bb4486..21078641c1f536ccd7c917a1c926e30633d2220e 100644 (file)
@@ -13,6 +13,7 @@
 use std::os::windows::prelude::*;
 use std::ops::RangeFrom;
 use libc::{DWORD, LPCWSTR, LONG, LPDWORD, LPBYTE, ERROR_SUCCESS};
+use libc::c_void;
 
 const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
 const KEY_WOW64_32KEY: REGSAM = 0x0200;
@@ -32,7 +33,7 @@ enum __HKEY__ {}
 pub type PHKEY = *mut HKEY;
 pub type REGSAM = DWORD;
 pub type LPWSTR = *mut u16;
-pub type PFILETIME = *mut ();
+pub type PFILETIME = *mut c_void;
 
 #[link(name = "advapi32")]
 extern "system" {
index 87941e79b2f7d79e6d2aa87b1454172ea9035be9..59fc8df6107310367ceeb26cc8cb34be05d7e291 100644 (file)
@@ -251,12 +251,11 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::{c_void, c_int};
 
-    #[repr(C)]
-    pub struct EXCEPTION_RECORD;
-    #[repr(C)]
-    pub struct CONTEXT;
-    #[repr(C)]
-    pub struct DISPATCHER_CONTEXT;
+    // Fake definitions; these are actually complicated structs,
+    // but we don't use the contents here.
+    pub type EXCEPTION_RECORD = c_void;
+    pub type CONTEXT = c_void;
+    pub type DISPATCHER_CONTEXT = c_void;
 
     #[repr(C)]
     #[derive(Copy, Clone)]
index cf827848db5c99f0f70de6295220a007ecb4fb76..491b53c4ed95ca06ea2c41f1e4398d599cd46f03 100644 (file)
@@ -82,6 +82,7 @@ pub unsafe fn make_handler() -> Handler {
     Handler { _data: 0 as *mut libc::c_void }
 }
 
+#[repr(C)]
 pub struct EXCEPTION_RECORD {
     pub ExceptionCode: DWORD,
     pub ExceptionFlags: DWORD,
@@ -91,6 +92,7 @@ pub struct EXCEPTION_RECORD {
     pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
 }
 
+#[repr(C)]
 pub struct EXCEPTION_POINTERS {
     pub ExceptionRecord: *mut EXCEPTION_RECORD,
     pub ContextRecord: LPVOID
index e2873601a7b6638e2463a932483e19cbaca0859d..11b375dcce2f4c20a3581019cd20d898785bd716 100644 (file)
@@ -335,13 +335,13 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
             #[linkage = "extern_weak"]
             static __dso_handle: *mut u8;
             #[linkage = "extern_weak"]
-            static __cxa_thread_atexit_impl: *const ();
+            static __cxa_thread_atexit_impl: *const libc::c_void;
         }
         if !__cxa_thread_atexit_impl.is_null() {
             type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
                                       arg: *mut u8,
                                       dso_handle: *mut u8) -> libc::c_int;
-            mem::transmute::<*const (), F>(__cxa_thread_atexit_impl)
+            mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
             (dtor, t, &__dso_handle as *const _ as *mut _);
             return
         }
index 9225889ef6348df7df644b98304b1b30162d4947..56261c34a030850e1fe3938347797c2e01ca2838 100644 (file)
@@ -37,7 +37,7 @@ struct D {
 }
 
 extern "C" {
-    fn foo(x: A); //~ ERROR found type without foreign-function-safe
+    fn foo(x: A); //~ ERROR found struct without foreign-function-safe
     fn bar(x: B); //~ ERROR foreign-function-safe
     fn baz(x: C);
     fn qux(x: A2); //~ ERROR foreign-function-safe
index c886c97a63607bc43143181b5f06e2f8336bb1ed..b5aa3568122ad49108a03ec12f87ce6bc3fb9175 100644 (file)
@@ -11,7 +11,7 @@
 #![deny(warnings)]
 
 extern {
-    pub fn foo(x: (isize)); //~ ERROR found rust type `isize` in foreign module
+    pub fn foo(x: (isize)); //~ ERROR found Rust type `isize` in foreign module
 }
 
 fn main() {
index dea933085de4e0c098e6a5a0790f8b2e9c487fb2..e35dadbea9d4d16429de2519f318e91524d8c080 100644 (file)
@@ -18,9 +18,9 @@ enum T { E, F, G }
 
 extern {
    fn zf(x: Z);
-   fn uf(x: U); //~ ERROR found type without foreign-function-safe
-   fn bf(x: B); //~ ERROR found type without foreign-function-safe
-   fn tf(x: T); //~ ERROR found type without foreign-function-safe
+   fn uf(x: U); //~ ERROR found enum without foreign-function-safe
+   fn bf(x: B); //~ ERROR found enum without foreign-function-safe
+   fn tf(x: T); //~ ERROR found enum without foreign-function-safe
 }
 
 pub fn main() { }
index 3f25e9c7b76aac34ea92298574f4584b3faf16c2..614f8e6fde81a966cd2244471a062024e07b3922 100644 (file)
 
 extern crate libc;
 
+trait Mirror { type It; }
+impl<T> Mirror for T { type It = Self; }
+#[repr(C)]
+pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
+#[repr(C)]
+pub struct StructWithProjectionAndLifetime<'a>(
+    &'a mut <StructWithProjectionAndLifetime<'a> as Mirror>::It
+);
+pub type I32Pair = (i32, i32);
+#[repr(C)]
+pub struct ZeroSize;
+pub type RustFn = fn();
+pub type RustBadRet = extern fn() -> Box<u32>;
+
 extern {
-    pub fn bare_type1(size: isize); //~ ERROR: found rust type
-    pub fn bare_type2(size: usize); //~ ERROR: found rust type
-    pub fn ptr_type1(size: *const isize); //~ ERROR: found rust type
-    pub fn ptr_type2(size: *const usize); //~ ERROR: found rust type
+    pub fn bare_type1(size: isize); //~ ERROR: found Rust type
+    pub fn bare_type2(size: usize); //~ ERROR: found Rust type
+    pub fn ptr_type1(size: *const isize); //~ ERROR: found Rust type
+    pub fn ptr_type2(size: *const usize); //~ ERROR: found Rust type
+    pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type
+    pub fn str_type(p: &str); //~ ERROR: found Rust type
+    pub fn box_type(p: Box<u32>); //~ ERROR found Rust type
+    pub fn char_type(p: char); //~ ERROR found Rust type
+    pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type
+    pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type
+    pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type
+    pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct
+    pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust
+    pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust
+    pub fn fn_contained(p: RustBadRet); //~ ERROR: found Rust type
 
     pub fn good1(size: *const libc::c_int);
     pub fn good2(size: *const libc::c_uint);
+    pub fn good3(fptr: Option<extern fn()>);
+    pub fn good4(aptr: &[u8; 4 as usize]);
+    pub fn good5(s: StructWithProjection);
+    pub fn good6(s: StructWithProjectionAndLifetime);
+    pub fn good7(fptr: extern fn() -> ());
+    pub fn good8(fptr: extern fn() -> !);
 }
 
 fn main() {
index 9ff0f011e1dc795f622c6fae10d52b37dca5ad87..b77f25a0a344f6151c4daab2c1c0231de9079811 100644 (file)
@@ -13,9 +13,9 @@
 
 mod xx {
     extern {
-        pub fn strlen(str: *const u8) -> usize; //~ ERROR found rust type `usize`
-        pub fn foo(x: isize, y: usize); //~ ERROR found rust type `isize`
-        //~^ ERROR found rust type `usize`
+        pub fn strlen(str: *const u8) -> usize; //~ ERROR found Rust type `usize`
+        pub fn foo(x: isize, y: usize); //~ ERROR found Rust type `isize`
+        //~^ ERROR found Rust type `usize`
     }
 }
 
index 8af3844e62eefdee3de563b9c759018b42101a84..771fce31023e13f6a2fd5d115e5dbe6556f13514 100644 (file)
@@ -9,7 +9,9 @@
 // except according to those terms.
 
 #![feature(rustc_private)]
+#![feature(libc)]
 
+extern crate libc;
 extern crate rustc;
 extern crate rustc_driver;
 extern crate rustc_lint;
@@ -29,6 +31,7 @@
 use rustc::session::build_session;
 use rustc_driver::driver;
 use rustc_resolve::MakeGlobMap;
+use libc::c_void;
 
 use syntax::diagnostics::registry::Registry;
 
@@ -111,7 +114,7 @@ pub fn add_module(&mut self, program: &str) {
     }
 
     /// Returns a raw pointer to the named function.
-    pub fn get_function(&mut self, name: &str) -> Option<*const ()> {
+    pub fn get_function(&mut self, name: &str) -> Option<*const c_void> {
         let s = CString::new(name.as_bytes()).unwrap();
 
         for &m in &self.modules {
@@ -128,7 +131,7 @@ pub fn get_function(&mut self, name: &str) -> Option<*const ()> {
     }
 
     /// Returns a raw pointer to the named global item.
-    pub fn get_global(&mut self, name: &str) -> Option<*const ()> {
+    pub fn get_global(&mut self, name: &str) -> Option<*const c_void> {
         let s = CString::new(name.as_bytes()).unwrap();
 
         for &m in &self.modules {