aboutsummaryrefslogtreecommitdiffstats
path: root/rust/pin-init/internal/src/init.rs
AgeCommit message (Collapse)AuthorFilesLines
2026-07-13rust: pin-init: internal: generate brace in macro for init code blocksGary Guo1-2/+4
`init!` support interleaving code execution and initialization, and code execution is done using `_: { ... }` syntax. If the code inside block is a single statement, Rust may add a lint about unused braces, but the suggestion will be incorrect as block is required by pin-init. Currently we use `unused_brace` to suppress this, but this affect everything nested inside as well. Use an alternative approach by generating the block from the macro, then rustc will know to not emit the lint. Reviewed-by: Benno Lossin <lossin@kernel.org> Link: https://patch.msgid.link/20260710-pin-init-sync-v1-5-8fa16cde87ae@garyguo.net Signed-off-by: Gary Guo <gary@garyguo.net>
2026-07-13rust: pin-init: internal: remove `allow` and `expect`s that don't fireGary Guo1-1/+1
Most warnings are suppressed from external macro expansions by default. Thus remove `allow` and `expect`s for them. Note that `unfulfilled_lint_expectations` is one of them too. This means that all of our `expect`s inside macros do nothing, and actually mislead people to the lints would be actually emitted without them. Reviewed-by: Benno Lossin <lossin@kernel.org> Link: https://patch.msgid.link/20260710-pin-init-sync-v1-4-8fa16cde87ae@garyguo.net Signed-off-by: Gary Guo <gary@garyguo.net>
2026-05-29rust: pin_init: internal: use `loop {}` to produce never valueGary Guo1-1/+1
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>
2026-05-29rust: pin-init: internal: suppress `non_snake_case` lint in `[pin_]init!`Mirko Adzic1-1/+3
Allows `non_snake_case` lint on local variables generated in `[pin_]init!`. Conceptually the identifiers in `[pin_]init!` just references the field names, and are not defining them, so the warning should not be generated, similar to how constructing a struct with non-snake-case field names do no generate these warnings. Reported-by: Gary Guo <gary@garyguo.net> Closes: https://github.com/Rust-for-Linux/pin-init/issues/125 Closes: https://lore.kernel.org/rust-for-linux/DGTBJBIVFZ2K.2F1ZEFGY0G7NK@garyguo.net/ Fixes: 42415d163e5d ("rust: pin-init: add references to previously initialized fields") Signed-off-by: Mirko Adzic <adzicmirko97@gmail.com> [ Reworded commit message - Gary ] Link: https://patch.msgid.link/20260527-pin-init-sync-v1-3-e20335ed2501@garyguo.net Signed-off-by: Gary Guo <gary@garyguo.net>
2026-05-18rust: pin-init: internal: project using full slotGary Guo1-3/+2
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>
2026-05-18rust: pin-init: internal: project slots instead of referencesGary Guo1-77/+36
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>
2026-05-18rust: pin-init: internal: make `make_closure` inherent methodsGary Guo1-5/+2
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>
2026-05-18rust: pin-init: internal: use marker on drop guard type for pinned fieldsGary Guo1-21/+26
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>
2026-05-18rust: pin-init: internal: init: handle code blocks earlyGary Guo1-45/+55
`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>
2026-05-10rust: pin-init: cleanup workaround for old Rust compilerGary Guo1-8/+1
The workaround mentions it's for Rust versions before 1.81. The minimum is now 1.82, thus clean up. Link: https://patch.msgid.link/20260428-pin-init-sync-v1-9-07f9bd3859fb@garyguo.net Signed-off-by: Gary Guo <gary@garyguo.net>
2026-04-30rust: pin-init: fix incorrect accessor reference lifetimeGary Guo1-59/+47
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: 42415d163e5d ("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>
2026-04-30rust: pin-init: internal: move alignment check to `make_field_check`Gary Guo1-41/+37
Instead of having the reference creation serving dual-purpose as both for let bindings and alignment check, detangle them so that the alignment check is done explicitly in `make_field_check`. This is more robust against refactors that may change the way let bindings are created. Cc: stable@vger.kernel.org Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260427-pin-init-fix-v3-1-496a699674dd@garyguo.net [ Reworded for typo. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-03-25rust: pin-init: replace `addr_of_mut!` with `&raw mut`Antonio Hickey1-4/+4
`feature(raw_ref_op)` became stable in Rust 1.82.0 which is the current MSRV of pin-init with no default features. Earlier Rust versions will now need to enable `raw_ref_op` to continue to work with pin-init. This reduces visual complexity and improves consistency with existing reference syntax. Suggested-by: Benno Lossin <lossin@kernel.org> Link: https://github.com/Rust-for-Linux/linux/issues/1148 Closes: https://github.com/Rust-for-Linux/pin-init/issues/99 Signed-off-by: Antonio Hickey <contact@antoniohickey.com> Link: https://github.com/Rust-for-Linux/pin-init/commit/e27763004e2f6616b089437fbe9b3719cd72bd5c [ Reworded commit message. - Benno ] Reviewed-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260319093542.3756606-6-lossin@kernel.org Signed-off-by: Benno Lossin <lossin@kernel.org>
2026-03-25rust: pin-init: properly document let binding workaroundBenno Lossin1-0/+6
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: https://github.com/Rust-for-Linux/pin-init/commit/bb3e96f3e9a4f5fca80a22af883c7e5aa90f0893 [ 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>
2026-03-12rust: pin-init: replace shadowed return token by `unsafe`-to-create tokenBenno Lossin1-15/+7
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: fc6c6baa1f40 ("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>
2026-03-06rust: pin-init: internal: init: document load-bearing fact of field accessorsBenno Lossin1-0/+8
The functions `[Pin]Init::__[pinned_]init` and `ptr::write` called from the `init!` macro require the passed pointer to be aligned. This fact is ensured by the creation of field accessors to previously initialized fields. Since we missed this very important fact from the beginning [1], document it in the code. Link: https://rust-for-linux.zulipchat.com/#narrow/channel/561532-pin-init/topic/initialized.20field.20accessor.20detection/with/576210658 [1] Fixes: 90e53c5e70a6 ("rust: add pin-init API core") Cc: <stable@vger.kernel.org> # 6.6.y, 6.12.y: 42415d163e5d: rust: pin-init: add references to previously initialized fields Cc: <stable@vger.kernel.org> # 6.6.y, 6.12.y, 6.18.y, 6.19.y Signed-off-by: Benno Lossin <lossin@kernel.org> Reviewed-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260302140424.4097655-2-lossin@kernel.org [ Updated Cc: stable@ tags as discussed. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-03-06rust: pin-init: internal: init: remove `#[disable_initialized_field_access]`Benno Lossin1-31/+8
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 ceca298c53f9 ("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: ceca298c53f9 ("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>
2026-01-17rust: pin-init: internal: init: simplify Zeroable safety checkBenno Lossin1-6/+1
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>
2026-01-17rust: pin-init: internal: init: add escape hatch for referencing initialized fieldsBenno Lossin1-23/+52
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>
2026-01-17rust: pin-init: internal: init: add support for attributes on initializer fieldsBenno Lossin1-14/+55
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>
2026-01-17rust: pin-init: add `#[default_error(<type>)]` attribute to initializer macrosBenno Lossin1-3/+41
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>
2026-01-17rust: pin-init: rewrite the initializer macros using `syn`Benno Lossin1-0/+445
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>