use crate::hir::def_id::DefId;
use rustc::hir::lowering::is_range_literal;
use rustc::ty::subst::SubstsRef;
-use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx, SizeSkeleton};
use rustc::{lint, util};
use rustc_index::vec::Idx;
ty::Array(ty, _) => self.check_type_for_ffi(cache, ty),
ty::FnPtr(sig) => {
- if self.is_internal_abi(sig.abi()) {
- return FfiUnsafe {
- ty,
- reason: "this function pointer has Rust-specific calling convention",
- help: Some("consider using an `extern fn(...) -> ...` \
- function pointer instead"),
- };
+ match sig.abi() {
+ Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
+ return FfiUnsafe {
+ ty,
+ reason: "this function pointer has Rust-specific calling convention",
+ help: Some("consider using an `extern fn(...) -> ...` \
+ function pointer instead"),
+ }
+ }
+ _ => {}
}
let sig = cx.erase_late_bound_regions(&sig);
ty::Foreign(..) => FfiSafe,
- // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
- // so they are currently ignored for the purposes of this lint, see #65134.
- ty::Param(..) | ty::Projection(..) => FfiSafe,
-
+ ty::Param(..) |
ty::Infer(..) |
ty::Bound(..) |
ty::Error |
ty::GeneratorWitness(..) |
ty::Placeholder(..) |
ty::UnnormalizedProjection(..) |
+ ty::Projection(..) |
ty::Opaque(..) |
ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
}
sp: Span,
note: &str,
help: Option<&str>,
- is_foreign_item: bool,
) {
let mut diag = self.cx.struct_span_lint(
IMPROPER_CTYPES,
sp,
- &format!(
- "`extern` {} uses type `{}`, which is not FFI-safe",
- if is_foreign_item { "block" } else { "fn" },
- ty,
- ),
+ &format!("`extern` block uses type `{}`, which is not FFI-safe", ty),
);
diag.span_label(sp, "not FFI-safe");
if let Some(help) = help {
diag.emit();
}
- fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>, is_foreign_item: bool) -> bool {
+ fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
+ use crate::rustc::ty::TypeFoldable;
+
struct ProhibitOpaqueTypes<'tcx> {
ty: Option<Ty<'tcx>>,
};
sp,
"opaque types have no C equivalent",
None,
- is_foreign_item,
);
true
} else {
}
}
- fn check_type_for_ffi_and_report_errors(
- &mut self,
- sp: Span,
- ty: Ty<'tcx>,
- is_foreign_item: bool,
- ) {
+ fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
// We have to check for opaque types before `normalize_erasing_regions`,
// which will replace opaque types with their underlying concrete type.
- if self.check_for_opaque_ty(sp, ty, is_foreign_item) {
+ if self.check_for_opaque_ty(sp, ty) {
// We've already emitted an error due to an opaque type.
return;
}
- let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
+ // it is only OK to use this function because extern fns cannot have
+ // any generic types right now:
+ let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiPhantom(ty) => {
- self.emit_ffi_unsafe_type_lint(
- ty, sp, "composed only of `PhantomData`", None, is_foreign_item);
+ self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None);
}
FfiResult::FfiUnsafe { ty, reason, help } => {
- self.emit_ffi_unsafe_type_lint(
- ty, sp, reason, help, is_foreign_item);
+ self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
}
}
}
- fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl, is_foreign_item: bool) {
+ fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl) {
let def_id = self.cx.tcx.hir().local_def_id(id);
let sig = self.cx.tcx.fn_sig(def_id);
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.span, input_ty, is_foreign_item);
+ self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
}
if let hir::Return(ref ret_hir) = decl.output {
let ret_ty = sig.output();
if !ret_ty.is_unit() {
- self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, is_foreign_item);
+ self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
}
}
}
fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
let def_id = self.cx.tcx.hir().local_def_id(id);
let ty = self.cx.tcx.type_of(def_id);
- self.check_type_for_ffi_and_report_errors(span, ty, true);
- }
-
- fn is_internal_abi(&self, abi: Abi) -> bool {
- if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
- true
- } else {
- false
- }
+ self.check_type_for_ffi_and_report_errors(span, ty);
}
}
fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem) {
let mut vis = ImproperCTypesVisitor { cx };
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
- if !vis.is_internal_abi(abi) {
+ if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
+ // Don't worry about types in internal ABIs.
+ } else {
match it.kind {
hir::ForeignItemKind::Fn(ref decl, _, _) => {
- vis.check_foreign_fn(it.hir_id, decl, true);
+ vis.check_foreign_fn(it.hir_id, decl);
}
hir::ForeignItemKind::Static(ref ty, _) => {
vis.check_foreign_static(it.hir_id, ty.span);
}
}
}
-
- fn check_fn(
- &mut self,
- cx: &LateContext<'a, 'tcx>,
- kind: hir::intravisit::FnKind<'tcx>,
- decl: &'tcx hir::FnDecl,
- _: &'tcx hir::Body,
- _: Span,
- hir_id: hir::HirId,
- ) {
- use hir::intravisit::FnKind;
-
- let abi = match kind {
- FnKind::ItemFn(_, _, header, ..) => (header.abi),
- FnKind::Method(_, sig, ..) => (sig.header.abi),
- _ => return,
- };
-
- let mut vis = ImproperCTypesVisitor { cx };
- if !vis.is_internal_abi(abi) {
- vis.check_foreign_fn(hir_id, decl, false);
- }
- }
}
declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);