Skip to content

Commit

Permalink
Auto merge of #86279 - JohnTitor:transparent-zero-size-fields, r=niko…
Browse files Browse the repository at this point in the history
…matsakis

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`
  • Loading branch information
bors committed Jun 24, 2021
2 parents 964a81e + 4e755a9 commit 456a032
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 81 deletions.
10 changes: 5 additions & 5 deletions compiler/rustc_error_codes/src/error_codes/E0690.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
A struct with the representation hint `repr(transparent)` had zero or more than
one fields that were not guaranteed to be zero-sized.
A struct with the representation hint `repr(transparent)` had two or more fields
that were not guaranteed to be zero-sized.

Erroneous code example:

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

Because transparent structs are represented exactly like one of their fields at
run time, said field must be uniquely determined. If there is no field, or if
there are multiple fields, it is not clear how the struct should be represented.
run time, said field must be uniquely determined. If there are multiple fields,
it is not clear how the struct should be represented.
Note that fields of zero-sized types (e.g., `PhantomData`) can also exist
alongside the field that contains the actual data, they do not count for this
error. When generic types are involved (as in the above example), an error is
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1382,7 +1382,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty
let non_zst_fields =
field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
let non_zst_count = non_zst_fields.clone().count();
if non_zst_count != 1 {
if non_zst_count >= 2 {
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
}
for (span, zst, align1) in field_infos {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_typeck/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
}
}

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

/// Emit an error when encountering more or less than one non-zero-sized field in a transparent
/// Emit an error when encountering two or more non-zero-sized fields in a transparent
/// enum.
fn bad_non_zero_sized_fields<'tcx>(
tcx: TyCtxt<'tcx>,
Expand All @@ -1048,7 +1048,7 @@ fn bad_non_zero_sized_fields<'tcx>(
field_spans: impl Iterator<Item = Span>,
sp: Span,
) {
let msg = format!("needs exactly one non-zero-sized field, but has {}", field_count);
let msg = format!("needs at most one non-zero-sized field, but has {}", field_count);
let mut err = struct_span_err!(
tcx.sess,
sp,
Expand Down
32 changes: 19 additions & 13 deletions src/test/ui/repr/repr-transparent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,29 @@
use std::marker::PhantomData;

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

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

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

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

#[repr(transparent)]
struct MultipleNonZst(u8, u8); //~ ERROR needs exactly one non-zero-sized field
struct ContainsZstAndNonZst((), [i32; 2]);

#[repr(transparent)]
struct MultipleNonZst(u8, u8); //~ ERROR needs at most one non-zero-sized field

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

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

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

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

#[repr(transparent)]
enum FieldlessEnum { //~ ERROR transparent enum needs exactly one non-zero-sized field, but has 0
enum FieldlessEnum {
Foo,
}

#[repr(transparent)]
enum UnitFieldEnum {
Foo(()),
}

#[repr(transparent)]
enum TooManyFieldsEnum {
Foo(u32, String),
}
//~^^^ ERROR transparent enum needs exactly one non-zero-sized field, but has 2
//~^^^ ERROR transparent enum needs at most one non-zero-sized field, but has 2

#[repr(transparent)]
enum TooManyVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
enum MultipleVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
Foo(String),
Bar,
}
Expand All @@ -71,12 +77,12 @@ enum GenericAlignEnum<T> {
}

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

#[repr(transparent)]
union TooManyFields { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 2
union TooManyFields { //~ ERROR transparent union needs at most one non-zero-sized field, but has 2
u: u32,
s: i32
}
Expand Down
82 changes: 23 additions & 59 deletions src/test/ui/repr/repr-transparent.stderr
Original file line number Diff line number Diff line change
@@ -1,128 +1,92 @@
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
--> $DIR/repr-transparent.rs:11:1
|
LL | struct NoFields;
| ^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0

error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
--> $DIR/repr-transparent.rs:14:1
|
LL | struct ContainsOnlyZst(());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0

error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
--> $DIR/repr-transparent.rs:17:1
|
LL | struct ContainsOnlyZstArray([bool; 0]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0

error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
--> $DIR/repr-transparent.rs:20:1
|
LL | struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0

error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:24:1
error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:26:1
|
LL | struct MultipleNonZst(u8, u8);
| ^^^^^^^^^^^^^^^^^^^^^^--^^--^^
| | | |
| | | this field is non-zero-sized
| | this field is non-zero-sized
| needs exactly one non-zero-sized field, but has 2
| needs at most one non-zero-sized field, but has 2

error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:30:1
error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:32:1
|
LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^-------------------^^
| | | |
| | | this field is non-zero-sized
| | this field is non-zero-sized
| needs exactly one non-zero-sized field, but has 2
| needs at most one non-zero-sized field, but has 2

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

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

error[E0084]: unsupported representation for zero-variant enum
--> $DIR/repr-transparent.rs:42:1
--> $DIR/repr-transparent.rs:44:1
|
LL | #[repr(transparent)]
| ^^^^^^^^^^^^^^^^^^^^
LL | enum Void {}
| ------------ zero-variant enum

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

error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 0
--> $DIR/repr-transparent.rs:47:1
|
LL | enum FieldlessEnum {
| ^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0

error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:52:1
error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:58:1
|
LL | enum TooManyFieldsEnum {
| ^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2
| ^^^^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
LL | Foo(u32, String),
| --- ------ this field is non-zero-sized
| |
| this field is non-zero-sized

error[E0731]: transparent enum needs exactly one variant, but has 2
--> $DIR/repr-transparent.rs:58:1
--> $DIR/repr-transparent.rs:64:1
|
LL | enum TooManyVariants {
| ^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
LL | enum MultipleVariants {
| ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
LL | Foo(String),
| -----------
LL | Bar,
| --- too many variants in `TooManyVariants`
| --- too many variants in `MultipleVariants`

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

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

error[E0690]: transparent union needs exactly one non-zero-sized field, but has 0
--> $DIR/repr-transparent.rs:74:1
|
LL | union UnitUnion {
| ^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0

error[E0690]: transparent union needs exactly one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:79:1
error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:85:1
|
LL | union TooManyFields {
| ^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2
| ^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
LL | u: u32,
| ------ this field is non-zero-sized
LL | s: i32
| ------ this field is non-zero-sized

error: aborting due to 17 previous errors
error: aborting due to 11 previous errors

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

0 comments on commit 456a032

Please sign in to comment.