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`
This commit is contained in:
bors 2021-06-24 07:29:59 +00:00
commit 456a03227e
5 changed files with 51 additions and 81 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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
@ -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>,
@ -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,

View File

@ -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
@ -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,
}
@ -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
}

View File

@ -1,61 +1,37 @@
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)]
| ^^^^^^^^^^^^^^^^^^^^
@ -63,66 +39,54 @@ 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`.