Skip to content

Commit 456a032

Browse files
committed
Auto merge of #86279 - JohnTitor:transparent-zero-size-fields, r=nikomatsakis
Permit zero non-zero-field on transparent types Fixes #77841 This makes the transparent fields meet the below: > * A `repr(transparent)` type `T` must meet the following rules: > * It may have any number of 1-ZST fields > * In addition, it may have at most one other field of type U r? `@nikomatsakis`
2 parents 964a81e + 4e755a9 commit 456a032

File tree

5 files changed

+51
-81
lines changed

5 files changed

+51
-81
lines changed

compiler/rustc_error_codes/src/error_codes/E0690.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
A struct with the representation hint `repr(transparent)` had zero or more than
2-
one fields that were not guaranteed to be zero-sized.
1+
A struct with the representation hint `repr(transparent)` had two or more fields
2+
that were not guaranteed to be zero-sized.
33

44
Erroneous code example:
55

66
```compile_fail,E0690
77
#[repr(transparent)]
8-
struct LengthWithUnit<U> { // error: transparent struct needs exactly one
8+
struct LengthWithUnit<U> { // error: transparent struct needs at most one
99
value: f32, // non-zero-sized field, but has 2
1010
unit: U,
1111
}
1212
```
1313

1414
Because transparent structs are represented exactly like one of their fields at
15-
run time, said field must be uniquely determined. If there is no field, or if
16-
there are multiple fields, it is not clear how the struct should be represented.
15+
run time, said field must be uniquely determined. If there are multiple fields,
16+
it is not clear how the struct should be represented.
1717
Note that fields of zero-sized types (e.g., `PhantomData`) can also exist
1818
alongside the field that contains the actual data, they do not count for this
1919
error. When generic types are involved (as in the above example), an error is

compiler/rustc_typeck/src/check/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1382,7 +1382,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty
13821382
let non_zst_fields =
13831383
field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
13841384
let non_zst_count = non_zst_fields.clone().count();
1385-
if non_zst_count != 1 {
1385+
if non_zst_count >= 2 {
13861386
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
13871387
}
13881388
for (span, zst, align1) in field_infos {

compiler/rustc_typeck/src/check/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
10201020
}
10211021
}
10221022

1023-
/// Emit an error when encountering more or less than one variant in a transparent enum.
1023+
/// Emit an error when encountering two or more variants in a transparent enum.
10241024
fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) {
10251025
let variant_spans: Vec<_> = adt
10261026
.variants
@@ -1039,7 +1039,7 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, d
10391039
err.emit();
10401040
}
10411041

