Skip to content

Commit a91a85e

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 a2159f0 commit a91a85e

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
@@ -346,45 +346,46 @@ fn generate_the_pin_data(
346346
// type. If a field is structurally pinned, we create a `Slot` with `Pinned` which must be
347347
// initialized via `PinInit`; if it is not structurally pinned, then we create a `Slot` with
348348
// `Unpinned` which allows initialization via `Init`.
349-
fn handle_field(
350-
Field {
351-
vis,
352-
ident,
353-
ty,
354-
attrs,
355-
..
356-
}: &Field,
357-
pinned: bool,
358-
) -> TokenStream {
359-
let ident = ident
360-
.as_ref()
361-
.expect("only structs with named fields are supported");
362-
let pin_marker = if pinned {
363-
quote!(Pinned)
364-
} else {
365-
quote!(Unpinned)
366-
};
367-
quote! {
368-
/// # Safety
369-
///
370-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
371-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
372-
#(#attrs)*
373-
#vis unsafe fn #ident(
374-
self,
375-
slot: *mut #ty,
376-
) -> ::pin_init::__internal::Slot<::pin_init::__internal::#pin_marker, #ty> {
377-
// SAFETY:
378-
// - If `#pin_marker` is `Pinned`, the corresponding field is structurally pinned.
379-
// - Other safety requirements follows the safety requirement.
380-
unsafe { ::pin_init::__internal::Slot::new(slot) }
381-
}
382-
}
383-
}
384-
385349
let field_accessors = fields
386350
.iter()
387-
.map(|(pinned, field)| handle_field(field, *pinned))
351+
.map(
352+
|(
353+
pinned,
354+
Field {
355+
vis,
356+
ident: field_name,
357+
ty,
358+
attrs,
359+
..
360+
},
361+
)| {
362+
let field_name = field_name
363+
.as_ref()
364+
.expect("only structs with named fields are supported");
365+
let pin_marker = if *pinned {
366+
quote!(Pinned)
367+
} else {
368+
quote!(Unpinned)
369+
};
370+
quote! {
371+
/// # Safety
372+
///
373+
/// - `slot` is valid and properly aligned.
374+
/// - `(*slot).#field_name` is properly aligned.
375+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
376+
#(#attrs)*
377+
#vis unsafe fn #field_name(
378+
self,
379+
slot: *mut #ident #ty_generics,
380+
) -> ::pin_init::__internal::Slot<::pin_init::__internal::#pin_marker, #ty> {
381+
// SAFETY:
382+
// - If `#pin_marker` is `Pinned`, the corresponding field is structurally pinned.
383+
// - Other safety requirements follows the safety requirement.
384+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).#field_name) }
385+
}
386+
}
387+
},
388+
)
388389
.collect::<TokenStream>();
389390
quote! {
390391
// 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
@@ -86,42 +86,45 @@ const _: () = {
8686
{
8787
/// # Safety
8888
///
89-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
90-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
89+
/// - `slot` is valid and properly aligned.
90+
/// - `(*slot).#field_name` is properly aligned.
91+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
9192
unsafe fn array(
9293
self,
93-
slot: *mut [u8; 1024 * 1024],
94+
slot: *mut Foo<'a, 'b, T, SIZE>,
9495
) -> ::pin_init::__internal::Slot<
9596
::pin_init::__internal::Unpinned,
9697
[u8; 1024 * 1024],
9798
> {
98-
unsafe { ::pin_init::__internal::Slot::new(slot) }
99+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).array) }
99100
}
100101
/// # Safety
101102
///
102-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
103-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
103+
/// - `slot` is valid and properly aligned.
104+
/// - `(*slot).#field_name` is properly aligned.
105+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
104106
unsafe fn r(
105107
self,
106-
slot: *mut &'b mut [&'a mut T; SIZE],
108+
slot: *mut Foo<'a, 'b, T, SIZE>,
107109
) -> ::pin_init::__internal::Slot<
108110
::pin_init::__internal::Unpinned,
109111
&'b mut [&'a mut T; SIZE],
110112
> {
111-
unsafe { ::pin_init::__internal::Slot::new(slot) }
113+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).r) }
112114
}
113115
/// # Safety
114116
///
115-
/// - `slot` points to a `#ident` field of a pinned struct that this `__ThePinData` describes.
116-
/// - `slot` is a valid, properly aligned and points to uninitialized and exclusively memory.
117+
/// - `slot` is valid and properly aligned.
118+
/// - `(*slot).#field_name` is properly aligned.
119+
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed memory.
117120
unsafe fn _pin(
118121
self,
119-
slot: *mut PhantomPinned,
122+
slot: *mut Foo<'a, 'b, T, SIZE>,
120123
) -> ::pin_init::__internal::Slot<
121124
::pin_init::__internal::Pinned,
122125
PhantomPinned,
123126
> {
124-
unsafe { ::pin_init::__internal::Slot::new(slot) }
127+
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot)._pin) }
125128
}
126129
}
127130
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)