use syntax::codemap::{self, Span};
use rustc_front::hir;
-use rustc_front::intravisit::{self, Visitor};
use rustc_front::util::is_shift_binop;
register_long_diagnostics! {
false
}
-fn ast_ty_to_normalized<'tcx>(tcx: &TyCtxt<'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).
}
}
- 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);
+ }
}
}
}