Forbid opaque types in extern blocks

This commit is contained in:
varkor 2019-09-10 18:16:35 +01:00
parent 740dd4bf05
commit df7e496f85
3 changed files with 63 additions and 0 deletions

View File

@ -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);

View File

@ -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() {}

View File

@ -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