Disallow single-variant enums

Couldn't find documentation supporting that single-variant
`#[repr(Rust)]` enums with RHS assigned work as expected with this
change.

```rust
enum Variants {
  A = 17,
} // Would this be zero sized optimized guaranteed?
```
This commit is contained in:
Arvind Mukund 2024-03-09 15:13:29 -08:00
parent 223d5eb64f
commit 014ddac9c9
3 changed files with 39 additions and 17 deletions

View File

@ -1102,22 +1102,24 @@ fn get_nullable_type<'tcx>(
/// A type is niche_optimization_candiate iff: /// A type is niche_optimization_candiate iff:
/// - Is a zero-sized type with alignment 1 (a “1-ZST”). /// - Is a zero-sized type with alignment 1 (a “1-ZST”).
/// - Has no fields. /// - Has no fields.
/// - Does not have the #[non_exhaustive] attribute. /// - Does not have the `#[non_exhaustive]` attribute.
fn is_niche_optimization_candidate<'tcx>( fn is_niche_optimization_candidate<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> bool { ) -> bool {
if !tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_1zst()) { if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| !layout.is_1zst()) {
return false; return false;
} }
match ty.kind() { match ty.kind() {
ty::Adt(ty_def, _) => { ty::Adt(ty_def, _) => {
let non_exhaustive = ty_def.is_variant_list_non_exhaustive(); let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
let contains_no_fields = ty_def.all_fields().next().is_none(); // Should single-variant enums be allowed?
let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
|| (ty_def.is_enum() && ty_def.variants().is_empty());
!non_exhaustive && contains_no_fields !non_exhaustive && empty
} }
ty::Tuple(tys) => tys.is_empty(), ty::Tuple(tys) => tys.is_empty(),
_ => false, _ => false,

View File

@ -122,6 +122,7 @@ extern "C" {
fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>); fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>); fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>);
fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>); fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
//~^ ERROR `extern` block uses type
fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>); fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
//~^ ERROR `extern` block uses type //~^ ERROR `extern` block uses type
fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>); fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
@ -159,6 +160,7 @@ extern "C" {
fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>); fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>); fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>);
fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>); fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
//~^ ERROR `extern` block uses type
fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>); fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
//~^ ERROR `extern` block uses type //~^ ERROR `extern` block uses type
fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>); fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);

View File

@ -113,8 +113,17 @@ LL | fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<NonZero<u8>, U>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:124:51
|
LL | fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:125:53 --> $DIR/lint-ctypes-enum.rs:126:53
| |
LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>); LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -123,7 +132,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:127:51 --> $DIR/lint-ctypes-enum.rs:128:51
| |
LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>); LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -132,7 +141,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>,
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:130:49 --> $DIR/lint-ctypes-enum.rs:131:49
| |
LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>); LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -141,7 +150,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Fi
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:132:30 --> $DIR/lint-ctypes-enum.rs:133:30
| |
LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>); LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -150,7 +159,7 @@ LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `u128`, which is not FFI-safe error: `extern` block uses type `u128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:143:33 --> $DIR/lint-ctypes-enum.rs:144:33
| |
LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>); LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -158,7 +167,7 @@ LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
= note: 128-bit integers don't currently have a known stable ABI = note: 128-bit integers don't currently have a known stable ABI
error: `extern` block uses type `i128`, which is not FFI-safe error: `extern` block uses type `i128`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:150:33 --> $DIR/lint-ctypes-enum.rs:151:33
| |
LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>); LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -166,7 +175,7 @@ LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
= note: 128-bit integers don't currently have a known stable ABI = note: 128-bit integers don't currently have a known stable ABI
error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:155:38 --> $DIR/lint-ctypes-enum.rs:156:38
| |
LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>); LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -175,7 +184,7 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZe
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:157:30 --> $DIR/lint-ctypes-enum.rs:158:30
| |
LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>); LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -183,8 +192,17 @@ LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<U, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:162:51
|
LL | fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:162:53 --> $DIR/lint-ctypes-enum.rs:164:53
| |
LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>); LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -193,7 +211,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:164:51 --> $DIR/lint-ctypes-enum.rs:166:51
| |
LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>); LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -202,7 +220,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:167:49 --> $DIR/lint-ctypes-enum.rs:169:49
| |
LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>); LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -211,7 +229,7 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<
= note: enum has no representation hint = note: enum has no representation hint
error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:169:30 --> $DIR/lint-ctypes-enum.rs:171:30
| |
LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>); LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -219,5 +237,5 @@ LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint = note: enum has no representation hint
error: aborting due to 23 previous errors error: aborting due to 25 previous errors