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:
commit
456a03227e
5 changed files with 51 additions and 81 deletions
|
@ -1,19 +1,19 @@
|
||||||
A struct with the representation hint `repr(transparent)` had zero or more than
|
A struct with the representation hint `repr(transparent)` had two or more fields
|
||||||
one fields that were not guaranteed to be zero-sized.
|
that were not guaranteed to be zero-sized.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0690
|
```compile_fail,E0690
|
||||||
#[repr(transparent)]
|
#[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
|
value: f32, // non-zero-sized field, but has 2
|
||||||
unit: U,
|
unit: U,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Because transparent structs are represented exactly like one of their fields at
|
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
|
run time, said field must be uniquely determined. If there are multiple fields,
|
||||||
there are multiple fields, it is not clear how the struct should be represented.
|
it is not clear how the struct should be represented.
|
||||||
Note that fields of zero-sized types (e.g., `PhantomData`) can also exist
|
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
|
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
|
error. When generic types are involved (as in the above example), an error is
|
||||||
|
|
|
@ -1382,7 +1382,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty
|
||||||
let non_zst_fields =
|
let non_zst_fields =
|
||||||
field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
|
field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
|
||||||
let non_zst_count = non_zst_fields.clone().count();
|
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);
|
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
|
||||||
}
|
}
|
||||||
for (span, zst, align1) in field_infos {
|
for (span, zst, align1) in field_infos {
|
||||||
|
|
|
@ -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) {
|
fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) {
|
||||||
let variant_spans: Vec<_> = adt
|
let variant_spans: Vec<_> = adt
|
||||||
.variants
|
.variants
|
||||||
|
@ -1039,7 +1039,7 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, d
|
||||||
err.emit();
|
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.
|
/// enum.
|
||||||
fn bad_non_zero_sized_fields<'tcx>(
|
fn bad_non_zero_sized_fields<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
@ -1048,7 +1048,7 @@ fn bad_non_zero_sized_fields<'tcx>(
|
||||||
field_spans: impl Iterator<Item = Span>,
|
field_spans: impl Iterator<Item = Span>,
|
||||||
sp: 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!(
|
let mut err = struct_span_err!(
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
sp,
|
sp,
|
||||||
|
|
|
@ -8,27 +8,29 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct NoFields; //~ ERROR needs exactly one non-zero-sized field
|
struct NoFields;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct ContainsOnlyZst(()); //~ ERROR needs exactly one non-zero-sized field
|
struct ContainsOnlyZst(());
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct ContainsOnlyZstArray([bool; 0]); //~ ERROR needs exactly one non-zero-sized field
|
struct ContainsOnlyZstArray([bool; 0]);
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
|
struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
|
||||||
//~^ ERROR needs exactly one non-zero-sized field
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[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; }
|
trait Mirror { type It: ?Sized; }
|
||||||
impl<T: ?Sized> Mirror for T { type It = Self; }
|
impl<T: ?Sized> Mirror for T { type It = Self; }
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct StructWithProjection(f32, <f32 as Mirror>::It);
|
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)]
|
#[repr(transparent)]
|
||||||
struct NontrivialAlignZst(u32, [u16; 0]); //~ ERROR alignment larger than 1
|
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
|
struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
|
||||||
|
|
||||||
#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
|
#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
|
||||||
enum Void {}
|
enum Void {} //~ ERROR transparent enum needs exactly one variant, but has 0
|
||||||
//~^ ERROR transparent enum needs exactly one variant, but has 0
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
enum FieldlessEnum { //~ ERROR transparent enum needs exactly one non-zero-sized field, but has 0
|
enum FieldlessEnum {
|
||||||
Foo,
|
Foo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
enum UnitFieldEnum {
|
||||||
|
Foo(()),
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
enum TooManyFieldsEnum {
|
enum TooManyFieldsEnum {
|
||||||
Foo(u32, String),
|
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)]
|
#[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),
|
Foo(String),
|
||||||
Bar,
|
Bar,
|
||||||
}
|
}
|
||||||
|
@ -71,12 +77,12 @@ enum GenericAlignEnum<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
union UnitUnion { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 0
|
union UnitUnion {
|
||||||
u: (),
|
u: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[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,
|
u: u32,
|
||||||
s: i32
|
s: i32
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +1,37 @@
|
||||||
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
|
error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
|
||||||
--> $DIR/repr-transparent.rs:11:1
|
--> $DIR/repr-transparent.rs:26: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
|
|
||||||
|
|
|
|
||||||
LL | struct MultipleNonZst(u8, u8);
|
LL | struct MultipleNonZst(u8, u8);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^--^^--^^
|
| ^^^^^^^^^^^^^^^^^^^^^^--^^--^^
|
||||||
| | | |
|
| | | |
|
||||||
| | | this field is non-zero-sized
|
| | | this field is non-zero-sized
|
||||||
| | 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
|
error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
|
||||||
--> $DIR/repr-transparent.rs:30:1
|
--> $DIR/repr-transparent.rs:32:1
|
||||||
|
|
|
|
||||||
LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
|
LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^-------------------^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^-------------------^^
|
||||||
| | | |
|
| | | |
|
||||||
| | | this field is non-zero-sized
|
| | | this field is non-zero-sized
|
||||||
| | 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
|
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]);
|
LL | struct NontrivialAlignZst(u32, [u16; 0]);
|
||||||
| ^^^^^^^^ has alignment larger than 1
|
| ^^^^^^^^ has alignment larger than 1
|
||||||
|
|
||||||
error[E0691]: zero-sized field in transparent struct 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);
|
LL | struct GenericAlign<T>(ZstAlign32<T>, u32);
|
||||||
| ^^^^^^^^^^^^^ has alignment larger than 1
|
| ^^^^^^^^^^^^^ has alignment larger than 1
|
||||||
|
|
||||||
error[E0084]: unsupported representation for zero-variant enum
|
error[E0084]: unsupported representation for zero-variant enum
|
||||||
--> $DIR/repr-transparent.rs:42:1
|
--> $DIR/repr-transparent.rs:44:1
|
||||||
|
|
|
|
||||||
LL | #[repr(transparent)]
|
LL | #[repr(transparent)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -63,66 +39,54 @@ LL | enum Void {}
|
||||||
| ------------ zero-variant enum
|
| ------------ zero-variant enum
|
||||||
|
|
||||||
error[E0731]: transparent enum needs exactly one variant, but has 0
|
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 {}
|
LL | enum Void {}
|
||||||
| ^^^^^^^^^ needs exactly one variant, but has 0
|
| ^^^^^^^^^ 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
|
error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
|
||||||
--> $DIR/repr-transparent.rs:47:1
|
--> $DIR/repr-transparent.rs:58: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
|
|
||||||
|
|
|
|
||||||
LL | enum TooManyFieldsEnum {
|
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),
|
LL | Foo(u32, String),
|
||||||
| --- ------ this field is non-zero-sized
|
| --- ------ this field is non-zero-sized
|
||||||
| |
|
| |
|
||||||
| this field is non-zero-sized
|
| this field is non-zero-sized
|
||||||
|
|
||||||
error[E0731]: transparent enum needs exactly one variant, but has 2
|
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 {
|
LL | enum MultipleVariants {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
|
| ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
|
||||||
LL | Foo(String),
|
LL | Foo(String),
|
||||||
| -----------
|
| -----------
|
||||||
LL | Bar,
|
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
|
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]),
|
LL | Foo(u32, [u16; 0]),
|
||||||
| ^^^^^^^^ has alignment larger than 1
|
| ^^^^^^^^ has alignment larger than 1
|
||||||
|
|
||||||
error[E0691]: zero-sized field in transparent enum 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 }
|
LL | Foo { bar: ZstAlign32<T>, baz: u32 }
|
||||||
| ^^^^^^^^^^^^^^^^^^ has alignment larger than 1
|
| ^^^^^^^^^^^^^^^^^^ has alignment larger than 1
|
||||||
|
|
||||||
error[E0690]: transparent union needs exactly one non-zero-sized field, but has 0
|
error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
|
||||||
--> $DIR/repr-transparent.rs:74:1
|
--> $DIR/repr-transparent.rs:85: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
|
|
||||||
|
|
|
|
||||||
LL | union TooManyFields {
|
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,
|
LL | u: u32,
|
||||||
| ------ this field is non-zero-sized
|
| ------ this field is non-zero-sized
|
||||||
LL | s: i32
|
LL | s: i32
|
||||||
| ------ this field is non-zero-sized
|
| ------ 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.
|
Some errors have detailed explanations: E0084, E0690, E0691, E0731.
|
||||||
For more information about an error, try `rustc --explain E0084`.
|
For more information about an error, try `rustc --explain E0084`.
|
||||||
|
|
Loading…
Add table
Reference in a new issue