From 6fa17b43d351ed4f9093cf80f4044d1208044241 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Thu, 25 Jun 2015 14:48:36 -0700 Subject: [PATCH] Rewrite the improper_ctypes lint. 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. --- src/librustc/middle/ty.rs | 136 +------- src/librustc_lint/builtin.rs | 301 ++++++++++++++++-- src/librustc_lint/lib.rs | 1 + src/librustc_llvm/lib.rs | 2 +- src/librustc_trans/back/msvc/registry.rs | 3 +- src/libstd/rt/unwind/gcc.rs | 11 +- src/libstd/sys/windows/stack_overflow.rs | 2 + src/libstd/thread/local.rs | 4 +- src/test/compile-fail/issue-14309.rs | 2 +- src/test/compile-fail/issue-16250.rs | 2 +- src/test/compile-fail/lint-ctypes-enum.rs | 6 +- src/test/compile-fail/lint-ctypes.rs | 39 ++- .../compile-fail/warn-foreign-int-types.rs | 6 +- src/test/run-make/execution-engine/test.rs | 7 +- 14 files changed, 345 insertions(+), 177 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 17a76f6eed9c5..64e707f6264e6 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3967,7 +3967,6 @@ def_type_content_sets! { 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 @@ def_type_content_sets! { 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 @@ impl TypeContents { 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 @@ impl TypeContents { 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(v: &[T], mut f: F) -> TypeContents where @@ -4129,7 +4099,7 @@ impl<'tcx> TyS<'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 @@ impl<'tcx> TyS<'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 @@ impl<'tcx> TyS<'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 @@ impl<'tcx> TyS<'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 @@ impl<'tcx> TyS<'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 @@ impl<'tcx> TyS<'tcx> { result } - fn tc_mt<'tcx>(cx: &ctxt<'tcx>, - mt: TypeAndMut<'tcx>, - cache: &mut FnvHashMap, 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 @@ impl<'tcx> TyS<'tcx> { 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 @@ impl<'tcx> TyS<'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, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ae95466e6e675..6289d50588104 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -32,23 +32,21 @@ #![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>>) -> 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: 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`. + 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); } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 54c1a79e10a9b..8d6dfb9298730 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -38,6 +38,7 @@ #![feature(ref_slice)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] +#![feature(slice_patterns)] #![feature(staged_api)] #![feature(str_char)] diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 83f8619c5eeab..9ee046915daca 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -685,7 +685,7 @@ extern { 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 */ diff --git a/src/librustc_trans/back/msvc/registry.rs b/src/librustc_trans/back/msvc/registry.rs index 97fd7f99d197e..21078641c1f53 100644 --- a/src/librustc_trans/back/msvc/registry.rs +++ b/src/librustc_trans/back/msvc/registry.rs @@ -13,6 +13,7 @@ use std::ffi::{OsString, OsStr}; 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 @@ pub type HKEY = *mut __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" { diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/rt/unwind/gcc.rs index 87941e79b2f7d..59fc8df610731 100644 --- a/src/libstd/rt/unwind/gcc.rs +++ b/src/libstd/rt/unwind/gcc.rs @@ -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)] diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs index cf827848db5c9..491b53c4ed95c 100644 --- a/src/libstd/sys/windows/stack_overflow.rs +++ b/src/libstd/sys/windows/stack_overflow.rs @@ -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 diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index e2873601a7b66..11b375dcce2f4 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -335,13 +335,13 @@ mod imp { #[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 } diff --git a/src/test/compile-fail/issue-14309.rs b/src/test/compile-fail/issue-14309.rs index 9225889ef6348..56261c34a0308 100644 --- a/src/test/compile-fail/issue-14309.rs +++ b/src/test/compile-fail/issue-14309.rs @@ -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 diff --git a/src/test/compile-fail/issue-16250.rs b/src/test/compile-fail/issue-16250.rs index c886c97a63607..b5aa3568122ad 100644 --- a/src/test/compile-fail/issue-16250.rs +++ b/src/test/compile-fail/issue-16250.rs @@ -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() { diff --git a/src/test/compile-fail/lint-ctypes-enum.rs b/src/test/compile-fail/lint-ctypes-enum.rs index dea933085de4e..e35dadbea9d4d 100644 --- a/src/test/compile-fail/lint-ctypes-enum.rs +++ b/src/test/compile-fail/lint-ctypes-enum.rs @@ -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() { } diff --git a/src/test/compile-fail/lint-ctypes.rs b/src/test/compile-fail/lint-ctypes.rs index 3f25e9c7b76aa..614f8e6fde81a 100644 --- a/src/test/compile-fail/lint-ctypes.rs +++ b/src/test/compile-fail/lint-ctypes.rs @@ -13,14 +13,45 @@ extern crate libc; +trait Mirror { type It; } +impl Mirror for T { type It = Self; } +#[repr(C)] +pub struct StructWithProjection(*mut ::It); +#[repr(C)] +pub struct StructWithProjectionAndLifetime<'a>( + &'a mut as Mirror>::It +); +pub type I32Pair = (i32, i32); +#[repr(C)] +pub struct ZeroSize; +pub type RustFn = fn(); +pub type RustBadRet = extern fn() -> Box; + 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); //~ 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); + 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() { diff --git a/src/test/compile-fail/warn-foreign-int-types.rs b/src/test/compile-fail/warn-foreign-int-types.rs index 9ff0f011e1dc7..b77f25a0a344f 100644 --- a/src/test/compile-fail/warn-foreign-int-types.rs +++ b/src/test/compile-fail/warn-foreign-int-types.rs @@ -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` } } diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 8af3844e62eef..771fce31023e1 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -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::config::{self, basic_options, build_configuration, Input, Op 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 @@ impl ExecutionEngine { } /// 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 @@ impl ExecutionEngine { } /// 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 {