Skip to content

Commit f3e0a95

Browse files
committed
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? ```
1 parent 747fd5b commit f3e0a95

File tree

3 files changed

+39
-17
lines changed

3 files changed

+39
-17
lines changed

compiler/rustc_lint/src/types.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1102,22 +1102,24 @@ fn get_nullable_type<'tcx>(
11021102
/// A type is niche_optimization_candiate iff:
11031103
/// - Is a zero-sized type with alignment 1 (a “1-ZST”).
11041104
/// - Has no fields.
1105-
/// - Does not have the #[non_exhaustive] attribute.
1105+
/// - Does not have the `#[non_exhaustive]` attribute.
11061106
fn is_niche_optimization_candidate<'tcx>(
11071107
tcx: TyCtxt<'tcx>,
11081108
param_env: ty::ParamEnv<'tcx>,
11091109
ty: Ty<'tcx>,
11101110
) -> bool {
1111-
if !tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_1zst()) {
1111+
if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| !layout.is_1zst()) {
11121112
return false;
11131113
}
11141114

11151115
match ty.kind() {
11161116
ty::Adt(ty_def, _) => {
11171117
let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
1118-
let contains_no_fields = ty_def.all_fields().next().is_none();
1118+
// Should single-variant enums be allowed?
1119+
let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
1120+
|| (ty_def.is_enum() && ty_def.variants().is_empty());
11191121

1120-
!non_exhaustive && contains_no_fields
1122+
!non_exhaustive && empty
11211123
}
11221124
ty::Tuple(tys) => tys.is_empty(),
11231125
_ => false,

tests/ui/lint/lint-ctypes-enum.rs

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ extern "C" {
123123
fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
124124
fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>);
125125
fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
126+
//~^ ERROR `extern` block uses type
126127
fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
127128
//~^ ERROR `extern` block uses type
128129
fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
@@ -160,6 +161,7 @@ extern "C" {
160161
fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
161162
fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>);
162163
fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
164+
//~^ ERROR `extern` block uses type
163165
fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
164166
//~^ ERROR `extern` block uses type
165167
fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);

tests/ui/lint/lint-ctypes-enum.stderr

+31-13
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,17 @@ LL | fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
113113
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
114114
= note: enum has no representation hint
115115

116+
error: `extern` block uses type `Result<NonZero<u8>, U>`, which is not FFI-safe
117+
--> $DIR/lint-ctypes-enum.rs:125:51
118+
|
119+
LL | fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
120+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
121+
|
122+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
123+
= note: enum has no representation hint
124+
116125
error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
117-
--> $DIR/lint-ctypes-enum.rs:126:53
126+
--> $DIR/lint-ctypes-enum.rs:127:53
118127
|
119128
LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
120129
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -123,7 +132,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>
123132
= note: enum has no representation hint
124133

125134
error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
126-
--> $DIR/lint-ctypes-enum.rs:128:51
135+
--> $DIR/lint-ctypes-enum.rs:129:51
127136
|
128137
LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
129138
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -132,7 +141,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>,
132141
= note: enum has no representation hint
133142

134143
error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
135-
--> $DIR/lint-ctypes-enum.rs:131:49
144+
--> $DIR/lint-ctypes-enum.rs:132:49
136145
|
137146
LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
138147
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -141,7 +150,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Fi
141150
= note: enum has no representation hint
142151

143152
error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
144-
--> $DIR/lint-ctypes-enum.rs:133:30
153+
--> $DIR/lint-ctypes-enum.rs:134:30
145154
|
146155
LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
147156
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -150,23 +159,23 @@ LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
150159
= note: enum has no representation hint
151160

152161
error: `extern` block uses type `u128`, which is not FFI-safe
153-
--> $DIR/lint-ctypes-enum.rs:144:33
162+
--> $DIR/lint-ctypes-enum.rs:145:33
154163
|
155164
LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
156165
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
157166
|
158167
= note: 128-bit integers don't currently have a known stable ABI
159168

160169
error: `extern` block uses type `i128`, which is not FFI-safe
161-
--> $DIR/lint-ctypes-enum.rs:151:33
170+
--> $DIR/lint-ctypes-enum.rs:152:33
162171
|
163172
LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
164173
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
165174
|
166175
= note: 128-bit integers don't currently have a known stable ABI
167176

168177
error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
169-
--> $DIR/lint-ctypes-enum.rs:156:38
178+
--> $DIR/lint-ctypes-enum.rs:157:38
170179
|
171180
LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
172181
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -175,16 +184,25 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZe
175184
= note: enum has no representation hint
176185

177186
error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
178-
--> $DIR/lint-ctypes-enum.rs:158:30
187+
--> $DIR/lint-ctypes-enum.rs:159:30
179188
|
180189
LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
181190
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
182191
|
183192
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
184193
= note: enum has no representation hint
185194

195+
error: `extern` block uses type `Result<U, NonZero<u8>>`, which is not FFI-safe
196+
--> $DIR/lint-ctypes-enum.rs:163:51
197+
|
198+
LL | fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
199+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
200+
|
201+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
202+
= note: enum has no representation hint
203+
186204
error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
187-
--> $DIR/lint-ctypes-enum.rs:163:53
205+
--> $DIR/lint-ctypes-enum.rs:165:53
188206
|
189207
LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
190208
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -193,7 +211,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<
193211
= note: enum has no representation hint
194212

195213
error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
196-
--> $DIR/lint-ctypes-enum.rs:165:51
214+
--> $DIR/lint-ctypes-enum.rs:167:51
197215
|
198216
LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
199217
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -202,7 +220,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num
202220
= note: enum has no representation hint
203221

204222
error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
205-
--> $DIR/lint-ctypes-enum.rs:168:49
223+
--> $DIR/lint-ctypes-enum.rs:170:49
206224
|
207225
LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
208226
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -211,13 +229,13 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<
211229
= note: enum has no representation hint
212230

213231
error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
214-
--> $DIR/lint-ctypes-enum.rs:170:30
232+
--> $DIR/lint-ctypes-enum.rs:172:30
215233
|
216234
LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
217235
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
218236
|
219237
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
220238
= note: enum has no representation hint
221239

222-
error: aborting due to 23 previous errors
240+
error: aborting due to 25 previous errors
223241

0 commit comments

Comments
 (0)