lint: check for unit ret type after normalization

This commit moves the check that skips unit return types to after
where the return type has been normalized - therefore ensuring that
FFI-safety lints are not emitted for types which normalize to unit.

Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
David Wood 2020-06-01 15:41:36 +01:00
parent a8640cdf47
commit 3e7aabb1b3
No known key found for this signature in database
GPG Key ID: 2592E76C87381FD9
3 changed files with 26 additions and 25 deletions

View File

@ -946,7 +946,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
}
fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>, is_static: bool) {
fn check_type_for_ffi_and_report_errors(
&mut self,
sp: Span,
ty: Ty<'tcx>,
is_static: bool,
is_return_type: bool,
) {
// 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) {
@ -957,14 +963,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// 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);
// C doesn't really support passing arrays by value.
// The only way to pass an array by value is through a struct.
// So we first test that the top level isn't an array,
// and then recursively check the types inside.
// C doesn't really support passing arrays by value - the only way to pass an array by value
// is through a struct. So, first test that the top level isn't an array, and then
// recursively check the types inside.
if !is_static && self.check_for_array_ty(sp, ty) {
return;
}
// Don't report FFI errors for unit return types. This check exists here, and not in
// `check_foreign_fn` (where it would make more sense) so that normalization has definitely
// happened.
if is_return_type && ty.is_unit() {
return;
}
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiPhantom(ty) => {
@ -982,21 +995,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
for (input_ty, input_hir) in sig.inputs().iter().zip(decl.inputs) {
self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false);
self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false);
}
if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
let ret_ty = sig.output();
if !ret_ty.is_unit() {
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false);
}
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false, true);
}
}
fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
let def_id = self.cx.tcx.hir().local_def_id(id);
let ty = self.cx.tcx.type_of(def_id);
self.check_type_for_ffi_and_report_errors(span, ty, true);
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
}
}

View File

@ -9,7 +9,6 @@ pub struct W<T>(T);
extern "C" {
pub fn bare() -> ();
pub fn normalize() -> <() as ToOwned>::Owned;
//~^ ERROR uses type `()`
pub fn transparent() -> W<()>;
//~^ ERROR uses type `W<()>`
}

View File

@ -1,23 +1,14 @@
error: `extern` block uses type `()`, which is not FFI-safe
--> $DIR/lint-ctypes-66202.rs:11:27
error: `extern` block uses type `W<()>`, which is not FFI-safe
--> $DIR/lint-ctypes-66202.rs:12:29
|
LL | pub fn normalize() -> <() as ToOwned>::Owned;
| ^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
LL | pub fn transparent() -> W<()>;
| ^^^^^ not FFI-safe
|
note: the lint level is defined here
--> $DIR/lint-ctypes-66202.rs:1:9
|
LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^
= help: consider using a struct instead
= note: tuples have unspecified layout
error: `extern` block uses type `W<()>`, which is not FFI-safe
--> $DIR/lint-ctypes-66202.rs:13:29
|
LL | pub fn transparent() -> W<()>;
| ^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
note: the type is defined here
--> $DIR/lint-ctypes-66202.rs:7:1
@ -25,5 +16,5 @@ note: the type is defined here
LL | pub struct W<T>(T);
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
error: aborting due to previous error