1042-
/// Emit an error when encountering more or less than one non-zero-sized field in a transparent
1042+
/// Emit an error when encountering two or more non-zero-sized fields in a transparent
10431043
/// enum.
10441044
fn bad_non_zero_sized_fields<'tcx>(
10451045
tcx: TyCtxt<'tcx>,
@@ -1048,7 +1048,7 @@ fn bad_non_zero_sized_fields<'tcx>(
10481048
field_spans: impl Iterator<Item = Span>,
10491049
sp: Span,
10501050
) {
1051-
let msg = format!("needs exactly one non-zero-sized field, but has {}", field_count);
1051+
let msg = format!("needs at most one non-zero-sized field, but has {}", field_count);
10521052
let mut err = struct_span_err!(
10531053
tcx.sess,
10541054
sp,

src/test/ui/repr/repr-transparent.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,29 @@
88
use std::marker::PhantomData;
99

1010
#[repr(transparent)]
11-
struct NoFields; //~ ERROR needs exactly one non-zero-sized field
11+
struct NoFields;
1212

1313
#[repr(transparent)]
14-
struct ContainsOnlyZst(()); //~ ERROR needs exactly one non-zero-sized field
14+
struct ContainsOnlyZst(());
1515

1616
#[repr(transparent)]
17-
struct ContainsOnlyZstArray([bool; 0]); //~ ERROR needs exactly one non-zero-sized field
17+
struct ContainsOnlyZstArray([bool; 0]);
1818

1919
#[repr(transparent)]
2020
struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
21-
//~^ ERROR needs exactly one non-zero-sized field
2221

2322
#[repr(transparent)]
24-
struct MultipleNonZst(u8, u8); //~ ERROR needs exactly one non-zero-sized field
23+
struct ContainsZstAndNonZst((), [i32; 2]);
24+
25+
#[repr(transparent)]
26+
struct MultipleNonZst(u8, u8); //~ ERROR needs at most one non-zero-sized field
2527

2628
trait Mirror { type It: ?Sized; }
2729
impl<T: ?Sized> Mirror for T { type It = Self; }
2830

2931
#[repr(transparent)]
3032
pub struct StructWithProjection(f32, <f32 as Mirror>::It);
31-
//~^ ERROR needs exactly one non-zero-sized field
33+
//~^ ERROR needs at most one non-zero-sized field
3234

3335
#[repr(transparent)]
3436
struct NontrivialAlignZst(u32, [u16; 0]); //~ ERROR alignment larger than 1
@@ -40,22 +42,26 @@ struct ZstAlign32<T>(PhantomData<T>);
4042
struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
4143

4244
#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
43-
enum Void {}
44-
//~^ ERROR transparent enum needs exactly one variant, but has 0
45+
enum Void {} //~ ERROR transparent enum needs exactly one variant, but has 0
4546

4647
#[repr(transparent)]
47-
enum FieldlessEnum { //~ ERROR transparent enum needs exactly one non-zero-sized field, but has 0
48+
enum FieldlessEnum {
4849
Foo,
4950
}
5051

52+
#[repr(transparent)]
53+
enum UnitFieldEnum {
54+
Foo(()),
55+
}
56+
5157
#[repr(transparent)]
5258
enum TooManyFieldsEnum {
5359
Foo(u32, String),
5460
}
55-
//~^^^ ERROR transparent enum needs exactly one non-zero-sized field, but has 2
61+
//~^^^ ERROR transparent enum needs at most one non-zero-sized field, but has 2
5662

5763
#[repr(transparent)]
58-
enum TooManyVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
64+
enum MultipleVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
5965
Foo(String),
6066
Bar,
6167
}
@@ -71,12 +77,12 @@ enum GenericAlignEnum<T> {
7177
}
7278

7379
#[repr(transparent)]
74-
union UnitUnion { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 0
80+
union UnitUnion {
7581
u: (),
7682
}
7783

7884
#[repr(transparent)]
79-
union TooManyFields { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 2
85+
union TooManyFields { //~ ERROR transparent union needs at most one non-zero-sized field, but has 2
8086
u: u32,
8187
s: i32
8288
}
+23-59
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,92 @@
1-
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
2-
--> $DIR/repr-transparent.rs:11:1
3-
|
4-
LL | struct NoFields;
5-
| ^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
6-
7-
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
8-
--> $DIR/repr-transparent.rs:14:1
9-
|
10-
LL | struct ContainsOnlyZst(());
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
12-
13-
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
14-
--> $DIR/repr-transparent.rs:17:1
15-
|
16-
LL | struct ContainsOnlyZstArray([bool; 0]);
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
18-
19-
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
20-
--> $DIR/repr-transparent.rs:20:1
21-
|
22-
LL | struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
24-
25-
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2
26-
--> $DIR/repr-transparent.rs:24:1
1+
error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
2+
--> $DIR/repr-transparent.rs:26:1
273
|
284
LL | struct MultipleNonZst(u8, u8);
295
| ^^^^^^^^^^^^^^^^^^^^^^--^^--^^
306
| | | |
317
| | | this field is non-zero-sized
328
| | this field is non-zero-sized
33-
| needs exactly one non-zero-sized field, but has 2
9+
| needs at most one non-zero-sized field, but has 2
3410

35-
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2
36-
--> $DIR/repr-transparent.rs:30:1
11+
error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
12+
--> $DIR/repr-transparent.rs:32:1
3713
|
3814
LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
3915
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^-------------------^^
4016
| | | |
4117
| | | this field is non-zero-sized
4218
| | this field is non-zero-sized
43-
| needs exactly one non-zero-sized field, but has 2
19+
| needs at most one non-zero-sized field, but has 2
4420

4521
error[E0691]: zero-sized field in transparent struct has alignment larger than 1
46-
--> $DIR/repr-transparent.rs:34:32
22+
--> $DIR/repr-transparent.rs:36:32
4723
|
4824
LL | struct NontrivialAlignZst(u32, [u16; 0]);
4925
| ^^^^^^^^ has alignment larger than 1
5026

5127
error[E0691]: zero-sized field in transparent struct has alignment larger than 1
52-
--> $DIR/repr-transparent.rs:40:24
28+
--> $DIR/repr-transparent.rs:42:24
5329
|
5430
LL | struct GenericAlign<T>(ZstAlign32<T>, u32);
5531
| ^^^^^^^^^^^^^ has alignment larger than 1
5632

5733
error[E0084]: unsupported representation for zero-variant enum
58-
--> $DIR/repr-transparent.rs:42:1
34+
--> $DIR/repr-transparent.rs:44:1
5935
|
6036
LL | #[repr(transparent)]
6137
| ^^^^^^^^^^^^^^^^^^^^
6238
LL | enum Void {}
6339
| ------------ zero-variant enum
6440

6541
error[E0731]: transparent enum needs exactly one variant, but has 0
66-
--> $DIR/repr-transparent.rs:43:1
42+
--> $DIR/repr-transparent.rs:45:1
6743
|
6844
LL | enum Void {}
6945
| ^^^^^^^^^ needs exactly one variant, but has 0
7046

71-
error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 0
72-
--> $DIR/repr-transparent.rs:47:1
73-
|
74-
LL | enum FieldlessEnum {
75-
| ^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
76-
77-
error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 2
78-
--> $DIR/repr-transparent.rs:52:1
47+
error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
48+
--> $DIR/repr-transparent.rs:58:1
7949
|
8050
LL | enum TooManyFieldsEnum {
81-
| ^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2
51+
| ^^^^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
8252
LL | Foo(u32, String),
8353
| --- ------ this field is non-zero-sized
8454
| |
8555
| this field is non-zero-sized
8656

8757
error[E0731]: transparent enum needs exactly one variant, but has 2
88-
--> $DIR/repr-transparent.rs:58:1
58+
--> $DIR/repr-transparent.rs:64:1
8959
|
90-
LL | enum TooManyVariants {
91-
| ^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
60+
LL | enum MultipleVariants {
61+
| ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
9262
LL | Foo(String),
9363
| -----------
9464
LL | Bar,
95-
| --- too many variants in `TooManyVariants`
65+
| --- too many variants in `MultipleVariants`
9666

9767
error[E0691]: zero-sized field in transparent enum has alignment larger than 1
98-
--> $DIR/repr-transparent.rs:65:14
68+
--> $DIR/repr-transparent.rs:71:14
9969
|
10070
LL | Foo(u32, [u16; 0]),
10171
| ^^^^^^^^ has alignment larger than 1
10272

10373
error[E0691]: zero-sized field in transparent enum has alignment larger than 1
104-
--> $DIR/repr-transparent.rs:70:11
74+
--> $DIR/repr-transparent.rs:76:11
10575
|
10676
LL | Foo { bar: ZstAlign32<T>, baz: u32 }
10777
| ^^^^^^^^^^^^^^^^^^ has alignment larger than 1
10878

109-
error[E0690]: transparent union needs exactly one non-zero-sized field, but has 0
110-
--> $DIR/repr-transparent.rs:74:1
111-
|
112-
LL | union UnitUnion {
113-
| ^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0
114-
115-
error[E0690]: transparent union needs exactly one non-zero-sized field, but has 2
116-
--> $DIR/repr-transparent.rs:79:1
79+
error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
80+
--> $DIR/repr-transparent.rs:85:1
11781
|
11882
LL | union TooManyFields {
119-
| ^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2
83+
| ^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
12084
LL | u: u32,
12185
| ------ this field is non-zero-sized
12286
LL | s: i32
12387
| ------ this field is non-zero-sized
12488

125-
error: aborting due to 17 previous errors
89+
error: aborting due to 11 previous errors
12690

12791
Some errors have detailed explanations: E0084, E0690, E0691, E0731.
12892
For more information about an error, try `rustc --explain E0084`.

0 commit comments

Comments
 (0)