From ea188e9d21cd88222be1972f18cc50da97173607 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 14 Jun 2021 07:04:56 +0900 Subject: [PATCH 1/2] Permit zero non-zero-field on transparent types --- compiler/rustc_typeck/src/check/check.rs | 2 +- compiler/rustc_typeck/src/check/mod.rs | 6 +- src/test/ui/repr/repr-transparent.rs | 32 +++++---- src/test/ui/repr/repr-transparent.stderr | 82 +++++++----------------- 4 files changed, 46 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 70d85796d002e..77644ea1c3c95 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -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 { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index ad7853b7cd0f1..72d94c3a9c935 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -1029,7 +1029,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 @@ -1048,7 +1048,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>, @@ -1057,7 +1057,7 @@ fn bad_non_zero_sized_fields<'tcx>( field_spans: impl Iterator, 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, diff --git a/src/test/ui/repr/repr-transparent.rs b/src/test/ui/repr/repr-transparent.rs index 8fbdb4cc80b5e..8c9d1639c0a51 100644 --- a/src/test/ui/repr/repr-transparent.rs +++ b/src/test/ui/repr/repr-transparent.rs @@ -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 Mirror for T { type It = Self; } #[repr(transparent)] pub struct StructWithProjection(f32, ::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(PhantomData); struct GenericAlign(ZstAlign32, 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 { } #[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 } diff --git a/src/test/ui/repr/repr-transparent.stderr b/src/test/ui/repr/repr-transparent.stderr index cbc74fbb6a2cf..001a181881f14 100644 --- a/src/test/ui/repr/repr-transparent.stderr +++ b/src/test/ui/repr/repr-transparent.stderr @@ -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, ::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(ZstAlign32, 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, 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`. From 4e755a96a74b7d79a8796f78a194efca5d6d649b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 14 Jun 2021 07:05:14 +0900 Subject: [PATCH 2/2] Adjust documentation --- compiler/rustc_error_codes/src/error_codes/E0690.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0690.md b/compiler/rustc_error_codes/src/error_codes/E0690.md index 1673456580a85..ba706ad2b020b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0690.md +++ b/compiler/rustc_error_codes/src/error_codes/E0690.md @@ -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 { // error: transparent struct needs exactly one +struct LengthWithUnit { // 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