Skip to content

Commit fb6647c

Browse files
committed
Add FFI raw array lint
1 parent e41ced3 commit fb6647c

File tree

1 file changed

+29
-5
lines changed

1 file changed

+29
-5
lines changed

src/librustc_lint/types.rs

+29-5
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,23 @@ fn is_repr_nullable_ptr<'tcx>(
600600
}
601601

602602
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
603+
604+
/// Check if the type is array and emit an unsafe type lint.
605+
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
606+
if let ty::Array(..) = ty.kind {
607+
self.emit_ffi_unsafe_type_lint(
608+
ty,
609+
sp,
610+
"passing raw arrays by value is not FFI-safe",
611+
Some("consider passing a pointer to the array"),
612+
);
613+
true
614+
} else {
615+
false
616+
}
617+
}
618+
619+
603620
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
604621
/// representation which can be exported to C code).
605622
fn check_type_for_ffi(&self,
@@ -834,7 +851,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
834851
ty::RawPtr(ty::TypeAndMut { ty, .. }) |
835852
ty::Ref(_, ty, _) => self.check_type_for_ffi(cache, ty),
836853

837-
ty::Array(ty, _) => self.check_type_for_ffi(cache, ty),
854+
ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
838855

839856
ty::FnPtr(sig) => {
840857
match sig.abi() {
@@ -946,7 +963,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
946963
}
947964
}
948965

949-
fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
966+
fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>, is_static: bool) {
950967
// We have to check for opaque types before `normalize_erasing_regions`,
951968
// which will replace opaque types with their underlying concrete type.
952969
if self.check_for_opaque_ty(sp, ty) {
@@ -957,6 +974,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
957974
// it is only OK to use this function because extern fns cannot have
958975
// any generic types right now:
959976
let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
977+
// C doesn't really support passing arrays by value.
978+
// The only way to pass an array by value is through a struct.
979+
// So we first test that the top level isn't an array,
980+
// and then recursively check the types inside.
981+
if !is_static && self.check_for_array_ty(sp, ty) {
982+
return;
983+
}
960984

961985
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
962986
FfiResult::FfiSafe => {}
@@ -975,21 +999,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
975999
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
9761000

9771001
for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
978-
self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
1002+
self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false);
9791003
}
9801004

9811005
if let hir::Return(ref ret_hir) = decl.output {
9821006
let ret_ty = sig.output();
9831007
if !ret_ty.is_unit() {
984-
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
1008+
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false);
9851009
}
9861010
}
9871011
}
9881012

9891013
fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
9901014
let def_id = self.cx.tcx.hir().local_def_id(id);
9911015
let ty = self.cx.tcx.type_of(def_id);
992-
self.check_type_for_ffi_and_report_errors(span, ty);
1016+
self.check_type_for_ffi_and_report_errors(span, ty, true);
9931017
}
9941018
}
9951019

0 commit comments

Comments
 (0)