Skip to content

Commit 6056cad

Browse files
committed
internal: project using full slot
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>
1 parent a11eac9 commit 6056cad

6 files changed

Lines changed: 81 additions & 71 deletions

File tree

internal/src/init.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,11 @@ fn init_fields(
232232
let slot = if pinned {
233233
quote! {
234234
// SAFETY:
235-
// - `&raw mut (*slot).#ident` points to the `#ident` field of `slot`.
236-
// - `&raw mut (*slot).#ident` is valid.
235+
// - `slot` is valid and properly aligned.
237236
// - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned.
238237
// - `make_field_check` prevents `#ident` from being used twice, therefore
239238
// `(*slot).#ident` is exclusively accessed and has not been initialized.
240-
(unsafe { #data.#ident(&raw mut (*#slot).#ident) })
239+
(unsafe { #data.#ident(#slot) })
241240
}
242241
} else {
243242
quote! {

internal/src/pin_data.rs

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -344,45 +344,46 @@ fn generate_the_pin_data(
344344
// type. If a field is structurally pinned, we create a `Slot` with `Pinned` which must be
345345
// initialized via `PinInit`; if it is not structurally pinned, then we create a `Slot` with
346346
// `Unpinned` which allows initialization via `Init`.
347-
fn handle_field(
348-
Field {
349-
vis,
350-
ident,
351-
ty,
352-
attrs,
353-
..
354-
}: &Field,
355-
pinned: bool,
356-
) -> TokenStream {
357-
let ident = ident
358-
.as_ref()
359-
.expect("only structs with named fields are supported");
360-
let pin_marker = if pinned {
361-
quote!(Pinned)
362-
} else {
363-
quote!(Unpinned)
364-
};
365-
quote! {
366-
/// # Safety
367-
///
368-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
369-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
370-
#(#attrs)*
371-
#vis unsafe fn #ident(
372-
self,
373-
slot: *mut #ty,
374-
) -> ::pin_init::__internal::Slot<::pin_init::__internal::#pin_marker, #ty> {
375-
// SAFETY:
376-
// - If `#pin_marker` is `Pinned`, the corresponding field is structurally pinned.
377-
// - Other safety requirements follows the safety requirement.
378-
unsafe { ::pin_init::__internal::Slot::new(slot) }
379-
}
380-
}
381-
}
382-
383347
let field_accessors = fields
384348
.iter()
385-
.map(|(pinned, field)| handle_field(field, *pinned))
349+
.map(
350+
|(
351+
pinned,
352+
Field {
353+
vis,
354+
ident: field_name,
355+
ty,
356+
attrs,
357+
..
358+
},
359+
)| {
360+
let field_name = field_name
361+
.as_ref()
362+
.expect("only structs with named fields are supported");
363+
let pin_marker = if *pinned {
364+
quote!(Pinned)
365+
} else {
366+
quote!(Unpinned)
367+
};
368+
quote! {
369+
/// # Safety
370+
///
371+
/// - `slot` is valid and properly aligned.
372+
/// - `(*slot).#field_name` is properly aligned.
373+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
374+
#(#attrs)*
375+
#vis unsafe fn #field_name(
376+
self,
377+
slot: *mut #ident #ty_generics,
378+
) -> ::pin_init::__internal::Slot<::pin_init::__internal::#pin_marker, #ty> {
379+
// SAFETY:
380+
// - If `#pin_marker` is `Pinned`, the corresponding field is structurally pinned.
381+
// - Other safety requirements follows the safety requirement.
382+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).#field_name) }
383+
}
384+
}
385+
},
386+
)
386387
.collect::<TokenStream>();
387388
quote! {
388389
// We declare this struct which will host all of the projection function for our type. It

src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -868,10 +868,13 @@ pub use pin_init_internal::init;
868868
macro_rules! assert_pinned {
869869
($ty:ty, $field:ident, $field_ty:ty, inline) => {
870870
// SAFETY: This code is unreachable.
871-
let _ = move |ptr: *mut $field_ty| unsafe {
871+
let _ = move || unsafe {
872872
let data = <$ty as $crate::__internal::HasPinData>::__pin_data();
873-
data.$field(ptr)
874-
.init($crate::__internal::AlwaysFail::<$field_ty>::new());
873+
data.__make_init(move |slot| {
874+
data.$field(slot)
875+
.init($crate::__internal::AlwaysFail::<$field_ty>::new())?;
876+
Err(())
877+
})
875878
};
876879
};
877880

tests/ui/expand/many_generics.expanded.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,42 +84,45 @@ const _: () = {
8484
{
8585
/// # Safety
8686
///
87-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
88-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
87+
/// - `slot` is valid and properly aligned.
88+
/// - `(*slot).#field_name` is properly aligned.
89+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
8990
unsafe fn array(
9091
self,
91-
slot: *mut [u8; 1024 * 1024],
92+
slot: *mut Foo<'a, 'b, T, SIZE>,
9293
) -> ::pin_init::__internal::Slot<
9394
::pin_init::__internal::Unpinned,
9495
[u8; 1024 * 1024],
9596
> {
96-
unsafe { ::pin_init::__internal::Slot::new(slot) }
97+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).array) }
9798
}
9899
/// # Safety
99100
///
100-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
101-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
101+
/// - `slot` is valid and properly aligned.
102+
/// - `(*slot).#field_name` is properly aligned.
103+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
102104
unsafe fn r(
103105
self,
104-
slot: *mut &'b mut [&'a mut T; SIZE],
106+
slot: *mut Foo<'a, 'b, T, SIZE>,
105107
) -> ::pin_init::__internal::Slot<
106108
::pin_init::__internal::Unpinned,
107109
&'b mut [&'a mut T; SIZE],
108110
> {
109-
unsafe { ::pin_init::__internal::Slot::new(slot) }
111+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).r) }
110112
}
111113
/// # Safety
112114
///
113-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
114-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
115+
/// - `slot` is valid and properly aligned.
116+
/// - `(*slot).#field_name` is properly aligned.
117+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
115118
unsafe fn _pin(
116119
self,
117-
slot: *mut PhantomPinned,
120+
slot: *mut Foo<'a, 'b, T, SIZE>,
118121
) -> ::pin_init::__internal::Slot<
119122
::pin_init::__internal::Pinned,
120123
PhantomPinned,
121124
> {
122-
unsafe { ::pin_init::__internal::Slot::new(slot) }
125+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot)._pin) }
123126
}
124127
}
125128
unsafe impl<

