Skip to content

Commit b3708a7

Browse files
committed
compiler/hir/check: clarify error message on transparent ADT
Replace the phrase "layout of non-zero size or alignment larger than 1" with "non-trivial layout", and then elaborate that a layout is trivial if, and only if, it is zero-sized with an alignment of 1. Additionally, add a comment to the check-function explaining which information is gathered to check transparent ADTs, and elaborate why it is needed.
1 parent a594ae1 commit b3708a7

File tree

7 files changed

+44
-21
lines changed

7 files changed

+44
-21
lines changed

compiler/rustc_error_codes/src/error_codes/E0690.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ Erroneous code example:
55

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

compiler/rustc_hir_analysis/messages.ftl

+6-4
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,17 @@ hir_analysis_transparent_enum_variant = transparent enum needs exactly one varia
270270
.many_label = too many variants in `{$path}`
271271
.multi_label = variant here
272272
273-
hir_analysis_transparent_layout = transparent {$desc} needs at most one field of non-zero size or alignment larger than 1, but has {$field_count}
274-
.label = needs at most one field of non-zero size or alignment larger than 1, but has {$field_count}
273+
hir_analysis_transparent_layout = transparent {$desc} needs at most one field with non-trivial layout, but has {$field_count}
274+
.label = needs at most one field with non-trivial layout, but has {$field_count}
275275
.non_layout_labels = this field may have an alignment larger than 1
276276
.non_zst_labels = this field is non-zero-sized
277+
.note = a layout is trivial if, any only if, it is zero-sized with an alignment of 1
277278
278-
hir_analysis_transparent_layout_enum = the variant of a transparent {$desc} needs at most one field of non-zero size or alignment larger than 1, but has {$field_count}
279-
.label = needs at most one field of non-zero size or alignment larger than 1, but has {$field_count}
279+
hir_analysis_transparent_layout_enum = the variant of a transparent {$desc} needs at most one field with non-trivial layout, but has {$field_count}
280+
.label = needs at most one field with non-trivial layout, but has {$field_count}
280281
.non_layout_labels = this field may have an alignment larger than 1
281282
.non_zst_labels = this field is non-zero-sized
283+
.note = a layout is trivial if, any only if, it is zero-sized with an alignment of 1
282284
283285
hir_analysis_typeof_reserved_keyword_used =
284286
`typeof` is a reserved keyword but unimplemented

compiler/rustc_hir_analysis/src/check/check.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1130,8 +1130,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
11301130
return;
11311131
}
11321132

1133-
// For each field, figure out if it's known to be a ZST with layout, with "known"
1134-
// respecting #[non_exhaustive] attributes.
1133+
// For each field, collect information on its layout and whether it has a #[non_exhaustive]
1134+
// annotation.
11351135
let field_infos = adt.all_fields().map(|field| {
11361136
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
11371137
let param_env = tcx.param_env(field.did);
@@ -1178,6 +1178,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
11781178
(span, zst, layout, check_non_exhaustive(tcx, ty).break_value())
11791179
});
11801180

1181+
// For a transparent ADT we must know which member field controls its layout. Hence, we only
1182+
// allow at most one field with non-trivial or unknown layout. A layout is trivial if, and only
1183+
// if, it is zero-sized with an alignment of 1. A layout is unknown if, for instance, it
1184+
// contains generic type parameters or has a #[non_exhaustive] annotation in a non-local type.
1185+
// We will reject any transparent ADT with more than one field with non-trivial or unknown
1186+
// layout, but we try our best to point out the violating properties.
1187+
11811188
let non_layout_fields = field_infos
11821189
.clone()
11831190
.filter_map(|(span, _, layout, _)| if layout.is_err() { Some(span) } else { None });

compiler/rustc_hir_analysis/src/check/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, d
516516
});
517517
}
518518

519-
/// Emit an error when encountering two or more fields without layout or non-zero size
519+
/// Emit an error when encountering two or more fields with non-trivial layout
520520
/// in a transparent Adt.
521521
fn bad_transparent_layout<'tcx>(
522522
tcx: TyCtxt<'tcx>,
@@ -533,6 +533,7 @@ fn bad_transparent_layout<'tcx>(
533533
non_zst_spans: non_zst_spans.collect(),
534534
field_count,
535535
desc: adt.descr(),
536+
note: (),
536537
});
537538
} else {
538539
tcx.sess.emit_err(errors::TransparentLayout {
@@ -541,6 +542,7 @@ fn bad_transparent_layout<'tcx>(
541542
non_zst_spans: non_zst_spans.collect(),
542543
field_count,
543544
desc: adt.descr(),
545+
note: (),
544546
});
545547
}
546548
}

compiler/rustc_hir_analysis/src/errors.rs

+4
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,8 @@ pub(crate) struct TransparentLayoutEnum<'a> {
788788
pub non_zst_spans: Vec<Span>,
789789
pub field_count: usize,
790790
pub desc: &'a str,
791+
#[note]
792+
pub note: (),
791793
}
792794

793795
#[derive(Diagnostic)]
@@ -802,6 +804,8 @@ pub(crate) struct TransparentLayout<'a> {
802804
pub non_zst_spans: Vec<Span>,
803805
pub field_count: usize,
804806
pub desc: &'a str,
807+
#[note]
808+
pub note: (),
805809
}
806810

807811
#[derive(Diagnostic)]

