Skip to content

Commit b04d170

Browse files
committed
Merge tag 'pin-init-v6.16' of https://github.com/Rust-for-Linux/linux into rust-next
Pull pin-init updates from Benno Lossin: "Added: - 'Wrapper<T>' trait for creating pin-initializers for wrapper structs with a structurally pinned value such as 'UnsafeCell<T>' or 'MaybeUninit<T>'. - 'MaybeZeroable' derive macro to try to derive 'Zeroable', but not error if not all fields implement it. This is needed to derive 'Zeroable' for all bindgen-generated structs. - 'unsafe fn cast_[pin_]init()' functions to unsafely change the initialized type of an initializer. These are utilized by the 'Wrapper<T>' implementations. Changed: - Added support for visibility in 'Zeroable' derive macro. - Added support for 'union's in 'Zeroable' derive macro. Upstream dev news: - The CI has been streamlined & some bugs with it have been fixed. I also added new workflows to check if the user-space version and the one in the kernel tree have diverged. - I also started to use the issues [1] tab to keep track of any problems or unexpected/unwanted things. This should help folks report and diagnose issues w.r.t. 'pin-init' better. [1] https://github.com/rust-for-linux/pin-init/issues" * tag 'pin-init-v6.16' of https://github.com/Rust-for-Linux/linux: rust: pin-init: improve documentation for `Zeroable` derive macros rust: pin-init: fix typos rust: pin-init: add `MaybeZeroable` derive macro rust: pin-init: allow `Zeroable` derive macro to also be applied to unions rust: pin-init: allow `pub` fields in `derive(Zeroable)` rust: pin-init: Update the structural pinning link in readme. rust: pin-init: Update Changelog and Readme rust: pin-init: Implement `Wrapper` for `UnsafePinned` behind feature flag. rust: pin-init: Add the `Wrapper` trait. rust: pin-init: add `cast_[pin_]init` functions to change the initialized type rust: pin-init: examples: use `allow` instead of `expect` rust: pin-init: examples: conditionally enable `feature(lint_reasons)` rust: pin-init: internal: skip rustfmt formatting of kernel-only module rust: pin-init: synchronize README.md
2 parents 06ff274 + 9de1a29 commit b04d170

File tree

9 files changed

+279
-10
lines changed

9 files changed

+279
-10
lines changed

rust/pin-init/README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ However, using the crate on stable compilers is possible by disabling `alloc`. I
4040
will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
4141
mode.
4242

