diff options
| author | David Rheinsberg <david@readahead.eu> | 2023-07-21 09:32:28 +0200 |
|---|---|---|
| committer | David Rheinsberg <david@readahead.eu> | 2023-07-21 11:04:16 +0200 |
| commit | b0dadff6de0a0d17b38ebfcae333cc88a8b6e47e (patch) | |
| tree | 9ad5aebae53562260320195f4348382b5aedfc25 | |
| parent | 1a44b45987a56dc1bbb4fc8327aa46efa58d5eaa (diff) | |
| download | rust-b0dadff6de0a0d17b38ebfcae333cc88a8b6e47e.tar.gz rust-b0dadff6de0a0d17b38ebfcae333cc88a8b6e47e.zip | |
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:
LL | struct Foobar(u32, [u32; 0]);
| ^^^^^^^^ has alignment larger than 1
This patch changes the report to include the alignment of the violating
field:
LL | struct Foobar(u32, [u32; 0]);
| ^^^^^^^^ has alignment of 4, which is larger than 1
In case of unknown alignments, it will yield:
LL | struct Foobar<T>(u32, [T; 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.
| -rw-r--r-- | compiler/rustc_error_codes/src/error_codes/E0691.md | 3 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/check.rs | 29 | ||||
| -rw-r--r-- | tests/ui/repr/repr-transparent.stderr | 8 |
3 files changed, 25 insertions, 15 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0691.md b/compiler/rustc_error_codes/src/error_codes/E0691.md index 60060cacbd6..483c74c0ff5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0691.md +++ b/compiler/rustc_error_codes/src/error_codes/E0691.md @@ -11,7 +11,8 @@ struct ForceAlign32; #[repr(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 diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d9e14096954..e0698a72335 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -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 let span = tcx.hir().span_if_local(field.did).unwrap(); 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 { - return (span, zst, align1, None); + return (span, zst, align, None); } fn check_non_exhaustive<'tcx>( @@ -1115,12 +1115,12 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'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 .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(); if non_zst_count >= 2 { bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did())); @@ -1128,17 +1128,26 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) let incompatible_zst_fields = field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count(); let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2; - for (span, zst, align1, non_exhaustive) in field_infos { - if zst && !align1 { - struct_span_err!( + for (span, zst, align, non_exhaustive) in field_infos { + if zst && align != Some(1) { + let mut err = struct_span_err!( tcx.sess, span, E0691, "zero-sized field in transparent {} has alignment larger than 1", 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 { tcx.struct_span_lint_hir( diff --git a/tests/ui/repr/repr-transparent.stderr b/tests/ui/repr/repr-transparent.stderr index cb1e2337776..028fc25db46 100644 --- a/tests/ui/repr/repr-transparent.stderr +++ b/tests/ui/repr/repr-transparent.stderr @@ -20,13 +20,13 @@ error[E0691]: zero-sized field in transparent struct has alignment larger than 1 --> $DIR/repr-transparent.rs:36:32 | 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 --> $DIR/repr-transparent.rs:42:24 | 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 --> $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 | 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 --> $DIR/repr-transparent.rs:76:11 | 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 --> $DIR/repr-transparent.rs:85:1 |
