Skip to content

Commit

Permalink
Disallow single-variant enums
Browse files Browse the repository at this point in the history
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?
```
  • Loading branch information
MasterAwesome committed Apr 24, 2024
1 parent 223d5eb commit 014ddac
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 17 deletions.
10 changes: 6 additions & 4 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1102,22 +1102,24 @@ fn get_nullable_type<'tcx>(
/// A type is niche_optimization_candiate iff:
/// - Is a zero-sized type with alignment 1 (a “1-ZST”).
/// - Has no fields.
/// - Does not have the #[non_exhaustive] attribute.
/// - Does not have the `#[non_exhaustive]` attribute.
fn is_niche_optimization_candidate<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> 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;
}

match ty.kind() {
ty::Adt(ty_def, _) => {
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(),
_ => false,
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/lint/lint-ctypes-enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ extern "C" {
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_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>);
//~^ ERROR `extern` block uses type
fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
Expand Down Expand Up @@ -159,6 +160,7 @@ extern "C" {
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_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>>);
//~^ ERROR `extern` block uses type
fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
Expand Down
44 changes: 31 additions & 13 deletions tests/ui/lint/lint-ctypes-enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
= 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
--> $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>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
Expand All @@ -123,7 +132,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>
= note: enum has no representation hint

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>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
Expand All @@ -132,7 +141,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>,
= note: enum has no representation hint

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>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
Expand All @@ -141,7 +150,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Fi
= note: enum has no representation hint

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>>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
Expand All @@ -150,23 +159,23 @@ LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
= note: enum has no representation hint

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>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI

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>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= 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
--> $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>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
Expand All @@ -175,16 +184,25 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZe
= note: enum has no representation hint

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>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<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
--> $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>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
Expand All @@ -193,7 +211,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<
= note: enum has no representation hint

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>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
Expand All @@ -202,7 +220,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num
= note: enum has no representation hint

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>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
Expand All @@ -211,13 +229,13 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<
= note: enum has no representation hint

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>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: aborting due to 23 previous errors
error: aborting due to 25 previous errors

0 comments on commit 014ddac

Please sign in to comment.