43+
### Nightly needed for `unsafe-pinned` feature
44+
45+
This feature enables the `Wrapper` implementation on the unstable `core::pin::UnsafePinned` type.
46+
This requires the [`unsafe_pinned` unstable feature](https://github.com/rust-lang/rust/issues/125735)
47+
and therefore a nightly compiler. Note that this feature is not enabled by default.
48+
4349
## Overview
4450

4551
To initialize a `struct` with an in-place constructor you will need two things:
@@ -216,13 +222,15 @@ the `kernel` crate. The [`sync`] module is a good starting point.
216222

217223
[`sync`]: https://rust.docs.kernel.org/kernel/sync/index.html
218224
[pinning]: https://doc.rust-lang.org/std/pin/index.html
219-
[structurally pinned fields]: https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
225+
[structurally pinned fields]: https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning
220226
[stack]: https://docs.rs/pin-init/latest/pin_init/macro.stack_pin_init.html
221-
[`Arc<T>`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html
222-
[`Box<T>`]: https://doc.rust-lang.org/stable/alloc/boxed/struct.Box.html
223227
[`impl PinInit<Foo>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
224228
[`impl PinInit<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
225229
[`impl Init<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.Init.html
226230
[Rust-for-Linux]: https://rust-for-linux.com/
227231

228232
<!-- cargo-rdme end -->
233+
234+
<!-- These links are not picked up by cargo-rdme, since they are behind cfgs... -->
235+
[`Arc<T>`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html
236+
[`Box<T>`]: https://doc.rust-lang.org/stable/alloc/boxed/struct.Box.html

rust/pin-init/examples/linked_list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![allow(clippy::undocumented_unsafe_blocks)]
44
#![cfg_attr(feature = "alloc", feature(allocator_api))]
5+
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
56

67
use core::{
78
cell::Cell,

rust/pin-init/examples/mutex.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![allow(clippy::undocumented_unsafe_blocks)]
44
#![cfg_attr(feature = "alloc", feature(allocator_api))]
5+
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
56
#![allow(clippy::missing_safety_doc)]
67

78
use core::{

rust/pin-init/examples/pthread_mutex.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// inspired by <https://github.com/nbdd0121/pin-init/blob/trunk/examples/pthread_mutex.rs>
44
#![allow(clippy::undocumented_unsafe_blocks)]
55
#![cfg_attr(feature = "alloc", feature(allocator_api))]
6+
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
7+
68
#[cfg(not(windows))]
79
mod pthread_mtx {
810
#[cfg(feature = "alloc")]
@@ -40,7 +42,7 @@ mod pthread_mtx {
4042

4143
#[derive(Debug)]
4244
pub enum Error {
43-
#[expect(dead_code)]
45+
#[allow(dead_code)]
4446
IO(std::io::Error),
4547
Alloc,
4648
}

rust/pin-init/examples/static_init.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![allow(clippy::undocumented_unsafe_blocks)]
44
#![cfg_attr(feature = "alloc", feature(allocator_api))]
5+
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
56

67
use core::{
78
cell::{Cell, UnsafeCell},

rust/pin-init/internal/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use proc_macro::TokenStream;
2222
#[cfg(kernel)]
2323
#[path = "../../../macros/quote.rs"]
2424
#[macro_use]
25+
#[cfg_attr(not(kernel), rustfmt::skip)]
2526
mod quote;
2627
#[cfg(not(kernel))]
2728
#[macro_use]
@@ -46,3 +47,8 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
4647
pub fn derive_zeroable(input: TokenStream) -> TokenStream {
4748
zeroable::derive(input.into()).into()
4849
}
50+
51+
#[proc_macro_derive(MaybeZeroable)]
52+
pub fn maybe_derive_zeroable(input: TokenStream) -> TokenStream {
53+
zeroable::maybe_derive(input.into()).into()
54+
}

rust/pin-init/internal/src/zeroable.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@ use proc_macro2 as proc_macro;
66
use crate::helpers::{parse_generics, Generics};
77
use proc_macro::{TokenStream, TokenTree};
88

9-
pub(crate) fn derive(input: TokenStream) -> TokenStream {
9+
pub(crate) fn parse_zeroable_derive_input(
10+
input: TokenStream,
11+
) -> (
12+
Vec<TokenTree>,
13+
Vec<TokenTree>,
14+
Vec<TokenTree>,
15+
Option<TokenTree>,
16+
) {
1017
let (
1118
Generics {
1219
impl_generics,
@@ -64,6 +71,11 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {
6471
if in_generic && !inserted {
6572
new_impl_generics.extend(quote! { : ::pin_init::Zeroable });
6673
}
74+
(rest, new_impl_generics, ty_generics, last)
75+
}
76+
77+
pub(crate) fn derive(input: TokenStream) -> TokenStream {
78+
let (rest, new_impl_generics, ty_generics, last) = parse_zeroable_derive_input(input);
6779
quote! {
6880
::pin_init::__derive_zeroable!(
6981
parse_input:
@@ -74,3 +86,16 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {
7486
);
7587
}
7688
}
89+
90+
pub(crate) fn maybe_derive(input: TokenStream) -> TokenStream {
91+
let (rest, new_impl_generics, ty_generics, last) = parse_zeroable_derive_input(input);
92+
quote! {
93+
::pin_init::__maybe_derive_zeroable!(
94+
parse_input:
95+
@sig(#(#rest)*),
96+
@impl_generics(#(#new_impl_generics)*),
97+
@ty_generics(#(#ty_generics)*),
98+
@body(#last),
99+
);
100+
}
101+
}

rust/pin-init/src/lib.rs

Lines changed: 140 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
//! will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
3333
//! mode.
3434
//!
35+
//! ## Nightly needed for `unsafe-pinned` feature
36+
//!
37+
//! This feature enables the `Wrapper` implementation on the unstable `core::pin::UnsafePinned` type.
38+
//! This requires the [`unsafe_pinned` unstable feature](https://github.com/rust-lang/rust/issues/125735)
39+
//! and therefore a nightly compiler. Note that this feature is not enabled by default.
40+
//!
3541
//! # Overview
3642
//!
3743
//! To initialize a `struct` with an in-place constructor you will need two things:
@@ -241,7 +247,7 @@
241247
//! [`sync`]: https://rust.docs.kernel.org/kernel/sync/index.html
242248
//! [pinning]: https://doc.rust-lang.org/std/pin/index.html
243249
//! [structurally pinned fields]:
244-
//! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
250+
//! https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning
245251
//! [stack]: crate::stack_pin_init
246252
#![cfg_attr(
247253
kernel,
@@ -269,6 +275,10 @@
269275
#![forbid(missing_docs, unsafe_op_in_unsafe_fn)]
270276
#![cfg_attr(not(feature = "std"), no_std)]
271277
#![cfg_attr(feature = "alloc", feature(allocator_api))]
278+
#![cfg_attr(
279+
all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED),
280+
feature(unsafe_pinned)
281+
)]
272282

273283
use core::{
274284
cell::UnsafeCell,
@@ -385,9 +395,10 @@ pub use ::pin_init_internal::pin_data;
385395
/// ```
386396
pub use ::pin_init_internal::pinned_drop;
387397

388-
/// Derives the [`Zeroable`] trait for the given struct.
398+
/// Derives the [`Zeroable`] trait for the given `struct` or `union`.
389399
///
390-
/// This can only be used for structs where every field implements the [`Zeroable`] trait.
400+
/// This can only be used for `struct`s/`union`s where every field implements the [`Zeroable`]
401+
/// trait.
391402
///
392403
/// # Examples
393404
///
@@ -396,13 +407,54 @@ pub use ::pin_init_internal::pinned_drop;
396407
///
397408
/// #[derive(Zeroable)]
398409
/// pub struct DriverData {
399-
/// id: i64,
410+
/// pub(crate) id: i64,
400411
/// buf_ptr: *mut u8,
401412
/// len: usize,
402413
/// }
403414
/// ```
415+
///
416+
/// ```
417+
/// use pin_init::Zeroable;
418+
///
419+
/// #[derive(Zeroable)]
420+
/// pub union SignCast {
421+
/// signed: i64,
422+
/// unsigned: u64,
423+
/// }
424+
/// ```
404425
pub use ::pin_init_internal::Zeroable;
405426

427+
/// Derives the [`Zeroable`] trait for the given `struct` or `union` if all fields implement
428+
/// [`Zeroable`].
429+
///
430+
/// Contrary to the derive macro named [`macro@Zeroable`], this one silently fails when a field
431+
/// doesn't implement [`Zeroable`].
432+
///
433+
/// # Examples
434+
///
435+
/// ```
436+
/// use pin_init::MaybeZeroable;
437+
///
438+
/// // implmements `Zeroable`
439+
/// #[derive(MaybeZeroable)]
440+
/// pub struct DriverData {
441+
/// pub(crate) id: i64,
442+
/// buf_ptr: *mut u8,
443+
/// len: usize,
444+
/// }
445+
///
446+
/// // does not implmement `Zeroable`
447+
/// #[derive(MaybeZeroable)]
448+
/// pub struct DriverData2 {
449+
/// pub(crate) id: i64,
450+
/// buf_ptr: *mut u8,
451+
/// len: usize,
452+
/// // this field doesn't implement `Zeroable`
453+
/// other_data: &'static i32,
454+
/// }
455+
/// ```
456+
pub use ::pin_init_internal::MaybeZeroable;
457+
406458
/// Initialize and pin a type directly on the stack.
407459
///
408460
/// # Examples
@@ -1216,6 +1268,38 @@ pub const unsafe fn init_from_closure<T: ?Sized, E>(
12161268
__internal::InitClosure(f, PhantomData)
12171269
}
12181270

1271+
/// Changes the to be initialized type.
1272+
///
1273+
/// # Safety
1274+
///
1275+
/// - `*mut U` must be castable to `*mut T` and any value of type `T` written through such a
1276+
/// pointer must result in a valid `U`.
1277+
#[expect(clippy::let_and_return)]
1278+
pub const unsafe fn cast_pin_init<T, U, E>(init: impl PinInit<T, E>) -> impl PinInit<U, E> {
1279+
// SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety
1280+
// requirements.
1281+
let res = unsafe { pin_init_from_closure(|ptr: *mut U| init.__pinned_init(ptr.cast::<T>())) };
1282+
// FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a
1283+
// cycle when computing the type returned by this function)
1284+
res
1285+
}
1286+
1287+
/// Changes the to be initialized type.
1288+
///
1289+
/// # Safety
1290+
///
1291+
/// - `*mut U` must be castable to `*mut T` and any value of type `T` written through such a
1292+
/// pointer must result in a valid `U`.
1293+
#[expect(clippy::let_and_return)]
1294+
pub const unsafe fn cast_init<T, U, E>(init: impl Init<T, E>) -> impl Init<U, E> {
1295+
// SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety
1296+
// requirements.
1297+
let res = unsafe { init_from_closure(|ptr: *mut U| init.__init(ptr.cast::<T>())) };
1298+
// FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a
1299+
// cycle when computing the type returned by this function)
1300+
res
1301+
}
1302+
12191303
/// An initializer that leaves the memory uninitialized.
12201304
///
12211305
/// The initializer is a no-op. The `slot` memory is not changed.
@@ -1481,3 +1565,55 @@ macro_rules! impl_tuple_zeroable {
14811565
}
14821566

14831567
impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J);
1568+
1569+
/// This trait allows creating an instance of `Self` which contains exactly one
1570+
/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
1571+
///
1572+
/// This is useful when using wrapper `struct`s like [`UnsafeCell`] or with new-type `struct`s.
1573+
///
1574+
/// # Examples
1575+
///
1576+
/// ```
1577+
/// # use core::cell::UnsafeCell;
1578+
/// # use pin_init::{pin_data, pin_init, Wrapper};
1579+
///
1580+
/// #[pin_data]
1581+
/// struct Foo {}
1582+
///
1583+
/// #[pin_data]
1584+
/// struct Bar {
1585+
/// #[pin]
1586+
/// content: UnsafeCell<Foo>
1587+
/// };
1588+
///
1589+
/// let foo_initializer = pin_init!(Foo{});
1590+
/// let initializer = pin_init!(Bar {
1591+
/// content <- UnsafeCell::pin_init(foo_initializer)
1592+
/// });
1593+
/// ```
1594+
pub trait Wrapper<T> {
1595+
/// Creates an pin-initializer for a [`Self`] containing `T` from the `value_init` initializer.
1596+
fn pin_init<E>(value_init: impl PinInit<T, E>) -> impl PinInit<Self, E>;
1597+
}
1598+
1599+
impl<T> Wrapper<T> for UnsafeCell<T> {
1600+
fn pin_init<E>(value_init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
1601+
// SAFETY: `UnsafeCell<T>` has a compatible layout to `T`.
1602+
unsafe { cast_pin_init(value_init) }
1603+
}
1604+
}
1605+
1606+
impl<T> Wrapper<T> for MaybeUninit<T> {
1607+
fn pin_init<E>(value_init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
1608+
// SAFETY: `MaybeUninit<T>` has a compatible layout to `T`.
1609+
unsafe { cast_pin_init(value_init) }
1610+
}
1611+
}
1612+
1613+
#[cfg(all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED))]
1614+
impl<T> Wrapper<T> for core::pin::UnsafePinned<T> {
1615+
fn pin_init<E>(init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
1616+
// SAFETY: `UnsafePinned<T>` has a compatible layout to `T`.
1617+
unsafe { cast_pin_init(init) }
1618+
}
1619+
}

0 commit comments

Comments
 (0)