[PATCH 2/3] rust: pin-init: internal: init: improve diagnostics from field checks
From: Gary Guo
Date: Mon Sep 28 2026 - 13:34:41 EST
Use span of the field name for generated alignment and field duplication
checks. This avoids pointing diagnostics to the full macro invocation, but
just the part of it going wrong.
Before the change:
error[E0062]: field `0` specified more than once
--> tests/ui/compile-fail/init/tuple_duplicate_field.rs:7:37
|
7 | let _ = pin_init!(Tuple { 0: 1, 0: 2, 1: 3 });
| ------------------------^------------
| | |
| | used more than once
| first use of `0`
After the change:
error[E0062]: field `0` specified more than once
--> tests/ui/compile-fail/init/tuple_duplicate_field.rs:7:37
|
7 | let _ = pin_init!(Tuple { 0: 1, 0: 2, 1: 3 });
| - ^ used more than once
| |
| first use of `0`
Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
---
rust/pin-init/internal/src/init.rs | 65 ++++++++++++++++++++++++--------------
1 file changed, 42 insertions(+), 23 deletions(-)
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 4e77c7af86f9..f6f3e2f8cda6 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -478,42 +478,61 @@ fn make_field_check(
init_kind: InitKind,
path: &Path,
) -> TokenStream {
- let field_attrs: Vec<_> = fields
+ let align_checks: TokenStream = fields
.iter()
- .filter_map(|f| f.kind.member().map(|_| &f.attrs))
+ .filter_map(|f| {
+ let member = f.kind.member()?;
+ let span = member.span().resolved_at(Span::mixed_site());
+ let attrs = &f.attrs;
+
+ Some(quote_spanned! {span =>
+ // Create references to ensure that the initialized field is properly aligned.
+ // Unaligned fields will cause the compiler to emit E0793. We do not support
+ // unaligned fields since `Init::__init` requires an aligned pointer; the call to
+ // `ptr::write` for value-initialization case has the same requirement.
+ #(#attrs)*
+ let _ = &(*slot).#member;
+ })
+ })
+ .collect();
+
+ let fake_field_init: TokenStream = fields
+ .iter()
+ .filter_map(|f| {
+ let member = f.kind.member()?;
+ let span = member.span().resolved_at(Span::mixed_site());
+ let attrs = &f.attrs;
+
+ Some(quote_spanned! {span =>
+ #(#attrs)*
+ #member: loop {},
+ })
+ })
.collect();
- let field_name: Vec<_> = fields.iter().filter_map(|f| f.kind.member()).collect();
let zeroing_trailer = match init_kind {
InitKind::Normal => None,
InitKind::Zeroing => Some(quote! {
..::core::mem::zeroed()
}),
};
+ let field_dup_checks = quote_spanned! { Span::mixed_site() =>
+ // If the zeroing trailer is not present, this checks that all fields have been
+ // mentioned exactly once. If the zeroing trailer is present, all missing fields will be
+ // zeroed, so this checks that all fields have been mentioned at most once. The use of
+ // struct initializer will still generate very natural error messages for any misuse.
+ ::core::ptr::write(slot, #path {
+ #fake_field_init
+ #zeroing_trailer
+ })
+ };
+
quote_spanned! { Span::mixed_site() =>
#[allow(unreachable_code)]
// We use unreachable code to perform field checks. They're still checked by the compiler.
// SAFETY: this code is never executed.
let _ = || unsafe {
- // Create references to ensure that the initialized field is properly aligned.
- // Unaligned fields will cause the compiler to emit E0793. We do not support
- // unaligned fields since `Init::__init` requires an aligned pointer; the call to
- // `ptr::write` for value-initialization case has the same requirement.
- #(
- #(#field_attrs)*
- let _ = &(*slot).#field_name;
- )*
-
- // If the zeroing trailer is not present, this checks that all fields have been
- // mentioned exactly once. If the zeroing trailer is present, all missing fields will be
- // zeroed, so this checks that all fields have been mentioned at most once. The use of
- // struct initializer will still generate very natural error messages for any misuse.
- ::core::ptr::write(slot, #path {
- #(
- #(#field_attrs)*
- #field_name: loop {},
- )*
- #zeroing_trailer
- })
+ #align_checks
+ #field_dup_checks
};
}
}
--
2.54.0