Rollup merge of #65130 - davidtwco:rfc-2008-improper-ctypes, r=petrochenkov

lint: extern non-exhaustive types are improper

This PR makes the `improper_ctype` lint trigger for non-exhaustive types when those types aren't defined in the current crate, as per [this comment](https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344).

cc @Centril
This commit is contained in:
Tyler Mandry 2019-10-05 21:55:11 -07:00 committed by GitHub
commit 485f5c953d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 175 additions and 0 deletions

View file

@ -631,6 +631,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
};
}
let is_non_exhaustive =
def.non_enum_variant().is_field_list_non_exhaustive();
if is_non_exhaustive && !def.did.is_local() {
return FfiUnsafe {
ty,
reason: "this struct is non-exhaustive",
help: None,
};
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe {
ty,
@ -730,8 +740,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
}
if def.is_variant_list_non_exhaustive() && !def.did.is_local() {
return FfiUnsafe {
ty,
reason: "this enum is non-exhaustive",
help: None,
};
}
// Check the contained variants.
for variant in &def.variants {
let is_non_exhaustive = variant.is_field_list_non_exhaustive();
if is_non_exhaustive && !variant.def_id.is_local() {
return FfiUnsafe {
ty,
reason: "this enum has non-exhaustive variants",
help: None,
};
}
for field in &variant.fields {
let field_ty = cx.normalize_erasing_regions(
ParamEnv::reveal_all(),

View file

@ -0,0 +1,31 @@
#![feature(non_exhaustive)]
#[non_exhaustive]
#[repr(C)]
pub enum NonExhaustiveEnum {
Unit,
Tuple(u32),
Struct { field: u32 }
}
#[non_exhaustive]
#[repr(C)]
pub struct NormalStruct {
pub first_field: u16,
pub second_field: u16,
}
#[non_exhaustive]
#[repr(C)]
pub struct UnitStruct;
#[non_exhaustive]
#[repr(C)]
pub struct TupleStruct (pub u16, pub u16);
#[repr(C)]
pub enum NonExhaustiveVariants {
#[non_exhaustive] Unit,
#[non_exhaustive] Tuple(u32),
#[non_exhaustive] Struct { field: u32 }
}

View file

@ -0,0 +1,24 @@
// aux-build:types.rs
#![deny(improper_ctypes)]
extern crate types;
// This test checks that non-exhaustive types with `#[repr(C)]` from an extern crate are considered
// improper.
use types::{NonExhaustiveEnum, NormalStruct, UnitStruct, TupleStruct, NonExhaustiveVariants};
extern {
pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
//~^ ERROR `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe
pub fn non_exhaustive_normal_struct(_: NormalStruct);
//~^ ERROR `extern` block uses type `types::NormalStruct`, which is not FFI-safe
pub fn non_exhaustive_unit_struct(_: UnitStruct);
//~^ ERROR `extern` block uses type `types::UnitStruct`, which is not FFI-safe
pub fn non_exhaustive_tuple_struct(_: TupleStruct);
//~^ ERROR `extern` block uses type `types::TupleStruct`, which is not FFI-safe
pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
//~^ ERROR `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe
}
fn main() { }

View file

@ -0,0 +1,47 @@
error: `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:12:35
|
LL | pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
| ^^^^^^^^^^^^^^^^^ not FFI-safe
|
note: lint level defined here
--> $DIR/extern_crate_improper.rs:2:9
|
LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^
= note: this enum is non-exhaustive
error: `extern` block uses type `types::NormalStruct`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:14:44
|
LL | pub fn non_exhaustive_normal_struct(_: NormalStruct);
| ^^^^^^^^^^^^ not FFI-safe
|
= note: this struct is non-exhaustive
error: `extern` block uses type `types::UnitStruct`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:16:42
|
LL | pub fn non_exhaustive_unit_struct(_: UnitStruct);
| ^^^^^^^^^^ not FFI-safe
|
= note: this struct is non-exhaustive
error: `extern` block uses type `types::TupleStruct`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:18:43
|
LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct);
| ^^^^^^^^^^^ not FFI-safe
|
= note: this struct is non-exhaustive
error: `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:20:38
|
LL | pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
| ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: this enum has non-exhaustive variants
error: aborting due to 5 previous errors

View file

@ -0,0 +1,46 @@
// check-pass
#![feature(non_exhaustive)]
#![deny(improper_ctypes)]
// This test checks that non-exhaustive types with `#[repr(C)]` are considered proper within
// the defining crate.
#[non_exhaustive]
#[repr(C)]
pub enum NonExhaustiveEnum {
Unit,
Tuple(u32),
Struct { field: u32 }
}
#[non_exhaustive]
#[repr(C)]
pub struct NormalStruct {
pub first_field: u16,
pub second_field: u16,
}
#[non_exhaustive]
#[repr(C)]
pub struct UnitStruct;
#[non_exhaustive]
#[repr(C)]
pub struct TupleStruct (pub u16, pub u16);
#[repr(C)]
pub enum NonExhaustiveVariants {
#[non_exhaustive] Unit,
#[non_exhaustive] Tuple(u32),
#[non_exhaustive] Struct { field: u32 }
}
extern {
// Unit structs aren't tested here because they will trigger `improper_ctypes` anyway.
pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
pub fn non_exhaustive_normal_struct(_: NormalStruct);
pub fn non_exhaustive_tuple_struct(_: TupleStruct);
pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
}
fn main() { }