Skip to content

Commit 080aa86

Browse files
committed
lint: extern non-exhaustive types are improper
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>
1 parent 7870050 commit 080aa86

File tree

5 files changed

+175
-0
lines changed

5 files changed

+175
-0
lines changed

Diff for: src/librustc_lint/types.rs

+27
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
631631
};
632632
}
633633

634+
let is_non_exhaustive =
635+
def.non_enum_variant().is_field_list_non_exhaustive();
636+
if is_non_exhaustive && !def.did.is_local() {
637+
return FfiUnsafe {
638+
ty,
639+
reason: "this struct is non-exhaustive",
640+
help: None,
641+
};
642+
}
643+
634644
if def.non_enum_variant().fields.is_empty() {
635645
return FfiUnsafe {
636646
ty,
@@ -730,8 +740,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
730740
}
731741
}
732742

743+
if def.is_variant_list_non_exhaustive() && !def.did.is_local() {
744+
return FfiUnsafe {
745+
ty,
746+
reason: "this enum is non-exhaustive",
747+
help: None,
748+
};
749+
}
750+
733751
// Check the contained variants.
734752
for variant in &def.variants {
753+
let is_non_exhaustive = variant.is_field_list_non_exhaustive();
754+
if is_non_exhaustive && !variant.def_id.is_local() {
755+
return FfiUnsafe {
756+
ty,
757+
reason: "this enum has non-exhaustive variants",
758+
help: None,
759+
};
760+
}
761+
735762
for field in &variant.fields {
736763
let field_ty = cx.normalize_erasing_regions(
737764
ParamEnv::reveal_all(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#![feature(non_exhaustive)]
2+
3+
#[non_exhaustive]
4+
#[repr(C)]
5+
pub enum NonExhaustiveEnum {
6+
Unit,
7+
Tuple(u32),
8+
Struct { field: u32 }
9+
}
10+
11+
#[non_exhaustive]
12+
#[repr(C)]
13+
pub struct NormalStruct {
14+
pub first_field: u16,
15+
pub second_field: u16,
16+
}
17+
18+
#[non_exhaustive]
19+
#[repr(C)]
20+
pub struct UnitStruct;
21+
22+
#[non_exhaustive]
23+
#[repr(C)]
24+
pub struct TupleStruct (pub u16, pub u16);
25+
26+
#[repr(C)]
27+
pub enum NonExhaustiveVariants {
28+
#[non_exhaustive] Unit,
29+
#[non_exhaustive] Tuple(u32),
30+
#[non_exhaustive] Struct { field: u32 }
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// aux-build:types.rs
2+
#![deny(improper_ctypes)]
3+
4+
extern crate types;
5+
6+
// This test checks that non-exhaustive types with `#[repr(C)]` from an extern crate are considered
7+
// improper.
8+
9+
use types::{NonExhaustiveEnum, NormalStruct, UnitStruct, TupleStruct, NonExhaustiveVariants};
10+
11+
extern {
12+
pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
13+
//~^ ERROR `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe
14+
pub fn non_exhaustive_normal_struct(_: NormalStruct);
15+
//~^ ERROR `extern` block uses type `types::NormalStruct`, which is not FFI-safe
16+
pub fn non_exhaustive_unit_struct(_: UnitStruct);
17+
//~^ ERROR `extern` block uses type `types::UnitStruct`, which is not FFI-safe
18+
pub fn non_exhaustive_tuple_struct(_: TupleStruct);
19+
//~^ ERROR `extern` block uses type `types::TupleStruct`, which is not FFI-safe
20+
pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
21+
//~^ ERROR `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe
22+
}
23+
24+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe
2+
--> $DIR/extern_crate_improper.rs:12:35
3+
|
4+
LL | pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
5+
| ^^^^^^^^^^^^^^^^^ not FFI-safe
6+
|
7+
note: lint level defined here
8+
--> $DIR/extern_crate_improper.rs:2:9
9+
|
10+
LL | #![deny(improper_ctypes)]
11+
| ^^^^^^^^^^^^^^^
12+
= note: this enum is non-exhaustive
13+
14+
error: `extern` block uses type `types::NormalStruct`, which is not FFI-safe
15+
--> $DIR/extern_crate_improper.rs:14:44
16+
|
17+
LL | pub fn non_exhaustive_normal_struct(_: NormalStruct);
18+
| ^^^^^^^^^^^^ not FFI-safe
19+
|
20+
= note: this struct is non-exhaustive
21+
22+
error: `extern` block uses type `types::UnitStruct`, which is not FFI-safe
23+
--> $DIR/extern_crate_improper.rs:16:42
24+
|
25+
LL | pub fn non_exhaustive_unit_struct(_: UnitStruct);
26+
| ^^^^^^^^^^ not FFI-safe
27+
|
28+
= note: this struct is non-exhaustive
29+
30+
error: `extern` block uses type `types::TupleStruct`, which is not FFI-safe
31+
--> $DIR/extern_crate_improper.rs:18:43
32+
|
33+
LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct);
34+
| ^^^^^^^^^^^ not FFI-safe
35+
|
36+
= note: this struct is non-exhaustive
37+
38+
error: `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe
39+
--> $DIR/extern_crate_improper.rs:20:38
40+
|
41+
LL | pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
42+
| ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
43+
|
44+
= note: this enum has non-exhaustive variants
45+
46+
error: aborting due to 5 previous errors
47+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// check-pass
2+
#![feature(non_exhaustive)]
3+
#![deny(improper_ctypes)]
4+
5+
// This test checks that non-exhaustive types with `#[repr(C)]` are considered proper within
6+
// the defining crate.
7+
8+
#[non_exhaustive]
9+
#[repr(C)]
10+
pub enum NonExhaustiveEnum {
11+
Unit,
12+
Tuple(u32),
13+
Struct { field: u32 }
14+
}
15+
16+
#[non_exhaustive]
17+
#[repr(C)]
18+
pub struct NormalStruct {
19+
pub first_field: u16,
20+
pub second_field: u16,
21+
}
22+
23+
#[non_exhaustive]
24+
#[repr(C)]
25+
pub struct UnitStruct;
26+
27+
#[non_exhaustive]
28+
#[repr(C)]
29+
pub struct TupleStruct (pub u16, pub u16);
30+
31+
#[repr(C)]
32+
pub enum NonExhaustiveVariants {
33+
#[non_exhaustive] Unit,
34+
#[non_exhaustive] Tuple(u32),
35+
#[non_exhaustive] Struct { field: u32 }
36+
}
37+
38+
extern {
39+
// Unit structs aren't tested here because they will trigger `improper_ctypes` anyway.
40+
pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
41+
pub fn non_exhaustive_normal_struct(_: NormalStruct);
42+
pub fn non_exhaustive_tuple_struct(_: TupleStruct);
43+
pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
44+
}
45+
46+
fn main() { }

0 commit comments

Comments
 (0)