diff options
| author | David Wood <david.wood@huawei.com> | 2023-03-02 11:23:44 +0000 |
|---|---|---|
| committer | David Wood <david.wood@huawei.com> | 2023-07-03 13:40:20 +0100 |
| commit | c75b080d7d878740c49539413d1b000906d420d4 (patch) | |
| tree | 411ba13166fc08c3dee5c426ae20fb7e31169044 | |
| parent | eddfce53c10d281cde6d283f36a12c43606b3f8c (diff) | |
| download | rust-c75b080d7d878740c49539413d1b000906d420d4.tar.gz rust-c75b080d7d878740c49539413d1b000906d420d4.zip | |
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>
| -rw-r--r-- | compiler/rustc_lint/src/types.rs | 63 | ||||
| -rw-r--r-- | tests/ui/lint/lint-ctypes-94223.rs | 4 | ||||
| -rw-r--r-- | tests/ui/lint/lint-ctypes-94223.stderr | 20 |
3 files changed, 68 insertions, 19 deletions
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fefd431971e..eeeac96798d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1384,35 +1384,40 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Argument types and the result type are checked for functions with external ABIs. /// For functions with internal ABIs, argument types and the result type are walked to find /// fn-ptr types that have external ABIs, as these still need checked. - fn check_maybe_foreign_fn(&mut self, abi: SpecAbi, def_id: LocalDefId, decl: &hir::FnDecl<'_>) { + fn check_maybe_foreign_fn( + &mut self, + abi: SpecAbi, + def_id: LocalDefId, + decl: &'tcx hir::FnDecl<'_>, + ) { let sig = self.cx.tcx.fn_sig(def_id).subst_identity(); let sig = self.cx.tcx.erase_late_bound_regions(sig); let is_internal_abi = self.is_internal_abi(abi); let check_ty = |this: &mut ImproperCTypesVisitor<'a, 'tcx>, - span: Span, + hir_ty: &'tcx hir::Ty<'_>, ty: Ty<'tcx>, is_return_type: bool| { // If this function has an external ABI, then its arguments and return type should be // checked.. if !is_internal_abi { - this.check_type_for_ffi_and_report_errors(span, ty, false, is_return_type); + this.check_type_for_ffi_and_report_errors(hir_ty.span, ty, false, is_return_type); return; } // ..but if this function has an internal ABI, then search the argument or return type // for any fn-ptr types with external ABI, which should be checked.. - if let Some(fn_ptr_ty) = this.find_fn_ptr_ty_with_external_abi(ty) { + for (fn_ptr_ty, span) in this.find_fn_ptr_ty_with_external_abi(hir_ty, ty) { this.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, is_return_type); } }; for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { - check_ty(self, input_hir.span, *input_ty, false); + check_ty(self, input_hir, *input_ty, false); } if let hir::FnRetTy::Return(ref ret_hir) = decl.output { - check_ty(self, ret_hir.span, sig.output(), true); + check_ty(self, ret_hir, sig.output(), true); } } @@ -1431,30 +1436,52 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Find any fn-ptr types with external ABIs in `ty`. /// /// For example, `Option<extern "C" fn()>` returns `extern "C" fn()` - fn find_fn_ptr_ty_with_external_abi(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { - struct FnPtrFinder<'parent, 'a, 'tcx>(&'parent ImproperCTypesVisitor<'a, 'tcx>); + fn find_fn_ptr_ty_with_external_abi( + &self, + hir_ty: &hir::Ty<'tcx>, + ty: Ty<'tcx>, + ) -> Vec<(Ty<'tcx>, Span)> { + struct FnPtrFinder<'parent, 'a, 'tcx> { + visitor: &'parent ImproperCTypesVisitor<'a, 'tcx>, + spans: Vec<Span>, + tys: Vec<Ty<'tcx>>, + } + + impl<'parent, 'a, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'parent, 'a, 'tcx> { + fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) { + debug!(?ty); + if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind + && !self.visitor.is_internal_abi(*abi) + { + self.spans.push(ty.span); + } + + hir::intravisit::walk_ty(self, ty) + } + } + impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'vis, 'a, 'tcx> { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::FnPtr(sig) = ty.kind() && !self.0.is_internal_abi(sig.abi()) { - ControlFlow::Break(ty) - } else { - ty.super_visit_with(self) + if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) { + self.tys.push(ty); } + + ty.super_visit_with(self) } } - self.cx - .tcx - .normalize_erasing_regions(self.cx.param_env, ty) - .visit_with(&mut FnPtrFinder(&*self)) - .break_value() + let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() }; + self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty).visit_with(&mut visitor); + hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty); + + iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect() } } impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { - fn check_foreign_item(&mut self, cx: &LateContext<'_>, it: &hir::ForeignItem<'_>) { + fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) { let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration }; let abi = cx.tcx.hir().get_foreign_abi(it.hir_id()); diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/lint-ctypes-94223.rs index ca7f3b73f66..98ccbd23a9e 100644 --- a/tests/ui/lint/lint-ctypes-94223.rs +++ b/tests/ui/lint/lint-ctypes-94223.rs @@ -3,3 +3,7 @@ pub fn bad(f: extern "C" fn([u8])) {} //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {} +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe +//~^^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr index f8afed34ea4..e05d6197cb4 100644 --- a/tests/ui/lint/lint-ctypes-94223.stderr +++ b/tests/ui/lint/lint-ctypes-94223.stderr @@ -12,5 +12,23 @@ note: the lint level is defined here LL | #![deny(improper_ctypes_definitions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:7:28 + | +LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {} + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:7:49 + | +LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {} + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: aborting due to 3 previous errors |
