#![allow(non_snake_case)]
-use middle::{infer};
-use middle::def_id::DefId;
-use middle::subst::Substs;
-use middle::ty::{self, Ty};
-use middle::const_eval::{eval_const_expr_partial, ConstVal};
-use middle::const_eval::EvalHint::ExprTypeChecked;
+use rustc::hir::def_id::DefId;
+use rustc::infer;
+use rustc::ty::subst::Substs;
+use rustc::ty::{self, Ty, TyCtxt};
+use middle::const_val::ConstVal;
+use rustc_const_eval::eval_const_expr_partial;
+use rustc_const_eval::EvalHint::ExprTypeChecked;
use util::nodemap::{FnvHashSet};
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::{self, Span};
-use rustc_front::hir;
-use rustc_front::intravisit::{self, Visitor};
-use rustc_front::util::is_shift_binop;
+use rustc::hir;
register_long_diagnostics! {
E0519: r##"
"comparison is useless due to type limits");
}
- if is_shift_binop(binop.node) {
+ if binop.node.is_shift() {
let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty {
ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
else { false }
} else {
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
- Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
- Ok(ConstVal::Uint(shift)) => { shift >= bits },
+ Ok(ConstVal::Integral(i)) => {
+ i.is_negative() || i.to_u64()
+ .map(|i| i >= bits)
+ .unwrap_or(true)
+ },
_ => { false }
}
};
return;
}
}
- _ => panic!()
+ _ => bug!()
};
},
ty::TyUint(t) => {
// _v is u8, within range by definition
ast::LitKind::Byte(_v) => return,
ast::LitKind::Int(v, _) => v,
- _ => panic!()
+ _ => bug!()
};
if lit_val < min || lit_val > max {
cx.span_lint(OVERFLOWING_LITERALS, e.span,
Err(_) => return
}
}
- _ => panic!()
+ _ => bug!()
};
if lit_val < min || lit_val > max {
cx.span_lint(OVERFLOWING_LITERALS, e.span,
hir::BiGt => v >= min && v < max,
hir::BiGe => v > min && v <= max,
hir::BiEq | hir::BiNe => v >= min && v <= max,
- _ => panic!()
+ _ => bug!()
}
}
}
}
- fn check_limits(tcx: &ty::ctxt, binop: hir::BinOp,
+ fn check_limits(tcx: &TyCtxt, binop: hir::BinOp,
l: &hir::Expr, r: &hir::Expr) -> bool {
let (lit, expr, swap) = match (&l.node, &r.node) {
(&hir::ExprLit(_), _) => (l, r, true),
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
_ => return true
},
- _ => panic!()
+ _ => bug!()
};
is_valid(norm_binop, lit_val, min, max)
}
ast::LitKind::Int(v, _) => v,
_ => return true
},
- _ => panic!()
+ _ => bug!()
};
is_valid(norm_binop, lit_val, min, max)
}
/// 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>(tcx: &ty::ctxt<'tcx>,
+fn is_repr_nullable_ptr<'tcx>(tcx: &TyCtxt<'tcx>,
def: ty::AdtDef<'tcx>,
substs: &Substs<'tcx>)
-> bool {
if def.variants[data_idx].fields.len() == 1 {
match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
- ty::TyBareFn(None, _) => { return true; }
+ ty::TyFnPtr(_) => { return true; }
ty::TyRef(..) => { return true; }
_ => { }
}
false
}
-fn ast_ty_to_normalized<'tcx>(tcx: &ty::ctxt<'tcx>,
- id: ast::NodeId)
- -> Ty<'tcx> {
- let tty = match tcx.ast_ty_to_ty_cache.borrow().get(&id) {
- Some(&t) => t,
- None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
- };
- infer::normalize_associated_type(tcx, &tty)
-}
-
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).
self.check_type_for_ffi(cache, ty)
}
- ty::TyBareFn(None, bare_fn) => {
+ ty::TyFnPtr(bare_fn) => {
match bare_fn.abi {
Abi::Rust |
Abi::RustIntrinsic |
ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
ty::TyClosure(..) | ty::TyProjection(..) |
- ty::TyBareFn(Some(_), _) => {
- panic!("Unexpected type in foreign function")
+ ty::TyFnDef(..) => {
+ bug!("Unexpected type in foreign function")
}
}
}
- fn check_def(&mut self, sp: Span, id: ast::NodeId) {
- let tty = ast_ty_to_normalized(self.cx.tcx, id);
+ fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
+ // it is only OK to use this function because extern fns cannot have
+ // any generic types right now:
+ let ty = infer::normalize_associated_type(self.cx.tcx, &ty);
- match ImproperCTypesVisitor::check_type_for_ffi(self, &mut FnvHashSet(), tty) {
+ match self.check_type_for_ffi(&mut FnvHashSet(), ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiUnsafe(s) => {
self.cx.span_lint(IMPROPER_CTYPES, sp, s);
}
}
}
-}
-impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> {
- fn visit_ty(&mut self, ty: &hir::Ty) {
- match ty.node {
- hir::TyPath(..) |
- hir::TyBareFn(..) => self.check_def(ty.span, ty.id),
- hir::TyVec(..) => {
- self.cx.span_lint(IMPROPER_CTYPES, ty.span,
- "found Rust slice type in foreign module, consider \
- using a raw pointer instead");
- }
- hir::TyFixedLengthVec(ref ty, _) => self.visit_ty(ty),
- hir::TyTup(..) => {
- self.cx.span_lint(IMPROPER_CTYPES, ty.span,
- "found Rust tuple type in foreign module; \
- consider using a struct instead`")
+ fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) {
+ let def_id = self.cx.tcx.map.local_def_id(id);
+ let scheme = self.cx.tcx.lookup_item_type(def_id);
+ let sig = scheme.ty.fn_sig();
+ let sig = self.cx.tcx.erase_late_bound_regions(&sig);
+
+ for (&input_ty, input_hir) in sig.inputs.iter().zip(&decl.inputs) {
+ self.check_type_for_ffi_and_report_errors(input_hir.ty.span, &input_ty);
+ }
+
+ if let hir::Return(ref ret_hir) = decl.output {
+ let ret_ty = sig.output.unwrap();
+ if !ret_ty.is_nil() {
+ self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
}
- _ => intravisit::walk_ty(self, ty)
}
}
+
+ fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) {
+ let def_id = self.cx.tcx.map.local_def_id(id);
+ let scheme = self.cx.tcx.lookup_item_type(def_id);
+ self.check_type_for_ffi_and_report_errors(span, scheme.ty);
+ }
}
#[derive(Copy, Clone)]
impl LateLintPass for ImproperCTypes {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
- fn check_ty(cx: &LateContext, ty: &hir::Ty) {
- let mut vis = ImproperCTypesVisitor { cx: cx };
- vis.visit_ty(ty);
- }
-
- fn check_foreign_fn(cx: &LateContext, decl: &hir::FnDecl) {
- for input in &decl.inputs {
- check_ty(cx, &input.ty);
- }
- if let hir::Return(ref ret_ty) = decl.output {
- let tty = ast_ty_to_normalized(cx.tcx, ret_ty.id);
- if !tty.is_nil() {
- check_ty(cx, &ret_ty);
- }
- }
- }
-
+ let mut vis = ImproperCTypesVisitor { cx: cx };
if let hir::ItemForeignMod(ref nmod) = it.node {
if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
for ni in &nmod.items {
match ni.node {
- hir::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &decl),
- hir::ForeignItemStatic(ref t, _) => check_ty(cx, &t)
+ hir::ForeignItemFn(ref decl, _) => {
+ vis.check_foreign_fn(ni.id, decl);
+ }
+ hir::ForeignItemStatic(ref ty, _) => {
+ vis.check_foreign_static(ni.id, ty.span);
+ }
}
}
}