* [PATCH 0/3] rust: pin-init: provide better span for diagnostics
@ 2026-09-16 12:11 Gary Guo
2026-09-16 12:11 ` [PATCH 1/3] rust: pin-init: internal: pin_init: emit `slot` using mixed site hygiene Gary Guo
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Gary Guo @ 2026-09-16 12:11 UTC (permalink / raw)
To: Benno Lossin, Gary Guo, Miguel Ojeda, Boqun Feng,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan
Cc: rust-for-linux, linux-kernel
When initializing a field, pin-init first projects the full slot to a slot
of the field, then initialize it by invoking a method. Currently the span
location is not explicitly set, so the error message points to the full
macro invocation.
Improve it by provide a span, so Rust will point to the specific fields
causing the error when type check fails.
Old error message:
error[E0308]: mismatched types
--> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
|
8 | let _ = init!(Foo { a: () });
| ---------------^^---
| | |
| | expected `usize`, found `()`
| arguments to this method are incorrect
New error message:
error[E0308]: mismatched types
--> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
|
8 | let _ = init!(Foo { a: () });
| ---^^
| | |
| | expected `usize`, found `()`
| arguments to this method are incorrect
---
Gary Guo (3):
rust: pin-init: internal: pin_init: emit `slot` using mixed site hygiene
rust: pin-init: internal: pin_init: use `slot` identifier directly with mixed site
rust: pin-init: internal: pin_init: provide span for slot projection
rust/pin-init/internal/src/init.rs | 48 +++++++++++++++++---------------------
1 file changed, 21 insertions(+), 27 deletions(-)
---
base-commit: 3b3ff9034a497fb3b8429f6fe8ba5697bc7dcebd
change-id: 20260916-dev-hygiene-5473c74b5b63
Best regards,
--
Gary Guo <gary@garyguo.net>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/3] rust: pin-init: internal: pin_init: emit `slot` using mixed site hygiene
2026-09-16 12:11 [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
@ 2026-09-16 12:11 ` Gary Guo
2026-09-16 12:11 ` [PATCH 2/3] rust: pin-init: internal: pin_init: use `slot` identifier directly with mixed site Gary Guo
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Gary Guo @ 2026-09-16 12:11 UTC (permalink / raw)
To: Benno Lossin, Gary Guo, Miguel Ojeda, Boqun Feng,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan
Cc: rust-for-linux, linux-kernel
Syn/quote's default is the call site hygiene. If user provides a field
named `slot`, it will conflict with pin-init generated `slot` identifier.
Change it to use mixed site hygiene instead.
Fixes: 4883830e9784 ("rust: pin-init: rewrite the initializer macros using `syn`")
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/init.rs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index dc5dfb2ca114..6ade192d27e6 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
use proc_macro2::{Span, TokenStream};
-use quote::{format_ident, quote, ToTokens, TokenStreamExt};
+use quote::{format_ident, quote, quote_spanned, ToTokens, TokenStreamExt};
use syn::{
braced, parenthesized,
parse::{End, Parse},
@@ -269,7 +269,7 @@ fn expand(
},
|(_, err)| Box::new(err),
);
- let slot = format_ident!("slot");
+ let slot = Ident::new("slot", Span::mixed_site());
let (has_data_trait, get_data, init_from_closure) = if pinned {
(
format_ident!("HasPinData"),
@@ -302,7 +302,7 @@ fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
};
let this = match this {
None => quote!(),
- Some(This { ident, .. }) => quote! {
+ Some(This { ident, .. }) => quote_spanned! { Span::mixed_site() =>
// Create the `this` so it can be referenced by the user inside of the
// expressions creating the individual fields.
let #ident = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };
@@ -312,7 +312,7 @@ fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
let data = Ident::new("__data", Span::mixed_site());
let init_fields = init_fields(&fields, pinned, &data, &slot);
let field_check = make_field_check(&fields, init_kind, &path);
- Ok(quote! {{
+ Ok(quote_spanned! { Span::mixed_site() => {
// Get the data about fields from the supplied type.
// SAFETY: TODO
let #data = unsafe {
@@ -512,7 +512,7 @@ fn make_field_check(
..::core::mem::zeroed()
}),
};
- quote! {
+ 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.
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3] rust: pin-init: internal: pin_init: use `slot` identifier directly with mixed site
2026-09-16 12:11 [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
2026-09-16 12:11 ` [PATCH 1/3] rust: pin-init: internal: pin_init: emit `slot` using mixed site hygiene Gary Guo
@ 2026-09-16 12:11 ` Gary Guo
2026-09-16 12:11 ` [PATCH 3/3] rust: pin-init: internal: pin_init: provide span for slot projection Gary Guo
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Gary Guo @ 2026-09-16 12:11 UTC (permalink / raw)
To: Benno Lossin, Gary Guo, Miguel Ojeda, Boqun Feng,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan
Cc: rust-for-linux, linux-kernel
Use `quote_spanned!(Span::mixed_site() => ...)` directly instead of
creating `slot` identifier and interpolate it later. Do the same for
`__data`, too.
This is needed so that we can customize the location of the span without
having the `slot` identifier getting in the way. For example:
quote_spanned!(Span::mixed_site().located_at(loc) => ...)
with `slot` mentioned directly will have the diagnostic pointing to the
desired location, while `#slot` won't.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/init.rs | 31 ++++++++++++-------------------
1 file changed, 12 insertions(+), 19 deletions(-)
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 6ade192d27e6..a77ffef9926b 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -269,7 +269,6 @@ fn expand(
},
|(_, err)| Box::new(err),
);
- let slot = Ident::new("slot", Span::mixed_site());
let (has_data_trait, get_data, init_from_closure) = if pinned {
(
format_ident!("HasPinData"),
@@ -286,7 +285,7 @@ fn expand(
let init_kind = get_init_kind(rest, dcx);
let zeroable_check = match init_kind {
InitKind::Normal => quote!(),
- InitKind::Zeroing => quote! {
+ InitKind::Zeroing => quote_spanned! { Span::mixed_site() =>
// The user specified `..Zeroable::zeroed()` at the end of the list of fields.
// Therefore we check if the struct implements `Zeroable` and then zero the memory.
// This allows us to also remove the check that all fields are present (since we
@@ -295,9 +294,9 @@ fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
where T: ::pin_init::Zeroable
{}
// Ensure that the struct is indeed `Zeroable`.
- assert_zeroable(#slot);
+ assert_zeroable(slot);
// SAFETY: The type implements `Zeroable` by the check above.
- unsafe { ::core::ptr::write_bytes(#slot, 0, 1) };
+ unsafe { ::core::ptr::write_bytes(slot, 0, 1) };
},
};
let this = match this {
@@ -309,20 +308,19 @@ fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
},
};
// `mixed_site` ensures that the data is not accessible to the user-controlled code.
- let data = Ident::new("__data", Span::mixed_site());
- let init_fields = init_fields(&fields, pinned, &data, &slot);
+ let init_fields = init_fields(&fields, pinned);
let field_check = make_field_check(&fields, init_kind, &path);
Ok(quote_spanned! { Span::mixed_site() => {
// Get the data about fields from the supplied type.
// SAFETY: TODO
- let #data = unsafe {
+ let data = unsafe {
use ::pin_init::__internal::#has_data_trait;
// Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit
// generics (which need to be present with that syntax).
#path::#get_data()
};
- // Ensure that `#data` really is of type `#data` and help with type inference:
- let init = #data.__make_closure::<_, #error>(
+ // Ensure that `data` really is of type `data` and help with type inference:
+ let init = data.__make_closure::<_, #error>(
move |slot| {
#zeroable_check
#this
@@ -380,12 +378,7 @@ fn get_init_kind(rest: Option<(Token![..], Expr)>, dcx: &mut DiagCtxt) -> InitKi
}
/// Generate the code that initializes the fields of the struct using the initializers in `field`.
-fn init_fields(
- fields: &Punctuated<InitializerField, Token![,]>,
- pinned: bool,
- data: &Ident,
- slot: &Ident,
-) -> TokenStream {
+fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -> TokenStream {
let mut guards = vec![];
let mut guard_attrs = vec![];
let mut res = TokenStream::new();
@@ -413,16 +406,16 @@ fn init_fields(
let ident = member.as_ident();
let slot = if pinned {
- quote! {
+ quote_spanned! { Span::mixed_site() =>
// SAFETY:
// - `slot` is valid and properly aligned.
// - `make_field_check` checks that `&raw mut (*slot).#member` is properly aligned.
// - `make_field_check` prevents `#member` from being used twice, therefore
// `(*slot).#member` is exclusively accessed and has not been initialized.
- (unsafe { #data.#ident(#slot) })
+ (unsafe { data.#ident(slot) })
}
} else {
- quote! {
+ quote_spanned! { Span::mixed_site() =>
// For `init!()` macro, everything is unpinned.
// SAFETY:
// - `&raw mut (*slot).#member` is valid.
@@ -431,7 +424,7 @@ fn init_fields(
// `(*slot).#member` is exclusively accessed and has not been initialized.
(unsafe {
::pin_init::__internal::Slot::<::pin_init::__internal::Unpinned, _>::new(
- &raw mut (*#slot).#member
+ &raw mut (*slot).#member
)
})
}
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] rust: pin-init: internal: pin_init: provide span for slot projection
2026-09-16 12:11 [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
2026-09-16 12:11 ` [PATCH 1/3] rust: pin-init: internal: pin_init: emit `slot` using mixed site hygiene Gary Guo
2026-09-16 12:11 ` [PATCH 2/3] rust: pin-init: internal: pin_init: use `slot` identifier directly with mixed site Gary Guo
@ 2026-09-16 12:11 ` Gary Guo
2026-09-16 18:41 ` [PATCH 4/3] rust: pin-init: util: use span of `Index` for generated identifiers Gary Guo
2026-09-18 11:53 ` [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
4 siblings, 0 replies; 6+ messages in thread
From: Gary Guo @ 2026-09-16 12:11 UTC (permalink / raw)
To: Benno Lossin, Gary Guo, Miguel Ojeda, Boqun Feng,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan
Cc: rust-for-linux, linux-kernel
When initializing a field, pin-init first projects the full slot to a slot
of the field, then initialize it by invoking a method. Currently the span
location is not explicitly set, so the error message points to the full
macro invocation.
Improve it by provide a span, so Rust will point to the specific fields
causing the error when type check fails.
Old error message:
error[E0308]: mismatched types
--> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
|
8 | let _ = init!(Foo { a: () });
| ---------------^^---
| | |
| | expected `usize`, found `()`
| arguments to this method are incorrect
New error message:
error[E0308]: mismatched types
--> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
|
8 | let _ = init!(Foo { a: () });
| ---^^
| | |
| | expected `usize`, found `()`
| arguments to this method are incorrect
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/init.rs | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index a77ffef9926b..1d2db93dd33d 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -404,9 +404,10 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
}
};
let ident = member.as_ident();
+ let span = Span::mixed_site().located_at(ident.span());
let slot = if pinned {
- quote_spanned! { Span::mixed_site() =>
+ quote_spanned! { span =>
// SAFETY:
// - `slot` is valid and properly aligned.
// - `make_field_check` checks that `&raw mut (*slot).#member` is properly aligned.
@@ -415,7 +416,7 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
(unsafe { data.#ident(slot) })
}
} else {
- quote_spanned! { Span::mixed_site() =>
+ quote_spanned! { span =>
// For `init!()` macro, everything is unpinned.
// SAFETY:
// - `&raw mut (*slot).#member` is valid.
@@ -432,6 +433,7 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
// `mixed_site` ensures that the guard is not accessible to the user-controlled code.
let guard = format_ident!("__{ident}_guard", span = Span::mixed_site());
+ let full_span = kind.span();
let init = match kind {
InitializerKind::Value { value, .. } => {
@@ -440,14 +442,13 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
.map(|(_, value)| quote!(#value))
.unwrap_or_else(|| quote!(#member));
- quote! {
+ quote_spanned! { full_span =>
#(#attrs)*
let mut #guard = #slot.write(#value);
-
}
}
InitializerKind::Init { value, .. } => {
- quote! {
+ quote_spanned! { full_span =>
#(#attrs)*
let mut #guard = #slot.init(#value)?;
}
@@ -458,7 +459,7 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
// A tuple field has no name that could be bound here (the `_0` identifiers are considered
// implementation detail and not user-facing).
let binding = match member {
- Member::Named(ident) => quote! {
+ Member::Named(ident) => quote_spanned! { span =>
#(#cfgs)*
// Allow `non_snake_case` since the same warning is going to be reported for the
// struct field.
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/3] rust: pin-init: util: use span of `Index` for generated identifiers
2026-09-16 12:11 [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
` (2 preceding siblings ...)
2026-09-16 12:11 ` [PATCH 3/3] rust: pin-init: internal: pin_init: provide span for slot projection Gary Guo
@ 2026-09-16 18:41 ` Gary Guo
2026-09-18 11:53 ` [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
4 siblings, 0 replies; 6+ messages in thread
From: Gary Guo @ 2026-09-16 18:41 UTC (permalink / raw)
To: Benno Lossin, Gary Guo, Miguel Ojeda, Boqun Feng,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan
Cc: rust-for-linux, linux-kernel
Use the span of `Index` for generated identifiers, so diagnostics can point
to the span of the index.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
Follow up to also improve the diagnostics for tuple structs.
---
rust/pin-init/internal/src/util.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/pin-init/internal/src/util.rs b/rust/pin-init/internal/src/util.rs
index ed2c78f0658f..0b5c28b21091 100644
--- a/rust/pin-init/internal/src/util.rs
+++ b/rust/pin-init/internal/src/util.rs
@@ -41,7 +41,7 @@ impl MemberExt for Member {
fn as_ident(&self) -> Ident {
match self {
Member::Named(ident) => ident.clone(),
- Member::Unnamed(Index { index, .. }) => format_ident!("_{index}"),
+ Member::Unnamed(Index { index, span }) => format_ident!("_{index}", span = *span),
}
}
base-commit: 3b3ff9034a497fb3b8429f6fe8ba5697bc7dcebd
prerequisite-patch-id: 84717125cba2ef134e74459d283b3206649b3b03
prerequisite-patch-id: 9f34c2d1fc9699479209cd0c98ec43a70dca8747
prerequisite-patch-id: 830ff446f1ac103336c3b30c9914e9a22c70e577
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 0/3] rust: pin-init: provide better span for diagnostics
2026-09-16 12:11 [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
` (3 preceding siblings ...)
2026-09-16 18:41 ` [PATCH 4/3] rust: pin-init: util: use span of `Index` for generated identifiers Gary Guo
@ 2026-09-18 11:53 ` Gary Guo
4 siblings, 0 replies; 6+ messages in thread
From: Gary Guo @ 2026-09-18 11:53 UTC (permalink / raw)
To: Gary Guo, Benno Lossin, Miguel Ojeda, Boqun Feng,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan
Cc: rust-for-linux, linux-kernel
On Wed Sep 16, 2026 at 1:11 PM BST, Gary Guo wrote:
> When initializing a field, pin-init first projects the full slot to a slot
> of the field, then initialize it by invoking a method. Currently the span
> location is not explicitly set, so the error message points to the full
> macro invocation.
>
> Improve it by provide a span, so Rust will point to the specific fields
> causing the error when type check fails.
>
> Old error message:
>
> error[E0308]: mismatched types
> --> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
> |
> 8 | let _ = init!(Foo { a: () });
> | ---------------^^---
> | | |
> | | expected `usize`, found `()`
> | arguments to this method are incorrect
>
> New error message:
>
> error[E0308]: mismatched types
> --> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
> |
> 8 | let _ = init!(Foo { a: () });
> | ---^^
> | | |
> | | expected `usize`, found `()`
> | arguments to this method are incorrect
>
> ---
> Gary Guo (4):
> rust: pin-init: internal: init: emit `slot` using mixed site hygiene
> rust: pin-init: internal: init: use `slot` identifier directly with mixed site
> rust: pin-init: internal: init: provide span for slot projection
> rust: pin-init: internal: use span of Index for generated identifiers
Applied to pin-init-next.
Best,
Gary
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-18 11:53 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-16 12:11 [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
2026-09-16 12:11 ` [PATCH 1/3] rust: pin-init: internal: pin_init: emit `slot` using mixed site hygiene Gary Guo
2026-09-16 12:11 ` [PATCH 2/3] rust: pin-init: internal: pin_init: use `slot` identifier directly with mixed site Gary Guo
2026-09-16 12:11 ` [PATCH 3/3] rust: pin-init: internal: pin_init: provide span for slot projection Gary Guo
2026-09-16 18:41 ` [PATCH 4/3] rust: pin-init: util: use span of `Index` for generated identifiers Gary Guo
2026-09-18 11:53 ` [PATCH 0/3] rust: pin-init: provide better span for diagnostics Gary Guo
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.