| Age | Commit message (Collapse) | Author |
|
`#[pin_data]` inserts outlive bounds between lifetimes to allow closure
callbacks to rely on their relationship. In some cases, these relations are
implied by fields, and Rust generates `explicit_outlives_requirements`
allow-by-default lint, which is turned out by kernel as part of
rust-2018-idioms lint group.
As `#[pin_data]` is a proc macro and it cannot know if the bounds are
already implied, suppress such lints for generated code.
Link: https://patch.msgid.link/20261011133904.600785-1-gary@kernel.org
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
There are many cases where structs that have interior mutability, but they
do not need the invariance over captured lifetimes as the lifetime is
captured upon construction, and new data of that particular lifetime does
not flow back into the struct.
For these use cases, the same mechanism as pin-init self-reference may be
used. Add support for existential lifetimes, introduced by having where
clauses such as
exists<'a>: 'b
The lifetime `'a` above is minted similar to field lifetimes. Because `'a`
is an erased lifetime living longer than `'b`, the only variance
requirement that we have is that `'b` cannot be contravariant; that defense
is fulfilled by adding `PhantomData<&'b ()>` so the struct is either
covariant or invariant over `'b`.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-20-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
For fields that self-references, it is desirable that projection can
happen on shared references too, so lifetime between different fields can
be correlated. Add support for that with `with_project_ref`.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-19-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Currently lifetimes are replaced via function type and `FnOutput` trait.
This is very general approach as it uses generic associated type to replace
lifetime, so it can even work when macros are involved. This does cause
more generated code, and does not render in documentation nicely.
Thus, just replace the lifetime in the AST if no macros are involved.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-18-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Non-covariant types can already be accessed inside projections. As
projections are only generated for `Pin<&mut T>`, they're not accessible
otherwise. Add `with_{field_name}` methods so fields can be accessed using
closures with just `&T`.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-17-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
type invariance
If invariant field captures a field lifetime, then we also need to make
sure that field is also invariant. Imagine this struct:
#[pin_data]
struct SelfRef<'a> {
#[uses('outer: invariant)]
part: Mutex<&'outer str>,
outer: &'a String,
}
fn new<'a>(str: &'a String) -> impl PinInit<SelfRef<'a>, Infallible> {
pin_init!(SelfRef {
outer: str,
part: Mutex::new(*outer),
})
}
If we make this struct covariant over `'a`, then we can have the following
case:
let mut long = "hello world".to_owned();
let s = Box::pin_init(new(&long)).unwrap();
{
let mut short = "hello world".to_owned();
// If `s` is covariant, this would be okay, because we shorten from
// `SelfRef<'long>` to `SelfRef<'short>`.
s.with_project_ref(|p| {
*p.part.lock().unwrap() = &short;
});
}
Conceptually, a field's type must outlive the field's lifetime, so if we
have a covariant `'a`, we can have a shortened `SelfRef<'short_a>` where
`'outer` outlives `'short_a`. But the wellformedness requirement of the
field will imply `'short_a: 'outer`, which enables the `&'short_a` to
`'outer` coercion, effectively making the field lifetime `'f` behave
covariantly, too, breaking the requirement that it is invariant.
Therefore, compute an invariant closure and use an additional generics on
`Borrowed` to allow capturing things invariantly. Note that we do capture
all parameters explicitly rather than capture the field type invariantly,
because if type aliases are involved, we might be syntactically determining
that the field uses a type parameter but actually not, causing the
invariance enforcement to be missed.
Outlive bounds between field lifetimes can also cause the same issue (an
invariant field lifetime cannot be a lower bound of a covariant field
lifetime). Since we cannot deduce whether any implied bounds from type
wellformness would create such outlive relationships, prevent such bounds
from happening by using a split outlive chain.
Note that this is not a soundness hole in itself in absence of
`with_project_ref`, because with single field accessors only, the field
lifetimes of the fields are not connected; in methods like `with_project`
lifetimes are invariant so shortening cannot happen. However, such method
is likely desirable, so include the variance rule before it has been
heavily relied upon.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-16-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Add support for explicit self-referential annotations.
`#[uses]` attribute is used to mark what other field lifetimes are
captured by this field, and also the variance of the type in respect to the
field lifetimes. For example,
#[uses('a: covariant, 'b: invariant)]
indicates that the field captures the field lifetime `'a` covariantly, and
field lifetime `'b` invariantly. Many types are covariant, so this is the
default variance if the variance is omitted (e.g. `#[uses('a)]`),
consistent with the automatically inferred borrow.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-15-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Allow fields to be mutably referenced by other fields in addition to shared
references. In order for this to be sound, the fields that can be mutably
borrowed are blocked from being accessed via field access syntax or
projection to maintain the aliasing requirements.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-14-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
`#[borrowed]` attribute explicitly marks a field as potentially being
borrowed by other fields.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-13-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
drop order
Add the outlive relations per field drop order. This allows a single
lifetime to be used when a field potentially borrow from two different
fields, by allowing the longer-living field lifetime to be shortened to a
shorter-living field lifetime.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-12-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Enable self-referential support, and add example and test cases.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-11-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
The `project` method needs to perform covariant coercion on covariant
fields, causing them to no longer being mutable. Implement a `with_project`
that does not require covariant coercion by using higher-ranked trait
bounds, thus allow the fields to be assignable inside the callback.
This mechanism can also be used to access non-covariant fields.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-10-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
This adds the projection for fields that are shared borrowed or that
borrows other fields but is covariant. Both cases allow a shared reference
to be accessed.
No mutable references can be created for these cases for different reasons:
* For fields that are shared borrowed, aliasing restriction prevents
creation of mutable reference
* For fields that borrow other fields, their proper type contains field
lifetimes. These lifetimes cannot be made available in the returned
`project` struct (because there is no way to represent existential
lifetime in return position). For covariant types, it is possible to
shorten these lifetimes to that of `&self`; but doing so requires the
reference to also be covariant over the pointee type, so we cannot give
out `&mut` as it is invariant over the pointee.
Due to field-referencing fields being wrapped inside `Erase`, the normal
accessor syntax stop working; create accessor methods for these fields
instead.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-9-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
We now have the checks to ensure that lifetime relations are what is
expected, we can generate the slot projections in `generate_pin_data` so
self-referential struct can be implemented.
New slot and guard types are defined (`SelfRefSlot` and `SelfRefDropGuard`)
which gives the generated let bindings longer lifetime than the guard
themselves.
Have `__make_closure` take `data` back as an argument. This gives
`#[pin_data]` an opportunity to change the type to add lifetimes.
Higher-ranked trait bound on `__make_closure` is used to ensure that the
initialization closure cannot make arbitrary assumptions of those
lifetimes.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-8-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
We implicitly infer covariance for fields that self-references. This needs
to be checked to ensure that the fields are really covariant, so the rest
of expansion code can rely on this fact.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-7-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Check drop order to ensure that usage of lifetime inside self-referential
struct is consistent with the order that the fields will dropped in drop
glue.
First, fields are checked according to their index to ensure that if `a`
borrows from `b`, `b` must outlive `a`. This is simple and produces a very
good diagnostic when misused.
Lifetime bounds can also be indirectly crafted with implied bounds that
make fields well-formed. For example, in this struct
struct Foo {
x: &'b &'a (),
a: String,
y: PrintOnDrop<&'b str>,
b: String,
}
`&'b &'a ()` will imply that `a` outlive `b`, which is inconsistent with
the actual drop order. For this case, create a `__drop_order_check`
function with field lifetimes and outlive relationship of them as generic
parameter, and ask Rust to prove that the types are well-formed inside the
generated function, to ensure that the bad implied bounds cannot happen.
The `__drop_order_check` also need to correlate lifetimes or types captured
by generics and the field lifetimes. Do this by inserting outlive bounds
when a field mentions a specific type or lifetime parameter.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-6-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
cannot dangle
Lifetimes not needed by drop glue are considered by Rust's drop check to be
considered `#[may_dangle]`. In case for a self-referential struct, we may
have fields which need lifetime of borrowed fields in their drop glue, so
compiler's automatic check is insufficient.
Code like this:
#[pin_data]
struct SelfRef<'a> {
borrow: PrintOnDrop<&'owner str>,
owner: &'a str,
}
may access `owner` during the drop, however Rust will determine that since
`'a` only is used in `owner`, the `'a` lifetime may dangle during drop.
This is undesirable for pin-init self references, because `&'a str` could
be coerced to `&'owner str` and this could further coerce if there're
implied outlives, e.g. `&'earlier_field &'owner ()` would allow `&'owner
str` to further coerce to `&'earlier_field`.
Thus, if any self-referential field require field lifetime access in `Drop`
impl, we would need to ensure that the all generic parameters visible by
self-referential fields would strictly outlive the struct. And this can be
done by a simple `Drop` impl that does nothing. Without a dropck eye patch,
presence of `Drop` impl, albeit empty, tells the drop check that the strict
outlive relation is needed.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-5-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
For fields that are borrowed, a mutable reference to the struct no longer
mean that it has the permission to access these fields. Therefore, the
memory that they refer to must be pinned.
Wrap these fields inside a `Borrowed` struct which pins it. They may be
accessed directly (if they're not themselves referencing other struct
fields), so implement a `Deref`.
As such fields are always pinned, there is no need to generate a
conditional `Unpin` implementations that implements `Unpin` when all fields
are. Simply generate a never satisfiable `Unpin` implementation to prevent
user from adding their own.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-4-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Fields that borrow other fields have lifetimes that are within the struct
and these are not part of the struct generics. Therefore, these fields need
to have their lifetime erased.
A naive implementation would be to replace their lifetimes with `'static`.
However, doing so is unsound for multiple reasons:
* Users may directly access such field with field access syntax, and get
exposed with wrong lifetime;
* Auto trait implementations will cause the struct to be implementing auto
traits when the type only implements the auto trait for specific
lifetime. This is similar to how specialization can be unsound if
specialized on lifetime.
Create a `Erase` type, which has `for<'a> fn(&'a ()) -> Foo<'a>` as generic
parameter. Internally, it uses a helper trait to resolve that to
`Foo<'static>`. The first issue is solved by not exposing any public
accessor on that type. The second issue is solved by add custom `Send` and
`Sync` implementations that requires `Send` to be implemented for all
lifetimes, thus closing the lifetime specialization hole. The actual
implementation is a bit more convoluted because it supports erasing
multiple lifetimes.
This is more or less a stable polyfill of the unstable `unsafe_binder`
feature, without `unsafe_binders`'s no drop glue requirement.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-3-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
As a first step towards adding self-referential data structures in
pin-init, add parsing support.
Scan all field types for unbounded lifetimes, and if the names that of
fields, it is inferred as a self-referential field lifetime. No explicit
annotations are supported yet.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-2-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Organize parsing and generation into two separate phases, with a single
`StructInfo` in the middle. This allows analysis and processing to happen
with a single struct and avoid having to pass different information into
the token stream generation functions.
A drawback of this approach is that as we consume the `Fields`, we cannot
expand the original struct using `quote!(#struct_)` anymore, and the field
needs to be re-constructed in `generate_struct_def` function. However, this
is only a temporary drawback, as the upcoming pin-init self-referential
feature will require modification of the generated struct anyway.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261006-dev-selfref-dep-v1-8-da716f740d6d@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
"pin" is a very overloaded word in pin-init. For the generated projection
structs, the lifetime refer to that of the whole struct, so rename the
lifetime used in expansion from `'__pin` to `'__this` instead.
The `__pin_phantom_data` field is renamed to `__this` for the same reason
and for clarity purpose, capture a `PhantomData` of the mutable reference
to the struct.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261006-dev-selfref-dep-v1-7-da716f740d6d@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
function
The `pin_data` function is getting big. Split the `#[cfg]` handling which
does not interact with other part of expansion to its own `expand_with_cfg`
function.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261006-dev-selfref-dep-v1-6-da716f740d6d@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
()` block
Most users would not need to mention the generated projection struct. With
the upcoming self-referential support, there needs to be additional
projection structs. Instead of give them publicly visible names, simply
make the name not publicly accessible.
A heavy user of pin projection outside kernel is for async programming.
I've checked tokio codebase there is a single use case and that's for
enums.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261006-dev-selfref-dep-v1-5-da716f740d6d@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
More attributes are to be added which has the requirement that they should
only be specified once. Add a utility code to extract attributes for a
specific path and report error when appeared multiple times.
Convert `#[pin]` parsing to use the added utility.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261006-dev-selfref-dep-v1-4-da716f740d6d@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
There're many cases where we want to merge multiple generics together.
Currently this is done by cloning generics and modifying it, making the
code less readable.
Add a utility code that allow printing multiple generics together, ensuring
correct ordering between lifetime and other parameters.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261006-dev-selfref-dep-v1-3-da716f740d6d@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Set the span location of the guards to point to the identifier. The
generated diagnostic is still not ideal, as ideally it points the place
where the identifier is used rather than the identifier name in
initializer, but is still an improvement to status quo.
Before the change:
error[E0505]: cannot move out of value because it is borrowed
--> tests/ui/compile-fail/init/accessor_lifetime.rs:8:13
|
8 | let _ = init!(Foo {
| _____________^
9 | | x: 0,
10 | | _: {
11 | | let _: &'static usize = x;
| | -------------- type annotation requires that borrow lasts for `'static`
12 | | },
13 | | });
| | ^
| | |
| |______move out of value occurs here
| borrow of value occurs here
After the change:
error[E0505]: cannot move out of value because it is borrowed
--> tests/ui/compile-fail/init/accessor_lifetime.rs:9:9
|
9 | x: 0,
| ^
| |
| move out of value occurs here
| borrow of value occurs here
10 | _: {
11 | let _: &'static usize = x;
| -------------- type annotation requires that borrow lasts for `'static`
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261006-dev-selfref-dep-v1-2-da716f740d6d@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Currently, the forget order is the same as initialization order, this is
the wrong way around compared to their drop order when going out-of-scope.
The wrong order will cause borrow checker errors if there are lifetime
dependencies between the guards. This does not matter for now because there
cannot be any lifetime dependency; it would matter for self-referential
borrows.
Reverse the order to be consistent with their out-of-scope drop order.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261006-dev-selfref-dep-v1-1-da716f740d6d@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Currently we use the full span of the field initializer as the span of the
generated init call. This produces overlapping spans for type mismatch
errors, which is hard to read.
Use the span of `<-` or `:` for the method name, which wll cause type
mismatch errors or trait bound not implemented error to be appear from the
`<-` or `:` token, which declutter the output a bit and make it easier to
read.
Before the change:
error[E0277]: `impl pin_init::PinInit<Bar>` cannot be used to movably initialize `Bar` with error `_`
--> tests/ui/compile-fail/init/invalid_init.rs:19:16
|
19 | bar <- Bar::new(),
| -------^^^^^^^^^^
| | |
| | the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
| required by a bound introduced by this call
|
= note: if your type implements `PinInit` but not `Init`, you might be forgetting a `#[pin]` annotation on fields
After the change:
error[E0277]: `impl pin_init::PinInit<Bar>` cannot be used to movably initialize `Bar` with error `_`
--> tests/ui/compile-fail/init/invalid_init.rs:19:16
|
19 | bar <- Bar::new(),
| -- ^^^^^^^^^^ the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
| |
| required by a bound introduced by this call
|
= note: if your type implements `PinInit` but not `Init`, you might be forgetting a `#[pin]` annotation on fields
Suggested-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20260928-dev-pin-init-sync-v1-3-e591c8e9cf0e@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
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`
Link: https://patch.msgid.link/20260928-dev-pin-init-sync-v1-2-e591c8e9cf0e@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Use `let mut` for created bindings of initialized field, so `Pin<&mut T>`
bindings may be reborrowed in subsequent initializers or code blocks.
Without `let mut`, attempt to reborrow can produce error (and also a
confusing fix):
error[E0596]: cannot borrow `gpu` as mutable, as it is not declared as mutable
--> drivers/gpu/nova-core/driver.rs:129:17
|
129 | gpu.as_mut().run_selftests(pdev);
| ^^^ cannot borrow as mutable
|
help: consider changing this to be mutable |
119 | mut gpu <- Gpu::new(
| +++
error: aborting due to 1 previous error
Reported-by: Danilo Krummrich <dakr@kernel.org>
Closes: https://lore.kernel.org/nova-gpu/DLQXWXRP3P1J.28SLFOJJQ2EDK@kernel.org/
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Tested-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Link: https://patch.msgid.link/20260928-dev-pin-init-sync-v1-1-e591c8e9cf0e@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Currently, if proc macro panicked, the diagnostics clean up is not
executed, and further invocation will cause the "DiagCtxt cannot be nested"
error. While we should aim to have no panics inside proc macros, producing
a sensible diagnostics message even when macro panicked is very useful for
developing.
Thus, catch proc macro panics and convert them to errors, and emit them
together with all diagnostics accumulated so far.
Ideally we would like panic location w/ line numbers being available as
well; however this is not currently implementable without overriding the
global panic hook.
Reviewed-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20260923140618.1978181-3-gary@kernel.org
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Currently, there is a split between `syn::Error` and pin-init's custom
`DiagCtxt`. Parsing has no access to `DiagCtxt` and therefore cannot report
diagnostics without failing the parse. Bridge the gap by making the
`DiagCtxt` available inside parsers using `thread_local!`.
`parse_macro_input!` returns error as token stream directly, so it is no
longer suitable when the parsing is moved inside `DiagCtxt` closure. Add a
`From<syn::Error> for ErrorGuaranteed` implementation so `?` can be used to
add a `syn::Error` into the current diagnostic context and obtain a
`ErrorGuaranteed`.
Clean up the handler of using `<-` inside tuple expression as a
demonstration of the usefulness of having `DiagCtxt` access inside `Parse`.
Reviewed-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20260923140618.1978181-2-gary@kernel.org
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Currently `DiagCtxt` is used to allow error recovery in the pin-init
macros, by generating both a `compile_error!()` macro item and continue
expansion, and then merge token streams together. This works very well for
items, however for expressions, this will produce invalid expression and
result in a confusing error message.
error: macro expansion ignores `::` and any tokens following
--> tests/ui/compile-fail/zeroable/invalid_spread.rs:15:9
|
13 | let _ = init!(Foo {
| _____________-
14 | | a: 0,
15 | | ..MyZeroable::init_zeroed()
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
16 | | });
| |______- caused by the macro expansion here
|
= note: the usage of `init!` is likely invalid in expression context
Fix this by wrap the concatenated diagnostics in a block, with the
generated expression in its tail position. This results in the desired
error message.
error: expected nothing or `..Zeroable::init_zeroed()`.
--> tests/ui/compile-fail/zeroable/invalid_spread.rs:15:9
|
15 | ..MyZeroable::init_zeroed()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Reviewed-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20260923140618.1978181-1-gary@kernel.org
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Give a slightly more useful error message when these traits are not
implemented.
Before this change:
error[E0277]: the trait bound `impl pin_init::PinInit<Bar>: Init<Bar, _>` is not satisfied
--> tests/ui/compile-fail/init/invalid_init.rs:19:16
|
19 | bar <- Bar::new(),
| -------^^^^^^^^^^
| | |
| | the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
| required by a bound introduced by this call
After this change:
error[E0277]: `impl pin_init::PinInit<Bar>` cannot be used to movably initialize `Bar` with error `_`
--> tests/ui/compile-fail/init/invalid_init.rs:19:16
|
19 | bar <- Bar::new(),
| -------^^^^^^^^^^
| | |
| | the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
| required by a bound introduced by this call
|
= note: if your type implements `PinInit` but not `Init`, you might be forgetting a `#[pin]` annotation on fields
Ideally, we would generate differnet message when `PinInit` is implemented
but not `Init`; that is not feasible with today's
`diagnostics::on_unimplemented` attribute. However, the added note is worth
it because in `init!()` is more rarely used compared to `pin_init!()`; in
most cases `Init` being unimplemented is the result of missing `#[pin]`.
Link: https://patch.msgid.link/20260923-dev-pin-data-diag-v1-5-e4d7193569e5@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
implemented
Produce a more helpful error message when `#[pin_data]` is omitted. The
error message changes from
error[E0277]: the trait bound `Foo: pin_init::__internal::HasPinData` is not satisfied
--> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
|
9 | pin_init!(Self { a: 42 })
| ^^^^ unsatisfied trait bound
|
help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
--> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
|
3 | struct Foo {
| ^^^^^^^^^^
to
error[E0277]: `Foo` cannot be used with `pin_init!` macro
--> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
|
9 | pin_init!(Self { a: 42 })
| ^^^^ unsatisfied trait bound
|
help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
--> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
|
3 | struct Foo {
| ^^^^^^^^^^
= note: did you forget to add `#[pin_data]` attribute to the struct?
Link: https://patch.msgid.link/20260923-dev-pin-data-diag-v1-4-e4d7193569e5@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Currently, type inference of the initialized type is done by use the
function calling syntax `PATH::__pin_data` or `PATH::__init_data` to obtain
the required init data type, without needing the user to explicitly mention
all generics. Switch to always use `HasInitData::__init_data` to provide
that inference, which will not produce method-not-found errors as it is
always available.
Change `__pin_data` to take `InitData<Self>` as the receiver, so for types
that require `HasPinData`, `HasPinData::__pin_data(data)` can be used to
obtain the needed type without having to mention the user-provided path
again. The expanded code also uses the span of the type, so diagnostics
will hint to user that the type is causing the issue.
With this change, the error message when `HasPinData` is not implemented
changes from
error[E0599]: no associated function or constant named `__pin_data` found for struct `Foo` in the current scope
--> tests/ui/compile-fail/init/missing_pin_data.rs:9:9
|
3 | struct Foo {
| ---------- associated function or constant `__pin_data` not found for this struct
...
9 | pin_init!(Self { a: 42 })
| ^^^^^^^^^^^^^^^^^^^^^^^^^ associated function or constant not found in `Foo`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `__pin_data`, perhaps you need to implement it:
candidate #1: `pin_init::__internal::HasPinData`
to
error[E0277]: the trait bound `Foo: pin_init::__internal::HasPinData` is not satisfied
--> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
|
9 | pin_init!(Self { a: 42 })
| ^^^^ unsatisfied trait bound
|
help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
--> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
|
3 | struct Foo {
| ^^^^^^^^^^
Link: https://patch.msgid.link/20260923-dev-pin-data-diag-v1-3-e4d7193569e5@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
There is only a single implementation, the associated type is not
necessary. Remove it, and rename `AllData` to `InitData` to be a more
meaningful name.
The single implementation also means that "unsafe" is redundant, so remove
it as well.
Link: https://patch.msgid.link/20260923-dev-pin-data-diag-v1-2-e4d7193569e5@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Remove the unsafe markers of `__init_data` and `__pin_data`. These methods
are for inference help and does not need to be unsafe.
The `HasInitData` cannot be implemented outside pin-init, so the `unsafe
trait` marker is not necessary.
Link: https://patch.msgid.link/20260923-dev-pin-data-diag-v1-1-e4d7193569e5@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
for `Unpin`
`#[pin_data]` generates a `Unpin` implementation for the user, which
requires reasoning using field types. This is rejected by rustc as "trivial
bounds", which can only be specified using the
`#![feature(trivial_bounds)]`.
Currently we use an extra lifetime in `__Unpin` to work around this; use
HRTB to introduce a dummy lifetime can achieve the same, which the
`Zeroable` implementation already uses.
Unify the `Unpin` impl to also use the same HRTB trick that `Zeroable`
uses. This produces slightly better error message and slightly shorter
expansion.
Link: https://patch.msgid.link/20260922211320.1390159-1-gary@kernel.org
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Use the span of `Index` for generated identifiers, so diagnostics can point
to the span of the index.
Link: https://patch.msgid.link/20260916184131.435059-1-gary@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
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
Link: https://patch.msgid.link/20260916-dev-hygiene-v1-3-dfb6ae2588ba@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
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.
Link: https://patch.msgid.link/20260916-dev-hygiene-v1-2-dfb6ae2588ba@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
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`")
Link: https://patch.msgid.link/20260916-dev-hygiene-v1-1-dfb6ae2588ba@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
A tuple struct whose fields are all set to a value reads better written
like a call to its constructor than with the indices spelled out:
pin_init!(Foo(value, value))
Parse the two forms into separate types and rewrite the constructor
arguments into the indexed fields they are shorthand for, so that only the
parser has to know about the second form.
The arguments have no names, so they cannot use `<-`. Parse it anyway and
reject it afterwards, which reports the position of every offending `<-`
rather than stopping at the first one.
`cfg` needs different treatment for tuple constructor syntax. As non-derive
proc macros are invoked before cfg is resolved, the macro cannot know
whether a field survives, and dropping a tuple field renumbers every field
after it. That cannot be expressed by attaching a `cfg` attribute to the
initializer of a single field. Thus, resolve tuple field cfgs up front
instead, by generating two cfg-gated invocations of the macro with one
field resolved in each. This is the approach of commit 5bbf2b2deb94 ("rust:
pin-init: internal: rework how `#[pin_data]` handles cfg"), and it is
linear time because only one of the two branches is ever expanded. Struct
expression syntax do not renumber, so using tuple structs with struct
syntax can keep using the existing attribute-based handling.
Suggested-by: Gary Guo <gary@garyguo.net>
Link: https://github.com/Rust-for-Linux/pin-init/pull/165
Signed-off-by: Mohamad Alsadhan <mo@sdhn.cc>
[ Pre-expand cfgs for tuple init syntax. Use generics instead of separate
types for normalization - Gary ]
Co-developed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260904-tuple-struct-v1-4-72c50bd037fd@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Extend the initializer syntax so that a field can be named by an index,
addressing tuple struct fields the same way a struct expression does:
pin_init!(Foo { 0: value, 1 <- initializer })
Tuple fields are not exposed by a `let` binding to the fields after them,
since they have no name to bind; `_0` would shadow a user variable.
Signed-off-by: Mohamad Alsadhan <mo@sdhn.cc>
[ Fixed incorrect index calculation and cleaned up the code - Gary ]
Link: https://patch.msgid.link/20260904-tuple-struct-v1-3-72c50bd037fd@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
`#[pin_data]` rejects tuple structs because it assumes every field has a
name, which it uses for the projection field, the `__Unpin` field and the
pin-data accessor.
Identify fields by `syn::Member` instead, so that tuple fields are referred
to by their index in generated field accesses. The names that generated
items still need are derived from the index as `_0`, `_1`, etc.
The projection of a tuple struct is a tuple struct itself, so projected
fields are accessed with the same `.0`, `.1` syntax as on the input
type rather than through synthesised names.
Signed-off-by: Mohamad Alsadhan <mo@sdhn.cc>
[ Moved utility code to util.rs as extension trait - Gary ]
Link: https://patch.msgid.link/20260904-tuple-struct-v1-2-72c50bd037fd@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
Create a new `util.rs` to host utility code that are generic and can be
shared by multiple macros.
Link: https://patch.msgid.link/20260904-tuple-struct-v1-1-72c50bd037fd@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
|
|
In Rust 1.100.0, `Infallible` will become an alias of `!`. The let
binding in `stack_pin_init` will thus become unreachable and produce
an "unreachable expression" warning for the subsequent match, and thus
will fail a `-Dwarnings` build. For this macro, all we need to know is
that the error type is uninhabited, so replace this with an irrefutable
pattern instead.
[ The error looks like (dummy reproducer):
error: unreachable expression
--> rust/kernel/sync.rs:177:5
|
177 | pin_init::stack_pin_init!(let num = 42u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| unreachable expression
| any code following this expression is unreachable
|
= note: `-D unreachable-code` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(unreachable_code)]`
= note: this error originates in the macro `pin_init::stack_pin_init` (in Nightly builds, run with -Z macro-backtrace for more info)
- Miguel ]
Reported-by: Mohamad Alsadhan <mo@sdhn.cc>
Closes: https://github.com/Rust-for-Linux/pin-init/pull/171
Signed-off-by: Gary Guo <gary@garyguo.net>
Cc: stable@vger.kernel.org # Needed in 7.1.y and later (for 6.12.y and 6.18.y a custom one is needed).
Link: https://patch.msgid.link/20260828155033.2101924-1-gary@kernel.org
[ Reworded for typos. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
|
|
Currently `pin-init` crate is missing many inline annotations. They are all
generic so still get inlined in normal builds, but are not inlined in
`-C opt-level=s` build. Mark these functions as `#[inline]` so they are
considered for inlining regardless.
Signed-off-by: Gary Guo <gary@garyguo.net>
|