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.
This commit is contained in:
Eli Friedman 2015-06-25 14:48:36 -07:00
parent d4d4206e56
commit 6fa17b43d3
14 changed files with 349 additions and 181 deletions
src
librustc/middle
librustc_lint
librustc_llvm
librustc_trans/back/msvc
libstd
rt/unwind
sys/windows
thread
test

@ -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<T, F>(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<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 @@ 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<DefId>,

@ -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>
}
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");
}
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");
}
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!")
};
enum FfiResult {
FfiSafe,
FfiUnsafe(&'static str),
FfiBadStruct(ast::DefId, &'static str),
FfiBadEnum(ast::DefId, &'static str)
}
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");
}
/// 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> {
/// 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
}
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`")
}
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);
}
}

@ -38,6 +38,7 @@
#![feature(ref_slice)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(str_char)]

@ -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 */

@ -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" {

@ -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)]

@ -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

@ -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
}

@ -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

@ -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() {

@ -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() { }

@ -13,14 +13,45 @@
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() {

@ -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`
}
}

@ -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 {