From df7e496f855331acd0cb9c6133a77197cd6118cf Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 10 Sep 2019 18:16:35 +0100 Subject: [PATCH] Forbid opaque types in extern blocks --- src/librustc_lint/types.rs | 33 ++++++++++++++++++++ src/test/ui/lint/opaque-ty-ffi-unsafe.rs | 16 ++++++++++ src/test/ui/lint/opaque-ty-ffi-unsafe.stderr | 14 +++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/test/ui/lint/opaque-ty-ffi-unsafe.rs create mode 100644 src/test/ui/lint/opaque-ty-ffi-unsafe.stderr diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index bdb6844920d4..63fe11f3443e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -859,7 +859,40 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } + fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { + use crate::rustc::ty::TypeFoldable; + + struct ProhibitOpaqueTypes<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, + sp: Span, + }; + + impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + if let ty::Opaque(..) = ty.sty { + self.cx.span_lint(IMPROPER_CTYPES, + self.sp, + &format!("`extern` block uses type `{}` which is not FFI-safe: \ + opaque types have no C equivalent", ty)); + true + } else { + ty.super_visit_with(self) + } + } + } + + let mut visitor = ProhibitOpaqueTypes { cx: self.cx, sp }; + ty.visit_with(&mut visitor) + } + 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) { + // We've already emitted an error due to an opaque type. + return; + } + // 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); diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs new file mode 100644 index 000000000000..907ad068035b --- /dev/null +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +#![deny(improper_ctypes)] + +type A = impl Fn(); + +pub fn ret_closure() -> A { + || {} +} + +extern "C" { + pub fn a(_: A); + //~^ ERROR `extern` block uses type `A` which is not FFI-safe: opaque types have no C equivalent +} + +fn main() {} diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr new file mode 100644 index 000000000000..6e234aa300b7 --- /dev/null +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr @@ -0,0 +1,14 @@ +error: `extern` block uses type `A` which is not FFI-safe: opaque types have no C equivalent + --> $DIR/opaque-ty-ffi-unsafe.rs:12:17 + | +LL | pub fn a(_: A); + | ^ + | +note: lint level defined here + --> $DIR/opaque-ty-ffi-unsafe.rs:3:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error +