In the `init!`/`pin_init!` macros, we rely on a trick that assigns never
(`!`) values to all mentioned fields in never-executed code to let the
compiler check that all fields have been initialized.
Currently we use `::core::panic!()` to produce this value, but before Rust
1.91.0, it creates outlined `panic_cold_explicit` functions which do not
get removed by the optimizer, thus leaving dead code behind in the binary.
This has been fixed by [1], which lands in Rust 1.91.0+, higher than the
kernel minimum version 1.85.0.
This causes ~200 dead `panic_cold_explicit` instances being included in the
binary, with ~90 of them from nova-core's usage of pin-init.
Work around the issue by using `loop {}` which creates the never value
without macro expansion or function call at all. All instances of
`panic_cold_explicit` outside libcore are removed by this change in my
kernel build.
Link: https://github.com/rust-lang/rust/pull/145304 [1]
Link: https://patch.msgid.link/20260508152950.833635-1-gary@kernel.org
Signed-off-by: Gary Guo <gary@garyguo.net>
Move `E` from type to trait impl block. This greatly shortens the
monomorphized type names. The `__pinned_init` function name is only
slightly shortened as it still encodes the `E` as part of `PinInit<T, E>`
in the symbol.
`T` cannot be moved to trait impl block otherwise it will start to conflict
with the `impl Init<T> for T` as Rust cannot deduce that there're no types
that fulfill `T: FnOnce(*mut T)`.
Link: https://patch.msgid.link/20260527-pin-init-sync-v1-6-e20335ed2501@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
The `__internal` module is for exposing internal items publicly to
procedural macros (pin-init-internal). Types that are crate-local only can
just have proper visibility and does not need to be in `__internal`.
The type name of `InitClosure` can often shows up in symbol names, this
reduces the length slightly.
Link: https://patch.msgid.link/20260527-pin-init-sync-v1-5-e20335ed2501@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
When using a macro with custom attributes in a `#[pin_data]` struct it
can mess up the generated code. The generated code needs nothing more than
the `#[cfg]` attribute, thus strip away all other attributes.
[ Rebased and updated to only include `#[cfg]` instead of both `#[cfg]` and
`#[doc]`; doc is not needed for the generated hidden items. - Gary ]
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260527-pin-init-sync-v1-1-e20335ed2501@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
Instead of projecting using pointer to a field project the full slot. This
further shifts the code generation from the initializer site to the struct
definition site, which means less code is generated overall.
It also makes the safety comment easier to justify, as now the projection
is done by the `#[pin_data]` macro which has full visibility of pinnedness
of fields.
The field alignment could also be checked on the `#[pin_data]` side;
however, since `init!()` macro works for other type of structs, we cannot
remove the alignment check from `init!`/`pin_init!` side anyway, so I opted
to still keep the alignment check in init.rs.
Signed-off-by: Gary Guo <gary@garyguo.net>
By projecting slots, the `pin_init!` and `init!` code path can be more
unified. This also reduces the amount of macro-generated code and shifts
them to the shared infrastructure.
Signed-off-by: Gary Guo <gary@garyguo.net>
The `InitData` and `PinData` traits do not need to exist, the inference
helpers could be inherent methods instead.
There is no risk for calling the wrong methods even when user defines it,
as inherent methods take priority over trait methods.
With this change, it unlocks the possibility of attaching additional bounds
to the method per type, which is not possible for trait methods.
Signed-off-by: Gary Guo <gary@garyguo.net>
Instead of projecting the created reference, simply create drop guards with
different marker types and have the `let_binding()` method of guards of
different marker produce different type instead.
This allows more flexible lifetime as this is now controlled by the guard.
This will be needed when implementing self-referential fields.
Signed-off-by: Gary Guo <gary@garyguo.net>
`InitializerKind::Code` is a special case where it does not initialize a
field, and thus generate no guard and accessors. Handle it earlier and make
the rest of the code more linear.
Signed-off-by: Gary Guo <gary@garyguo.net>
Currently, the `pin_init` library has an `Invariant` type alias, and it is
instantiated using `PhantomData`. Generated code from `pin_data` on the
other hand cannot access the crate-local type alias, so it generates
`PhantomData<fn(T) -> T>` directly. This is all very inconsistent, despite
the exact same use case of ensuring invariance.
Add `PhantomInvariant` and `PhantomInvariantLifetime` and switch all users
that need to express the concept of invariance to use these. They're
polyfills of unstable types in the same names in the Rust standard library.
Link: https://patch.msgid.link/20260512-pin-init-sync-v1-3-81963130dfbd@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
`handle_field` is currently a function, which precludes it from referencing
things in the scope of the parent function. Given that it's only called
once, inline its contents to the closure that invokes it instead, so it can
directly reference `struct_name` without having to pass in as argument.
Link: https://patch.msgid.link/20260512-pin-init-sync-v1-1-81963130dfbd@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
Tuples implement `FromIterator` since Rust 1.79. Remove the `collect_tuple`
polyfill now the MSRV is above 1.79.
To avoid over-identing the closure, I move the `Field` destructure from the
closure parameter to a let binding. This keeps the diff small.
Link: https://patch.msgid.link/20260501134445.3809731-1-gary@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
The `PhantomPinned` detection is just a lint, and is emitted as an error
because there is no `compile_warning!()` macro, and
`proc-macro-diagnostics` is not stable.
Use of `#[deprecated = ""]` attribute to approximate custom proc-macro
warnings. A new line is added before message for visual clarity.
An example warning with this trick looks like this:
warning: use of deprecated function `_::warn`:
The field `pin` of type `PhantomPinned` only has an effect if it has the `#[pin]` attribute
--> test.rs:9:5
|
9 | pin: marker::PhantomPinned,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Suggested-by: Benno Lossin <lossin@kernel.org>
Link: https://github.com/Rust-for-Linux/pin-init/issues/51
Link: https://patch.msgid.link/20260428-pin-init-sync-v1-10-07f9bd3859fb@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
The pin-init crate has been licensed under `Apache-2.0 OR MIT` since the
beginning. I introduced in commit 071cedc84e ("rust: add derive macro for
`Zeroable`") `zeroable.rs` with incompatible GPL-2.0 SPDX identifier. The
file has not been modified by other authors, so relicense it under the
above license.
Signed-off-by: Benno Lossin <lossin@kernel.org>
[ Reworded commit message - Gary ]
Link: https://patch.msgid.link/20260428-pin-init-sync-v1-7-07f9bd3859fb@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
Improve impl_zeroable_option macro to handle generic impls for types
like `&T`, `&mut T`, `NonNull<T>`, and others (for which `Option<T>`
is guaranteed to be zeroable) with similar approach to
`impl_zeroable`.
Also, update old declarations to use generics e.g. `NonZeroU8` to
`NonZero<u8>`.
Signed-off-by: Mohamad Alsadhan <mo@sdhn.cc>
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260428-pin-init-sync-v1-4-07f9bd3859fb@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
Place definitions and implementations (incl. macro invocations) of
the `Zeroable` trait first in the relevant section of `src/lib.rs`,
followed by the ZeroableOption trait and its implementations.
Rename `impl_non_zero_int_zeroable_option` to `impl_zeroable_option`
for consistency.
This commit should not introduce any functional changes.
Signed-off-by: Mohamad Alsadhan <mo@sdhn.cc>
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260428-pin-init-sync-v1-3-07f9bd3859fb@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
Following the kernel minimum version bump in commit f32fb9c58a ("rust:
bump Rust minimum supported version to 1.85.0 (Debian Trixie)"), bump
pin-init's minimum Rust version to 1.82.
This removes the `lint_reasons` feature which is stabilized in 1.81 and the
`raw_ref_ops` and `new_uninit` features which are stabilized in 1.82.
Given we do not use any features that are stabilized in 1.82..=1.85 range,
and pin-init crate is useful for other projects which may have their own
MSRV requirements, the minimum version is not straightly bumped to 1.85.
Reviewed-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20260428-pin-init-sync-v1-2-07f9bd3859fb@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
When a field has been initialized, `init!`/`pin_init!` create a reference
or pinned reference to the field so it can be accessed later during the
initialization of other fields. However, the reference it created is
incorrectly `&'static` rather than just the scope of the initializer.
This means that you can do
init!(Foo {
a: 1,
_: {
let b: &'static u32 = a;
}
})
which is unsound.
This is caused by `&mut (*#slot).#ident`, which actually allows arbitrary
lifetime, so this is effectively `'static`. Somewhat ironically, the safety
justification of creating the accessor is.. "SAFETY: TODO".
Fix it by adding `let_binding` method on `DropGuard` to shorten lifetime.
This results in exactly what we want for these accessors. The safety and
invariant comments of `DropGuard` have been reworked; instead of reasoning
about what caller can do with the guard, express it in a way that the
ownership is transferred to the guard and `forget` takes it back, so the
unsafe operations within the `DropGuard` can be more easily justified.
Fixes: 42415d163e ("rust: pin-init: add references to previously initialized fields")
Cc: stable@vger.kernel.org
Signed-off-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260427-pin-init-fix-v3-2-496a699674dd@garyguo.net
[ Reworded for missing word. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Currently the doc for `Zeroable` and `ZeroableOption` are filled with the
generated impl of tuples and fn pointers. Use the internal
"fake_variadics" feature to improve the rendered quality.
This makes use of an internal feature, however this is of minimal risk as
it's for documentation only, not activated during normal build, gated
behind `USE_RUSTC_FEATURES`, and can be removed at any time. This feature
is already used by serde and bevy to improve documentation quality.
For compilers that cannot use this feature, we still hide most generated
impls, and the existence of them are hinted by doc comments on the single
non-hidden impl.
Signed-off-by: Gary Guo <gary@garyguo.net>
Link: 530c4eb79a
[ Reordered `#[doc]` attributes and safety comments to avoid errors in
older versions of clippy. - Benno ]
Link: https://patch.msgid.link/20260319093542.3756606-4-lossin@kernel.org
Signed-off-by: Benno Lossin <lossin@kernel.org>
The three let bindings (in the bodies of `cast_init`, `cast_pin_init`
and the `init!` macro) are used to avoid the following compiler error in
Rust 1.78.0, 1.79.0, 1.80.0, 1.80.1, and 1.81.0 (just showing the one
for `cast_init`, the others are similar):
error[E0391]: cycle detected when computing type of opaque `cast_init::{opaque#0}`
--> src/lib.rs:1160:66
|
1160 | pub const unsafe fn cast_init<T, U, E>(init: impl Init<T, E>) -> impl Init<U, E> {
| ^^^^^^^^^^^^^^^
|
note: ...which requires borrow-checking `cast_init`...
--> src/lib.rs:1160:1
|
1160 | pub const unsafe fn cast_init<T, U, E>(init: impl Init<T, E>) -> impl Init<U, E> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const checking `cast_init`...
--> src/lib.rs:1160:1
|
1160 | pub const unsafe fn cast_init<T, U, E>(init: impl Init<T, E>) -> impl Init<U, E> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing whether `cast_init::{opaque#0}` is freeze...
= note: ...which requires evaluating trait selection obligation `cast_init::{opaque#0}: core::marker::Freeze`...
= note: ...which again requires computing type of opaque `cast_init::{opaque#0}`, completing the cycle
note: cycle used when computing type of `cast_init::{opaque#0}`
--> src/lib.rs:1160:66
|
1160 | pub const unsafe fn cast_init<T, U, E>(init: impl Init<T, E>) -> impl Init<U, E> {
| ^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
Once we raise the nightly-MSRV above 1.81, we can remove this
workaround.
Link: bb3e96f3e9
[ Moved this commit after the previous one to avoid a build failure due
to unstable features. Changed the cfg to use `USE_RUSTC_FEAUTURES`.
- Benno ]
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260319093542.3756606-3-lossin@kernel.org
Signed-off-by: Benno Lossin <lossin@kernel.org>
We use some features that are already stable in later versions of Rust,
but only available as unstable features in older Rust versions that the
kernel needs to support.
Instead of checking if a feature is already stable, simply enable them
and allow the warning if the feature is already stable. This avoids the
need of hardcoding whether a feature has been stabilized at a given
version.
`#[feature(...)]` is used when cfg `USE_RUSTC_FEATURES` is enabled. The
build script automatically does this when a nightly compiler is detected
or `RUSTC_BOOTSTRAP` is set.
Signed-off-by: Gary Guo <gary@garyguo.net>
Link: 885c5d83d7
[ Added kernel build system changes to always enable USE_RUSTC_FEATURES.
Moved this commit earlier (swapped with the next one) to avoid a build
error. - Benno ]
Link: https://patch.msgid.link/20260319093542.3756606-2-lossin@kernel.org
Signed-off-by: Benno Lossin <lossin@kernel.org>
We use a unit struct `__InitOk` in the closure generated by the
initializer macros as the return value. We shadow it by creating a
struct with the same name again inside of the closure, preventing early
returns of `Ok` in the initializer (before all fields have been
initialized).
In the face of Type Alias Impl Trait (TAIT) and the next trait solver,
this solution no longer works [1]. The shadowed struct can be named
through type inference. In addition, there is an RFC proposing to add
the feature of path inference to Rust, which would similarly allow [2].
Thus remove the shadowed token and replace it with an `unsafe` to create
token.
The reason we initially used the shadowing solution was because an
alternative solution used a builder pattern. Gary writes [3]:
In the early builder-pattern based InitOk, having a single InitOk
type for token is unsound because one can launder an InitOk token
used for one place to another initializer. I used a branded lifetime
solution, and then you figured out that using a shadowed type would
work better because nobody could construct it at all.
The laundering issue does not apply to the approach we ended up with
today.
With this change, the example by Tim Chirananthavat in [1] no longer
compiles and results in this error:
error: cannot construct `pin_init::__internal::InitOk` with struct literal syntax due to private fields
--> src/main.rs:26:17
|
26 | InferredType {}
| ^^^^^^^^^^^^
|
= note: private field `0` that was not provided
help: you might have meant to use the `new` associated function
|
26 - InferredType {}
26 + InferredType::new()
|
Applying the suggestion of using the `::new()` function, results in
another expected error:
error[E0133]: call to unsafe function `pin_init::__internal::InitOk::new` is unsafe and requires unsafe block
--> src/main.rs:26:17
|
26 | InferredType::new()
| ^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
Reported-by: Tim Chirananthavat <theemathas@gmail.com>
Link: https://github.com/rust-lang/rust/issues/153535 [1]
Link: https://github.com/rust-lang/rfcs/pull/3444#issuecomment-4016145373 [2]
Link: https://github.com/rust-lang/rust/issues/153535#issuecomment-4017620804 [3]
Fixes: fc6c6baa1f ("rust: init: add initialization macros")
Cc: stable@vger.kernel.org
Signed-off-by: Benno Lossin <lossin@kernel.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260311105056.1425041-1-lossin@kernel.org
[ Added period as mentioned. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Gary noticed [1] that the initializer macros as well as the `[Pin]Init`
traits cannot support unaligned fields, since they use operations that
require aligned pointers. This means that any code using structs with
unaligned fields in pin-init is unsound.
By default, the `init!` macro generates references to initialized fields,
which makes the compiler check that those fields are aligned. However,
we added the `#[disable_initialized_field_access]` attribute to avoid
this behavior in commit ceca298c53 ("rust: pin-init: internal: init:
add escape hatch for referencing initialized fields"). Thus remove the
`#[disable_initialized_field_access]` attribute from `init!`, which is
the only safe way to create an initializer handling unaligned fields.
If support for in-place initializing structs with unaligned fields is
required in the future, we could figure out a solution. This is tracked
in [2].
Reported-by: Gary Guo <gary@garyguo.net>
Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/561532-pin-init/topic/initialized.20field.20accessor.20detection/with/576210658 [1]
Link: https://github.com/Rust-for-Linux/pin-init/issues/112 [2]
Fixes: ceca298c53 ("rust: pin-init: internal: init: add escape hatch for referencing initialized fields")
Signed-off-by: Benno Lossin <lossin@kernel.org>
Acked-by: Janne Grunau <j@jannau.net>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://patch.msgid.link/20260302140424.4097655-1-lossin@kernel.org
[ Adjusted tags and reworded as discussed. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Pull rust fixes from Miguel Ojeda:
"Toolchain and infrastructure:
- Pass '-Zunstable-options' flag required by the future Rust 1.95.0
- Fix 'objtool' warning for Rust 1.84.0
'kernel' crate:
- 'irq' module: add missing bound detected by the future Rust 1.95.0
- 'list' module: add missing 'unsafe' blocks and placeholder safety
comments to macros (an issue for future callers within the crate)
'pin-init' crate:
- Clean Clippy warning that changed behavior in the future Rust
1.95.0"
* tag 'rust-fixes-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux:
rust: list: Add unsafe blocks for container_of and safety comments
rust: pin-init: replace clippy `expect` with `allow`
rust: irq: add `'static` bounds to irq callbacks
objtool/rust: add one more `noreturn` Rust function
rust: kbuild: pass `-Zunstable-options` for Rust 1.95.0
`clippy` has changed behavior in [1] (Rust 1.95) where it no longer
warns about the `let_and_return` lint when a comment is placed between
the let binding and the return expression. Nightly thus fails to build,
because the expectation is no longer fulfilled.
Thus replace the expectation with an `allow`.
[ The errors were:
error: this lint expectation is unfulfilled
--> rust/pin-init/src/lib.rs:1279:10
|
1279 | #[expect(clippy::let_and_return)]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D unfulfilled-lint-expectations` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]`
error: this lint expectation is unfulfilled
--> rust/pin-init/src/lib.rs:1295:10
|
1295 | #[expect(clippy::let_and_return)]
| ^^^^^^^^^^^^^^^^^^^^^^
- Miguel ]
Link: https://github.com/rust-lang/rust-clippy/pull/16461 [1]
Signed-off-by: Benno Lossin <lossin@kernel.org>
Cc: stable@vger.kernel.org # Needed in 6.18.y and later.
Link: https://patch.msgid.link/20260215132232.1549861-1-lossin@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This feature allows users to use `&'static mut MaybeUninit<T>` as a
place to initialize the value. It mirrors an existing implemetation
for `Box<MaybeUninit>`, but enables users to use external allocation
mechanisms such as `static_cell` [1].
Signed-off-by: Oleksandr Babak <alexanderbabak@proton.me>
Link: https://crates.io/crates/static_cell [1]
[ Added link to `static_cell` - Benno ]
Signed-off-by: Benno Lossin <lossin@kernel.org>
The `Zeroable` type check uses a small dance with a raw pointer to aid
type inference. It turns out that this is not necessary and type
inference is powerful enough to resolve any ambiguity. Thus remove it.
Suggested-by: Gary Guo <gary@garyguo.net>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
The initializer macro emits mutable references for already initialized
fields, which allows modifying or accessing them later in code blocks or
when initializing other fields. This behavior results in compiler errors
when combining with packed structs, since those do not permit creating
references to misaligned fields. For example:
#[repr(C, packed)]
struct Foo {
a: i8,
b: i32,
}
fn main() {
let _ = init!(Foo { a: -42, b: 42 });
}
This will lead to an error like this:
error[E0793]: reference to field of packed struct is unaligned
--> tests/ui/compile-fail/init/packed_struct.rs:10:13
|
10 | let _ = init!(Foo { a: -42, b: 42 });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this struct is 1-byte aligned, but the type of this field may require higher alignment
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
= note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info)
This was requested by Janne Grunau [1] and will most certainly be used
by the kernel when we eventually end up with trying to initialize packed
structs.
Thus add an initializer attribute `#[disable_initialized_field_access]`
that does what the name suggests: do not generate references to already
initialized fields.
There is space for future work: add yet another attribute which can be
applied on fields of initializers that ask for said field to be made
accessible. We can add that when the need arises.
Requested-by: Janne Grunau <j@jannau.net>
Link: https://lore.kernel.org/all/20251206170214.GE1097212@robin.jannau.net [1]
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
Initializer fields ought to support the same attributes that are allowed
in struct initializers on fields. For example, `cfg` or lint levels such
as `expect`, `allow` etc. Add parsing support for these attributes using
syn to initializer fields and adjust the macro expansion accordingly.
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
The `#[default_error(<type>)]` attribute can be used to supply a default
type as the error used for the `[pin_]init!` macros. This way one can
easily define custom `try_[pin_]init!` variants that default to your
project specific error type. Just write the following declarative macro:
macro_rules! try_init {
($($args:tt)*) => {
::pin_init::init!(
#[default_error(YourCustomErrorType)]
$($args)*
)
}
}
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
Rewrite the initializer macros `[pin_]init!` using `syn`. No functional
changes intended aside from improved error messages on syntactic and
semantical errors. For example if one forgets to use `<-` with an
initializer (and instead uses `:`):
impl Bar {
fn new() -> impl PinInit<Self> { ... }
}
impl Foo {
fn new() -> impl PinInit<Self> {
pin_init!(Self { bar: Bar::new() })
}
}
Then the declarative macro would report:
error[E0308]: mismatched types
--> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:9
|
14 | fn new() -> impl PinInit<Self> {
| ------------------ the found opaque type
...
21 | pin_init!(Self { bar: Bar::new() })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected `Bar`, found opaque type
| arguments to this function are incorrect
|
= note: expected struct `Bar`
found opaque type `impl pin_init::PinInit<Bar>`
note: function defined here
--> $RUST/core/src/ptr/mod.rs
|
| pub const unsafe fn write<T>(dst: *mut T, src: T) {
| ^^^^^
= note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info)
And the new error is:
error[E0308]: mismatched types
--> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:31
|
14 | fn new() -> impl PinInit<Self> {
| ------------------ the found opaque type
...
21 | pin_init!(Self { bar: Bar::new() })
| --- ^^^^^^^^^^ expected `Bar`, found opaque type
| |
| arguments to this function are incorrect
|
= note: expected struct `Bar`
found opaque type `impl pin_init::PinInit<Bar>`
note: function defined here
--> $RUST/core/src/ptr/mod.rs
|
| pub const unsafe fn write<T>(dst: *mut T, src: T) {
| ^^^^^
Importantly, this error gives much more accurate span locations,
pointing to the offending field, rather than the entire macro
invocation.
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
The `#[pin_data]` macro uses some auxiliary traits to ensure that a user
does not implement `Drop` for the annotated struct, as that is unsound
and can lead to UB. However, if the struct that is annotated is
`!Sized`, the current bounds do not work, because `Sized` is an implicit
bound for generics.
This is *not* a soundness hole of pin-init, as it currently is
impossible to construct an unsized struct using pin-init.
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
Rewrite the attribute macro `#[pin_data]` using `syn`. No functional
changes intended aside from improved error messages on syntactic and
semantical errors. For example if one forgets a comma at the end of a
field:
#[pin_data]
struct Foo {
a: Box<Foo>
b: Box<Foo>
}
The declarative macro reports the following errors:
error: expected `,`, or `}`, found `b`
--> tests/ui/compile-fail/pin_data/missing_comma.rs:5:16
|
5 | a: Box<Foo>
| ^ help: try adding a comma: `,`
error: recursion limit reached while expanding `$crate::__pin_data!`
--> tests/ui/compile-fail/pin_data/missing_comma.rs:3:1
|
3 | #[pin_data]
| ^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`$CRATE`)
= note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info)
The new `syn` version reports:
error: expected `,`, or `}`, found `b`
--> tests/ui/compile-fail/pin_data/missing_comma.rs:5:16
|
5 | a: Box<Foo>
| ^ help: try adding a comma: `,`
error: expected `,`
--> tests/ui/compile-fail/pin_data/missing_comma.rs:6:5
|
6 | b: Box<Foo>
| ^
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
Rewrite the attribute macro for implementing `PinnedDrop` using `syn`.
Otherwise no functional changes intended aside from improved error
messages on syntactic and semantical errors. For example:
When missing the `drop` function in the implementation, the old error
was:
error: no rules expected `)`
--> tests/ui/compile-fail/pinned_drop/no_fn.rs:6:1
|
6 | #[pinned_drop]
| ^^^^^^^^^^^^^^ no rules expected this token in macro call
|
note: while trying to match keyword `fn`
--> src/macros.rs
|
| fn drop($($sig:tt)*) {
| ^^
= note: this error originates in the attribute macro `pinned_drop` (in Nightly builds, run with -Z macro-backtrace for more info)
And the new one is:
error[E0046]: not all trait items implemented, missing: `drop`
--> tests/ui/compile-fail/pinned_drop/no_fn.rs:7:1
|
7 | impl PinnedDrop for Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation
|
= help: implement the missing item: `fn drop(self: Pin<&mut Self>, _: OnlyCallFromDrop) { todo!() }`
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
Rewrite the two derive macros for `Zeroable` using `syn`. One positive
side effect of this change is that tuple structs are now supported by
them. Additionally, syntax errors and the error emitted when trying to
use one of the derive macros on an `enum` are improved. Otherwise no
functional changes intended.
For example:
#[derive(Zeroable)]
enum Num {
A(u32),
B(i32),
}
Produced this error before this commit:
error: no rules expected keyword `enum`
--> tests/ui/compile-fail/zeroable/enum.rs:5:1
|
5 | enum Num {
| ^^^^ no rules expected this token in macro call
|
note: while trying to match keyword `struct`
--> src/macros.rs
|
| $vis:vis struct $name:ident
| ^^^^^^
Now the error is:
error: cannot derive `Zeroable` for an enum
--> tests/ui/compile-fail/zeroable/enum.rs:5:1
|
5 | enum Num {
| ^^^^
error: cannot derive `Zeroable` for an enum
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
The API is similar to diagnostics handling in rustc and uses a
`ErrorGuaranteed` value to signify that an error has been emitted. It
supports both fatal errors (which abort the macro expansion immediately
by returning `Err(ErrorGuaranteed)`) and non-fatal ones at generation
time. These errors are appended to the token stream after generation has
finished normally. This allows giving good errors while still expanding
most of the code as expected to avoid the user encountering additional
errors (for example missing definitions).
Suggested-by: Gary Guo <gary@garyguo.net>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
[ remove duplicate word in commit message - Benno ]
Signed-off-by: Benno Lossin <lossin@kernel.org>