tests/ui/repr/repr-transparent.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ struct ContainsZstAndNonZst((), [i32; 2]);
2424

2525
#[repr(transparent)]
2626
struct MultipleNonZst(u8, u8);
27-
//~^ ERROR needs at most one field of non-zero size or alignment larger than 1
27+
//~^ ERROR needs at most one field with non-trivial layout
2828

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

3232
#[repr(transparent)]
3333
pub struct StructWithProjection(f32, <f32 as Mirror>::It);
34-
//~^ ERROR needs at most one field of non-zero size or alignment larger than 1
34+
//~^ ERROR needs at most one field with non-trivial layout
3535

3636
#[repr(transparent)]
3737
struct NontrivialAlignZst(u32, [u16; 0]); //~ ERROR alignment larger than 1
@@ -59,7 +59,7 @@ enum UnitFieldEnum {
5959
enum TooManyFieldsEnum {
6060
Foo(u32, String),
6161
}
62-
//~^^^ ERROR needs at most one field of non-zero size or alignment larger than 1, but has 2
62+
//~^^^ ERROR needs at most one field with non-trivial layout, but has 2
6363

6464
#[repr(transparent)]
6565
enum MultipleVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
@@ -87,6 +87,6 @@ union TooManyFields {
8787
u: u32,
8888
s: i32
8989
}
90-
//~^^^^ ERROR transparent union needs at most one field of non-zero size or alignment larger than 1, but has 2
90+
//~^^^^ ERROR transparent union needs at most one field with non-trivial layout, but has 2
9191

9292
fn main() {}

tests/ui/repr/repr-transparent.stderr

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
1-
error[E0690]: transparent struct needs at most one field of non-zero size or alignment larger than 1, but has 2
1+
error[E0690]: transparent struct needs at most one field with non-trivial layout, but has 2
22
--> $DIR/repr-transparent.rs:26:1
33
|
44
LL | struct MultipleNonZst(u8, u8);
55
| ^^^^^^^^^^^^^^^^^^^^^ -- -- this field is non-zero-sized
66
| | |
77
| | this field is non-zero-sized
8-
| needs at most one field of non-zero size or alignment larger than 1, but has 2
8+
| needs at most one field with non-trivial layout, but has 2
9+
|
10+
= note: a layout is trivial if, any only if, it is zero-sized with an alignment of 1
911

10-
error[E0690]: transparent struct needs at most one field of non-zero size or alignment larger than 1, but has 2
12+
error[E0690]: transparent struct needs at most one field with non-trivial layout, but has 2
1113
--> $DIR/repr-transparent.rs:33:1
1214
|
1315
LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
1416
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- ------------------- this field is non-zero-sized
1517
| | |
1618
| | this field is non-zero-sized
17-
| needs at most one field of non-zero size or alignment larger than 1, but has 2
19+
| needs at most one field with non-trivial layout, but has 2
20+
|
21+
= note: a layout is trivial if, any only if, it is zero-sized with an alignment of 1
1822

1923
error[E0691]: zero-sized field in transparent struct has alignment larger than 1
2024
--> $DIR/repr-transparent.rs:37:32
@@ -42,15 +46,17 @@ error[E0731]: transparent enum needs exactly one variant, but has 0
4246
LL | enum Void {}
4347
| ^^^^^^^^^ needs exactly one variant, but has 0
4448

45-
error[E0690]: the variant of a transparent enum needs at most one field of non-zero size or alignment larger than 1, but has 2
49+
error[E0690]: the variant of a transparent enum needs at most one field with non-trivial layout, but has 2
4650
--> $DIR/repr-transparent.rs:59:1
4751
|
4852
LL | enum TooManyFieldsEnum {
49-
| ^^^^^^^^^^^^^^^^^^^^^^ needs at most one field of non-zero size or alignment larger than 1, but has 2
53+
| ^^^^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial layout, but has 2
5054
LL | Foo(u32, String),
5155
| --- ------ this field is non-zero-sized
5256
| |
5357
| this field is non-zero-sized
58+
|
59+
= note: a layout is trivial if, any only if, it is zero-sized with an alignment of 1
5460

5561
error[E0731]: transparent enum needs exactly one variant, but has 2
5662
--> $DIR/repr-transparent.rs:65:1
@@ -74,15 +80,17 @@ error[E0691]: zero-sized field in transparent enum has alignment larger than 1
7480
LL | Foo { bar: ZstAlign32<T>, baz: u32 }
7581
| ^^^^^^^^^^^^^^^^^^ has alignment of 32, which is larger than 1
7682

77-
error[E0690]: transparent union needs at most one field of non-zero size or alignment larger than 1, but has 2
83+
error[E0690]: transparent union needs at most one field with non-trivial layout, but has 2
7884
--> $DIR/repr-transparent.rs:86:1
7985
|
8086
LL | union TooManyFields {
81-
| ^^^^^^^^^^^^^^^^^^^ needs at most one field of non-zero size or alignment larger than 1, but has 2
87+
| ^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial layout, but has 2
8288
LL | u: u32,
8389
| ------ this field is non-zero-sized
8490
LL | s: i32
8591
| ------ this field is non-zero-sized
92+
|
93+
= note: a layout is trivial if, any only if, it is zero-sized with an alignment of 1
8694

8795
error: aborting due to 11 previous errors
8896

0 commit comments

Comments
 (0)