Rollup merge of #113913 - dvdhrm:pr/transpalign, r=jackh726
error/E0691: include alignment in error message Include the computed alignment of the violating field when rejecting transparent types with non-trivially aligned ZSTs. ZST member fields in transparent types must have an alignment of 1 (to ensure it does not raise the layout requirements of the transparent field). The current error message looks like this: ```text LL | struct Foobar(u32, [u32; 0]); | ^^^^^^^^ has alignment larger than 1 ``` This patch changes the report to include the alignment of the violating field: ```text LL | struct Foobar(u32, [u32; 0]); | ^^^^^^^^ has alignment of 4, which is larger than 1 ``` In case of unknown alignments, it will yield: ```text LL | struct Foobar(u32, [u32; 0]); | ^^^^^^^^ may have alignment larger than 1 ``` This allows developers to get a better grasp why a specific field is rejected. Knowing the alignment of the violating field makes it easier to judge where that alignment-requirement originates, and thus hopefully provide better hints on how to mitigate the problem. This idea was proposed in 2022 in #98071 as part of a bigger change. This commit simply extracts this error-message change, to decouple it from the other diagnostic improvements. (Originally proposed by `@compiler-errors` in #98071)
This commit is contained in:
commit
4a90553717
@ -11,7 +11,8 @@ struct ForceAlign32;
|
|||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct Wrapper(f32, ForceAlign32); // error: zero-sized field in transparent
|
struct Wrapper(f32, ForceAlign32); // error: zero-sized field in transparent
|
||||||
// struct has alignment larger than 1
|
// struct has alignment of 32, which
|
||||||
|
// is larger than 1
|
||||||
```
|
```
|
||||||
|
|
||||||
A transparent struct, enum, or union is supposed to be represented exactly like
|
A transparent struct, enum, or union is supposed to be represented exactly like
|
||||||
|
@ -1078,9 +1078,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
|||||||
// We are currently checking the type this field came from, so it must be local
|
// We are currently checking the type this field came from, so it must be local
|
||||||
let span = tcx.hir().span_if_local(field.did).unwrap();
|
let span = tcx.hir().span_if_local(field.did).unwrap();
|
||||||
let zst = layout.is_ok_and(|layout| layout.is_zst());
|
let zst = layout.is_ok_and(|layout| layout.is_zst());
|
||||||
let align1 = layout.is_ok_and(|layout| layout.align.abi.bytes() == 1);
|
let align = layout.ok().map(|layout| layout.align.abi.bytes());
|
||||||
if !zst {
|
if !zst {
|
||||||
return (span, zst, align1, None);
|
return (span, zst, align, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_non_exhaustive<'tcx>(
|
fn check_non_exhaustive<'tcx>(
|
||||||
@ -1115,12 +1115,12 @@ fn check_non_exhaustive<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(span, zst, align1, check_non_exhaustive(tcx, ty).break_value())
|
(span, zst, align, check_non_exhaustive(tcx, ty).break_value())
|
||||||
});
|
});
|
||||||
|
|
||||||
let non_zst_fields = field_infos
|
let non_zst_fields = field_infos
|
||||||
.clone()
|
.clone()
|
||||||
.filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
|
.filter_map(|(span, zst, _align, _non_exhaustive)| 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 >= 2 {
|
if non_zst_count >= 2 {
|
||||||
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
|
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
|
||||||
@ -1128,17 +1128,26 @@ fn check_non_exhaustive<'tcx>(
|
|||||||
let incompatible_zst_fields =
|
let incompatible_zst_fields =
|
||||||
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
|
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
|
||||||
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
|
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
|
||||||
for (span, zst, align1, non_exhaustive) in field_infos {
|
for (span, zst, align, non_exhaustive) in field_infos {
|
||||||
if zst && !align1 {
|
if zst && align != Some(1) {
|
||||||
struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
span,
|
span,
|
||||||
E0691,
|
E0691,
|
||||||
"zero-sized field in transparent {} has alignment larger than 1",
|
"zero-sized field in transparent {} has alignment larger than 1",
|
||||||
adt.descr(),
|
adt.descr(),
|
||||||
)
|
);
|
||||||
.span_label(span, "has alignment larger than 1")
|
|
||||||
.emit();
|
if let Some(align_bytes) = align {
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!("has alignment of {align_bytes}, which is larger than 1"),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.span_label(span, "may have alignment larger than 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
err.emit();
|
||||||
}
|
}
|
||||||
if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive {
|
if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive {
|
||||||
tcx.struct_span_lint_hir(
|
tcx.struct_span_lint_hir(
|
||||||
|
@ -20,13 +20,13 @@ error[E0691]: zero-sized field in transparent struct has alignment larger than 1
|
|||||||
--> $DIR/repr-transparent.rs:36: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 of 2, which is 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:42: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 of 32, which is larger than 1
|
||||||
|
|
||||||
error[E0084]: unsupported representation for zero-variant enum
|
error[E0084]: unsupported representation for zero-variant enum
|
||||||
--> $DIR/repr-transparent.rs:44:1
|
--> $DIR/repr-transparent.rs:44:1
|
||||||
@ -66,13 +66,13 @@ error[E0691]: zero-sized field in transparent enum has alignment larger than 1
|
|||||||
--> $DIR/repr-transparent.rs:71:14
|
--> $DIR/repr-transparent.rs:71:14
|
||||||
|
|
|
|
||||||
LL | Foo(u32, [u16; 0]),
|
LL | Foo(u32, [u16; 0]),
|
||||||
| ^^^^^^^^ has alignment larger than 1
|
| ^^^^^^^^ has alignment of 2, which is 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:76: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 of 32, which is larger than 1
|
||||||
|
|
||||||
error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
|
error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
|
||||||
--> $DIR/repr-transparent.rs:85:1
|
--> $DIR/repr-transparent.rs:85:1
|
||||||
|
Loading…
Reference in New Issue
Block a user