Skip to content

Commit c75b080

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 <[email protected]>
1 parent eddfce5 commit c75b080

File tree

3 files changed

+68
-19
lines changed

3 files changed

+68
-19
lines changed

compiler/rustc_lint/src/types.rs

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,35 +1384,40 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13841384
/// Argument types and the result type are checked for functions with external ABIs.
13851385
/// For functions with internal ABIs, argument types and the result type are walked to find
13861386
/// fn-ptr types that have external ABIs, as these still need checked.
1387-
fn check_maybe_foreign_fn(&mut self, abi: SpecAbi, def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
1387+
fn check_maybe_foreign_fn(
1388+
&mut self,
1389+
abi: SpecAbi,
1390+
def_id: LocalDefId,
1391+
decl: &'tcx hir::FnDecl<'_>,
1392+
) {
13881393
let sig = self.cx.tcx.fn_sig(def_id).subst_identity();
13891394
let sig = self.cx.tcx.erase_late_bound_regions(sig);
13901395

13911396
let is_internal_abi = self.is_internal_abi(abi);
13921397
let check_ty = |this: &mut ImproperCTypesVisitor<'a, 'tcx>,
1393-
span: Span,
1398+
hir_ty: &'tcx hir::Ty<'_>,
13941399
ty: Ty<'tcx>,
13951400
is_return_type: bool| {
13961401
// If this function has an external ABI, then its arguments and return type should be
13971402
// checked..
13981403
if !is_internal_abi {
1399-
this.check_type_for_ffi_and_report_errors(span, ty, false, is_return_type);
1404+
this.check_type_for_ffi_and_report_errors(hir_ty.span, ty, false, is_return_type);
14001405
return;
14011406
}
14021407

14031408
// ..but if this function has an internal ABI, then search the argument or return type
14041409
// for any fn-ptr types with external ABI, which should be checked..
1405-
if let Some(fn_ptr_ty) = this.find_fn_ptr_ty_with_external_abi(ty) {
1410+
for (fn_ptr_ty, span) in this.find_fn_ptr_ty_with_external_abi(hir_ty, ty) {
14061411
this.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, is_return_type);
14071412
}
14081413
};
14091414

14101415
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1411-
check_ty(self, input_hir.span, *input_ty, false);
1416+
check_ty(self, input_hir, *input_ty, false);
14121417
}
14131418

14141419
if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
1415-
check_ty(self, ret_hir.span, sig.output(), true);
1420+
check_ty(self, ret_hir, sig.output(), true);
14161421
}
14171422
}
14181423

@@ -1431,30 +1436,52 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14311436
/// Find any fn-ptr types with external ABIs in `ty`.
14321437
///
14331438
/// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
1434-
fn find_fn_ptr_ty_with_external_abi(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
1435-
struct FnPtrFinder<'parent, 'a, 'tcx>(&'parent ImproperCTypesVisitor<'a, 'tcx>);
1439+
fn find_fn_ptr_ty_with_external_abi(
1440+
&self,
1441+
hir_ty: &hir::Ty<'tcx>,
1442+
ty: Ty<'tcx>,
1443+
) -> Vec<(Ty<'tcx>, Span)> {
1444+
struct FnPtrFinder<'parent, 'a, 'tcx> {
1445+
visitor: &'parent ImproperCTypesVisitor<'a, 'tcx>,
1446+
spans: Vec<Span>,
1447+
tys: Vec<Ty<'tcx>>,
1448+
}
1449+
1450+
impl<'parent, 'a, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'parent, 'a, 'tcx> {
1451+
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) {
1452+
debug!(?ty);
1453+
if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
1454+
&& !self.visitor.is_internal_abi(*abi)
1455+
{
1456+
self.spans.push(ty.span);
1457+
}
1458+
1459+
hir::intravisit::walk_ty(self, ty)
1460+
}
1461+
}
1462+
14361463
impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'vis, 'a, 'tcx> {
14371464
type BreakTy = Ty<'tcx>;
14381465

14391466
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
1440-
if let ty::FnPtr(sig) = ty.kind() && !self.0.is_internal_abi(sig.abi()) {
1441-
ControlFlow::Break(ty)
1442-
} else {
1443-
ty.super_visit_with(self)
1467+
if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) {
1468+
self.tys.push(ty);
14441469
}
1470+
1471+
ty.super_visit_with(self)
14451472
}
14461473
}
14471474

1448-
self.cx
1449-
.tcx
1450-
.normalize_erasing_regions(self.cx.param_env, ty)
1451-
.visit_with(&mut FnPtrFinder(&*self))
1452-
.break_value()
1475+
let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() };
1476+
self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty).visit_with(&mut visitor);
1477+
hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty);
1478+
1479+
iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect()
14531480
}
14541481
}
14551482

14561483
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
1457-
fn check_foreign_item(&mut self, cx: &LateContext<'_>, it: &hir::ForeignItem<'_>) {
1484+
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
14581485
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration };
14591486
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id());
14601487

tests/ui/lint/lint-ctypes-94223.rs

Lines changed: 4 additions & 0 deletions
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

tests/ui/lint/lint-ctypes-94223.stderr

Lines changed: 19 additions & 1 deletion
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)