Skip to content

Commit 92ae35f

Browse files
committed
lint/ctypes: multiple external fn-ptrs in ty
Extend previous commit's support for checking for external fn-ptrs in internal fn types to report errors for multiple found fn-ptrs. Signed-off-by: David Wood <david.wood@huawei.com>
1 parent c1dcf26 commit 92ae35f

File tree

3 files changed

+68
-19
lines changed

3 files changed

+68
-19
lines changed

Diff for: compiler/rustc_lint/src/types.rs

+45-18
Original file line numberDiff line numberDiff line change
@@ -1235,35 +1235,40 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12351235
/// Argument types and the result type are checked for functions with external ABIs.
12361236
/// For functions with internal ABIs, argument types and the result type are walked to find
12371237
/// fn-ptr types that have external ABIs, as these still need checked.
1238-
fn check_maybe_foreign_fn(&mut self, abi: SpecAbi, def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
1238+
fn check_maybe_foreign_fn(
1239+
&mut self,
1240+
abi: SpecAbi,
1241+
def_id: LocalDefId,
1242+
decl: &'tcx hir::FnDecl<'_>,
1243+
) {
12391244
let sig = self.cx.tcx.fn_sig(def_id).subst_identity();
12401245
let sig = self.cx.tcx.erase_late_bound_regions(sig);
12411246

12421247
let is_internal_abi = self.is_internal_abi(abi);
12431248
let check_ty = |this: &mut ImproperCTypesVisitor<'a, 'tcx>,
1244-
span: Span,
1249+
hir_ty: &'tcx hir::Ty<'_>,
12451250
ty: Ty<'tcx>,
12461251
is_return_type: bool| {
12471252
// If this function has an external ABI, then its arguments and return type should be
12481253
// checked..
12491254
if !is_internal_abi {
1250-
this.check_type_for_ffi_and_report_errors(span, ty, false, is_return_type);
1255+
this.check_type_for_ffi_and_report_errors(hir_ty.span, ty, false, is_return_type);
12511256
return;
12521257
}
12531258

12541259
// ..but if this function has an internal ABI, then search the argument or return type
12551260
// for any fn-ptr types with external ABI, which should be checked..
1256-
if let Some(fn_ptr_ty) = this.find_fn_ptr_ty_with_external_abi(ty) {
1261+
for (fn_ptr_ty, span) in this.find_fn_ptr_ty_with_external_abi(hir_ty, ty) {
12571262
this.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, is_return_type);
12581263
}
12591264
};
12601265

12611266
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1262-
check_ty(self, input_hir.span, *input_ty, false);
1267+
check_ty(self, input_hir, *input_ty, false);
12631268
}
12641269

12651270
if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
1266-
check_ty(self, ret_hir.span, sig.output(), true);
1271+
check_ty(self, ret_hir, sig.output(), true);
12671272
}
12681273
}
12691274

@@ -1282,30 +1287,52 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12821287
/// Find any fn-ptr types with external ABIs in `ty`.
12831288
///
12841289
/// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
1285-
fn find_fn_ptr_ty_with_external_abi(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
1286-
struct FnPtrFinder<'parent, 'a, 'tcx>(&'parent ImproperCTypesVisitor<'a, 'tcx>);
1290+
fn find_fn_ptr_ty_with_external_abi(
1291+
&self,
1292+
hir_ty: &hir::Ty<'tcx>,
1293+
ty: Ty<'tcx>,
1294+
) -> Vec<(Ty<'tcx>, Span)> {
1295+
struct FnPtrFinder<'parent, 'a, 'tcx> {
1296+
visitor: &'parent ImproperCTypesVisitor<'a, 'tcx>,
1297+
spans: Vec<Span>,
1298+
tys: Vec<Ty<'tcx>>,
1299+
}
1300+
1301+
impl<'parent, 'a, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'parent, 'a, 'tcx> {
1302+
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) {
1303+
debug!(?ty);
1304+
if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
1305+
&& !self.visitor.is_internal_abi(*abi)
1306+
{
1307+
self.spans.push(ty.span);
1308+
}
1309+
1310+
hir::intravisit::walk_ty(self, ty)
1311+
}
1312+
}
1313+
12871314
impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'vis, 'a, 'tcx> {
12881315
type BreakTy = Ty<'tcx>;
12891316

12901317
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
1291-
if let ty::FnPtr(sig) = ty.kind() && !self.0.is_internal_abi(sig.abi()) {
1292-
ControlFlow::Break(ty)
1293-
} else {
1294-
ty.super_visit_with(self)
1318+
if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) {
1319+
self.tys.push(ty);
12951320
}
1321+
1322+
ty.super_visit_with(self)
12961323
}
12971324
}
12981325

1299-
self.cx
1300-
.tcx
1301-
.normalize_erasing_regions(self.cx.param_env, ty)
1302-
.visit_with(&mut FnPtrFinder(&*self))
1303-
.break_value()
1326+
let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() };
1327+
self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty).visit_with(&mut visitor);
1328+
hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty);
1329+
1330+
iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect()
13041331
}
13051332
}
13061333

13071334
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
1308-
fn check_foreign_item(&mut self, cx: &LateContext<'_>, it: &hir::ForeignItem<'_>) {
1335+
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
13091336
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration };
13101337
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id());
13111338

Diff for: tests/ui/lint/lint-ctypes-94223.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33

44
pub fn bad(f: extern "C" fn([u8])) {}
55
//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe
6+
7+
pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
8+
//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe
9+
//~^^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe

Diff for: tests/ui/lint/lint-ctypes-94223.stderr

+19-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,23 @@ note: the lint level is defined here
1212
LL | #![deny(improper_ctypes_definitions)]
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

15-
error: aborting due to previous error
15+
error: `extern` fn uses type `[u8]`, which is not FFI-safe
16+
--> $DIR/lint-ctypes-94223.rs:7:28
17+
|
18+
LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
19+
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
20+
|
21+
= help: consider using a raw pointer instead
22+
= note: slices have no C equivalent
23+
24+
error: `extern` fn uses type `[u8]`, which is not FFI-safe
25+
--> $DIR/lint-ctypes-94223.rs:7:49
26+
|
27+
LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
28+
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
29+
|
30+
= help: consider using a raw pointer instead
31+
= note: slices have no C equivalent
32+
33+
error: aborting due to 3 previous errors
1634

0 commit comments

Comments
 (0)