Lint non-FFI-safe enums.
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
//! Context itself, span_lint should be used instead of add_lint.
|
//! Context itself, span_lint should be used instead of add_lint.
|
||||||
|
|
||||||
use driver::session;
|
use driver::session;
|
||||||
|
use middle::trans::adt; // for `adt::is_ffi_safe`
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::pat_util;
|
use middle::pat_util;
|
||||||
use metadata::csearch;
|
use metadata::csearch;
|
||||||
@@ -627,6 +628,14 @@ fn check_item_ctypes(cx: &Context, it: &ast::item) {
|
|||||||
"found rust type `uint` in foreign module, while \
|
"found rust type `uint` in foreign module, while \
|
||||||
libc::c_uint or libc::c_ulong should be used");
|
libc::c_uint or libc::c_ulong should be used");
|
||||||
}
|
}
|
||||||
|
ast::DefTy(def_id) => {
|
||||||
|
if !adt::is_ffi_safe(cx.tcx, def_id) {
|
||||||
|
cx.span_lint(ctypes, ty.span,
|
||||||
|
"found enum type without foreign-function-safe \
|
||||||
|
representation annotation in foreign module");
|
||||||
|
// NOTE this message could be more helpful
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,22 +145,8 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
|
|||||||
return Univariant(mk_struct(cx, ftys, packed), dtor)
|
return Univariant(mk_struct(cx, ftys, packed), dtor)
|
||||||
}
|
}
|
||||||
ty::ty_enum(def_id, ref substs) => {
|
ty::ty_enum(def_id, ref substs) => {
|
||||||
struct Case { discr: Disr, tys: ~[ty::t] };
|
let cases = get_cases(cx.tcx, def_id, substs);
|
||||||
impl Case {
|
let hint = ty::lookup_repr_hint(cx.tcx, def_id);
|
||||||
fn is_zerolen(&self, cx: &mut CrateContext) -> bool {
|
|
||||||
mk_struct(cx, self.tys, false).size == 0
|
|
||||||
}
|
|
||||||
fn find_ptr(&self) -> Option<uint> {
|
|
||||||
self.tys.iter().position(|&ty| mono_data_classify(ty) == MonoNonNull)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let cases = do ty::enum_variants(cx.tcx, def_id).map |vi| {
|
|
||||||
let arg_tys = do vi.args.map |&raw_ty| {
|
|
||||||
ty::subst(cx.tcx, substs, raw_ty)
|
|
||||||
};
|
|
||||||
Case { discr: vi.disr_val, tys: arg_tys }
|
|
||||||
};
|
|
||||||
|
|
||||||
if cases.len() == 0 {
|
if cases.len() == 0 {
|
||||||
// Uninhabitable; represent as unit
|
// Uninhabitable; represent as unit
|
||||||
@@ -170,7 +156,6 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
|
|||||||
if cases.iter().all(|c| c.tys.len() == 0) {
|
if cases.iter().all(|c| c.tys.len() == 0) {
|
||||||
// All bodies empty -> intlike
|
// All bodies empty -> intlike
|
||||||
let discrs = cases.map(|c| c.discr);
|
let discrs = cases.map(|c| c.discr);
|
||||||
let hint = ty::lookup_repr_hint(cx.tcx, def_id);
|
|
||||||
let bounds = IntBounds {
|
let bounds = IntBounds {
|
||||||
ulo: *discrs.iter().min().unwrap(),
|
ulo: *discrs.iter().min().unwrap(),
|
||||||
uhi: *discrs.iter().max().unwrap(),
|
uhi: *discrs.iter().max().unwrap(),
|
||||||
@@ -232,6 +217,56 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determine, without doing translation, whether an ADT must be FFI-safe.
|
||||||
|
/// For use in lint or similar, where being sound but slightly incomplete is acceptable.
|
||||||
|
pub fn is_ffi_safe(tcx: ty::ctxt, def_id: ast::DefId) -> bool {
|
||||||
|
match ty::get(ty::lookup_item_type(tcx, def_id).ty).sty {
|
||||||
|
ty::ty_enum(def_id, ref substs) => {
|
||||||
|
let cases = get_cases(tcx, def_id, substs);
|
||||||
|
// Univariant => like struct/tuple.
|
||||||
|
if cases.len() <= 2 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let hint = ty::lookup_repr_hint(tcx, def_id);
|
||||||
|
// Appropriate representation explicitly selected?
|
||||||
|
if hint.is_ffi_safe() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Conservative approximation of nullable pointers, for Option<~T> etc.
|
||||||
|
if cases.len() == 2 && hint == attr::ReprAny &&
|
||||||
|
(cases[0].tys.is_empty() && cases[1].find_ptr().is_some() ||
|
||||||
|
cases[1].tys.is_empty() && cases[0].find_ptr().is_some()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// struct, tuple, etc.
|
||||||
|
// (is this right in the present of typedefs?)
|
||||||
|
_ => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE this should probably all be in ty
|
||||||
|
struct Case { discr: Disr, tys: ~[ty::t] }
|
||||||
|
impl Case {
|
||||||
|
fn is_zerolen(&self, cx: &mut CrateContext) -> bool {
|
||||||
|
mk_struct(cx, self.tys, false).size == 0
|
||||||
|
}
|
||||||
|
fn find_ptr(&self) -> Option<uint> {
|
||||||
|
self.tys.iter().position(|&ty| mono_data_classify(ty) == MonoNonNull)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cases(tcx: ty::ctxt, def_id: ast::DefId, substs: &ty::substs) -> ~[Case] {
|
||||||
|
do ty::enum_variants(tcx, def_id).map |vi| {
|
||||||
|
let arg_tys = do vi.args.map |&raw_ty| {
|
||||||
|
ty::subst(tcx, substs, raw_ty)
|
||||||
|
};
|
||||||
|
Case { discr: vi.disr_val, tys: arg_tys }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn mk_struct(cx: &mut CrateContext, tys: &[ty::t], packed: bool) -> Struct {
|
fn mk_struct(cx: &mut CrateContext, tys: &[ty::t], packed: bool) -> Struct {
|
||||||
let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty));
|
let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty));
|
||||||
let llty_rec = Type::struct_(lltys, packed);
|
let llty_rec = Type::struct_(lltys, packed);
|
||||||
|
|||||||
@@ -442,6 +442,16 @@ pub enum ReprAttr {
|
|||||||
ReprExtern
|
ReprExtern
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ReprAttr {
|
||||||
|
pub fn is_ffi_safe(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
ReprAny => false,
|
||||||
|
ReprInt(_sp, ity) => ity.is_ffi_safe(),
|
||||||
|
ReprExtern => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[deriving(Eq)]
|
#[deriving(Eq)]
|
||||||
pub enum IntType {
|
pub enum IntType {
|
||||||
SignedInt(ast::int_ty),
|
SignedInt(ast::int_ty),
|
||||||
@@ -456,4 +466,13 @@ impl IntType {
|
|||||||
UnsignedInt(*) => false
|
UnsignedInt(*) => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn is_ffi_safe(self) -> bool {
|
||||||
|
match self {
|
||||||
|
SignedInt(ast::ty_i8) | UnsignedInt(ast::ty_u8) |
|
||||||
|
SignedInt(ast::ty_i16) | UnsignedInt(ast::ty_u16) |
|
||||||
|
SignedInt(ast::ty_i32) | UnsignedInt(ast::ty_u32) |
|
||||||
|
SignedInt(ast::ty_i64) | UnsignedInt(ast::ty_u64) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user