tests/ui/expand/pin-data.expanded.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,29 +48,31 @@ const _: () = {
4848
impl __ThePinData {
4949
/// # Safety
5050
///
51-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
52-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
51+
/// - `slot` is valid and properly aligned.
52+
/// - `(*slot).#field_name` is properly aligned.
53+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
5354
unsafe fn array(
5455
self,
55-
slot: *mut [u8; 1024 * 1024],
56+
slot: *mut Foo,
5657
) -> ::pin_init::__internal::Slot<
5758
::pin_init::__internal::Unpinned,
5859
[u8; 1024 * 1024],
5960
> {
60-
unsafe { ::pin_init::__internal::Slot::new(slot) }
61+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).array) }
6162
}
6263
/// # Safety
6364
///
64-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
65-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
65+
/// - `slot` is valid and properly aligned.
66+
/// - `(*slot).#field_name` is properly aligned.
67+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
6668
unsafe fn _pin(
6769
self,
68-
slot: *mut PhantomPinned,
70+
slot: *mut Foo,
6971
) -> ::pin_init::__internal::Slot<
7072
::pin_init::__internal::Pinned,
7173
PhantomPinned,
7274
> {
73-
unsafe { ::pin_init::__internal::Slot::new(slot) }
75+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot)._pin) }
7476
}
7577
}
7678
unsafe impl ::pin_init::__internal::HasPinData for Foo {

tests/ui/expand/pinned_drop.expanded.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,29 +48,31 @@ const _: () = {
4848
impl __ThePinData {
4949
/// # Safety
5050
///
51-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
52-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
51+
/// - `slot` is valid and properly aligned.
52+
/// - `(*slot).#field_name` is properly aligned.
53+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
5354
unsafe fn array(
5455
self,
55-
slot: *mut [u8; 1024 * 1024],
56+
slot: *mut Foo,
5657
) -> ::pin_init::__internal::Slot<
5758
::pin_init::__internal::Unpinned,
5859
[u8; 1024 * 1024],
5960
> {
60-
unsafe { ::pin_init::__internal::Slot::new(slot) }
61+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).array) }
6162
}
6263
/// # Safety
6364
///
64-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
65-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
65+
/// - `slot` is valid and properly aligned.
66+
/// - `(*slot).#field_name` is properly aligned.
67+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
6668
unsafe fn _pin(
6769
self,
68-
slot: *mut PhantomPinned,
70+
slot: *mut Foo,
6971
) -> ::pin_init::__internal::Slot<
7072
::pin_init::__internal::Pinned,
7173
PhantomPinned,
7274
> {
73-
unsafe { ::pin_init::__internal::Slot::new(slot) }
75+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot)._pin) }
7476
}
7577
}
7678
unsafe impl ::pin_init::__internal::HasPinData for Foo {

0 commit comments

Comments
 (0)