Skip to content

Commit

Permalink
lint: extern non-exhaustive types are improper
Browse files Browse the repository at this point in the history
This commit makes the `improper_ctype` lint trigger for non-exhaustive
types when those types aren't defined in the current crate.

Signed-off-by: David Wood <david@davidtw.co>
  • Loading branch information
davidtwco committed Oct 5, 2019
1 parent 7870050 commit 080aa86
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/librustc_lint/types.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -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(),
Expand Down
@@ -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 }
}
@@ -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() { }
@@ -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

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

0 comments on commit 080aa86

Please sign in to comment.