Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lint: extern non-exhaustive types are improper #65130

Merged
merged 1 commit into from
Oct 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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 }
}
Original file line number Diff line number Diff line change
@@ -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() { }
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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() { }