Skip to content

Commit 0a1f2a3

Browse files
authored
Merge pull request #152 from Rust-for-Linux/dev/field_info
internal: pin_data: add struct to record field info
2 parents 41ed491 + ef572c1 commit 0a1f2a3

4 files changed

Lines changed: 113 additions & 106 deletions

File tree

internal/src/pin_data.rs

Lines changed: 99 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ impl Parse for Args {
3535
}
3636
}
3737

38+
struct FieldInfo<'a> {
39+
field: &'a Field,
40+
pinned: bool,
41+
}
42+
3843
pub(crate) fn pin_data(
3944
args: Args,
4045
input: Item,
@@ -73,24 +78,30 @@ pub(crate) fn pin_data(
7378
replacer.visit_generics_mut(&mut struct_.generics);
7479
replacer.visit_fields_mut(&mut struct_.fields);
7580

76-
let fields: Vec<(bool, &Field)> = struct_
81+
let fields: Vec<FieldInfo<'_>> = struct_
7782
.fields
7883
.iter_mut()
7984
.map(|field| {
8085
let len = field.attrs.len();
8186
field.attrs.retain(|a| !a.path().is_ident("pin"));
82-
(len != field.attrs.len(), &*field)
87+
let pinned = len != field.attrs.len();
88+
89+
FieldInfo {
90+
field: &*field,
91+
pinned,
92+
}
8393
})
8494
.collect();
8595

86-
for (pinned, field) in &fields {
87-
if !pinned && is_phantom_pinned(&field.ty) {
96+
for field in &fields {
97+
let ident = field.field.ident.as_ref().unwrap();
98+
99+
if !field.pinned && is_phantom_pinned(&field.field.ty) {
88100
dcx.warn(
89-
field,
101+
field.field,
90102
format!(
91-
"The field `{}` of type `PhantomPinned` only has an effect \
103+
"The field `{ident}` of type `PhantomPinned` only has an effect \
92104
if it has the `#[pin]` attribute",
93-
field.ident.as_ref().unwrap(),
94105
),
95106
);
96107
}
@@ -143,7 +154,7 @@ fn is_phantom_pinned(ty: &Type) -> bool {
143154
fn generate_unpin_impl(
144155
ident: &Ident,
145156
generics: &Generics,
146-
fields: &[(bool, &Field)],
157+
fields: &[FieldInfo<'_>],
147158
) -> TokenStream {
148159
let (_, ty_generics, _) = generics.split_for_impl();
149160
let mut generics_with_pin_lt = generics.clone();
@@ -160,7 +171,7 @@ fn generate_unpin_impl(
160171
else {
161172
unreachable!()
162173
};
163-
let pinned_fields = fields.iter().filter_map(|(b, f)| b.then_some(f));
174+
let pinned_fields = fields.iter().filter(|f| f.pinned).map(|f| f.field);
164175
quote! {
165176
// This struct will be used for the unpin analysis. It is needed, because only structurally
166177
// pinned fields are relevant whether the struct should implement `Unpin`.
@@ -238,7 +249,7 @@ fn generate_projections(
238249
vis: &Visibility,
239250
ident: &Ident,
240251
generics: &Generics,
241-
fields: &[(bool, &Field)],
252+
fields: &[FieldInfo<'_>],
242253
) -> TokenStream {
243254
let (impl_generics, ty_generics, _) = generics.split_for_impl();
244255
let mut generics_with_pin_lt = generics.clone();
@@ -249,21 +260,21 @@ fn generate_projections(
249260

250261
let (fields_decl, fields_proj): (Vec<_>, Vec<_>) = fields
251262
.iter()
252-
.map(|(pinned, field)| {
263+
.map(|field| {
253264
let Field {
254265
vis,
255266
ident,
256267
ty,
257268
attrs,
258269
..
259-
} = field;
270+
} = &field.field;
260271

261272
let mut no_doc_attrs = attrs.clone();
262273
no_doc_attrs.retain(|a| !a.path().is_ident("doc"));
263274
let ident = ident
264275
.as_ref()
265276
.expect("only structs with named fields are supported");
266-
if *pinned {
277+
if field.pinned {
267278
(
268279
quote!(
269280
#(#attrs)*
@@ -291,12 +302,12 @@ fn generate_projections(
291302
.collect();
292303
let structurally_pinned_fields_docs = fields
293304
.iter()
294-
.filter_map(|(pinned, field)| pinned.then_some(field))
295-
.map(|Field { ident, .. }| format!(" - `{}`", ident.as_ref().unwrap()));
305+
.filter(|f| f.pinned)
306+
.map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap()));
296307
let not_structurally_pinned_fields_docs = fields
297308
.iter()
298-
.filter_map(|(pinned, field)| (!pinned).then_some(field))
299-
.map(|Field { ident, .. }| format!(" - `{}`", ident.as_ref().unwrap()));
309+
.filter(|f| !f.pinned)
310+
.map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap()));
300311
let docs = format!(" Pin-projections of [`{ident}`]");
301312
quote! {
302313
#[doc = #docs]
@@ -336,9 +347,9 @@ fn generate_projections(
336347

337348
fn generate_the_pin_data(
338349
vis: &Visibility,
339-
ident: &Ident,
350+
struct_name: &Ident,
340351
generics: &Generics,
341-
fields: &[(bool, &Field)],
352+
fields: &[FieldInfo<'_>],
342353
) -> TokenStream {
343354
let (impl_generics, ty_generics, whr) = generics.split_for_impl();
344355

@@ -347,78 +358,74 @@ fn generate_the_pin_data(
347358
// not structurally pinned, then it can be initialized via `Init`.
348359
//
349360
// The functions are `unsafe` to prevent accidentally calling them.
350-
fn handle_field(
351-
Field {
352-
vis,
353-
ident,
354-
ty,
355-
attrs,
356-
..
357-
}: &Field,
358-
struct_ident: &Ident,
359-
pinned: bool,
360-
) -> TokenStream {
361-
let ident = ident
362-
.as_ref()
363-
.expect("only structs with named fields are supported");
364-
let project_ident = format_ident!("__project_{ident}");
365-
let (init_ty, init_fn, project_ty, project_body, pin_safety) = if pinned {
366-
(
367-
quote!(PinInit),
368-
quote!(__pinned_init),
369-
quote!(::core::pin::Pin<&'__slot mut #ty>),
370-
// SAFETY: this field is structurally pinned.
371-
quote!(unsafe { ::core::pin::Pin::new_unchecked(slot) }),
372-
quote!(
373-
/// - `slot` will not move until it is dropped, i.e. it will be pinned.
374-
),
375-
)
376-
} else {
377-
(
378-
quote!(Init),
379-
quote!(__init),
380-
quote!(&'__slot mut #ty),
381-
quote!(slot),
382-
quote!(),
383-
)
384-
};
385-
let slot_safety = format!(
386-
" `slot` points at the field `{ident}` inside of `{struct_ident}`, which is pinned.",
387-
);
388-
quote! {
389-
/// # Safety
390-
///
391-
/// - `slot` is a valid pointer to uninitialized memory.
392-
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
393-
/// to deallocate.
394-
#pin_safety
395-
#(#attrs)*
396-
#vis unsafe fn #ident<E>(
397-
self,
398-
slot: *mut #ty,
399-
init: impl ::pin_init::#init_ty<#ty, E>,
400-
) -> ::core::result::Result<(), E> {
401-
// SAFETY: this function has the same safety requirements as the __init function
402-
// called below.
403-
unsafe { ::pin_init::#init_ty::#init_fn(init, slot) }
404-
}
405-
406-
/// # Safety
407-
///
408-
#[doc = #slot_safety]
409-
#(#attrs)*
410-
#vis unsafe fn #project_ident<'__slot>(
411-
self,
412-
slot: &'__slot mut #ty,
413-
) -> #project_ty {
414-
#project_body
415-
}
416-
}
417-
}
418-
419361
let field_accessors = fields
420362
.iter()
421-
.map(|(pinned, field)| handle_field(field, ident, *pinned))
363+
.map(|f| {
364+
let Field {
365+
vis,
366+
ident,
367+
ty,
368+
attrs,
369+
..
370+
} = f.field;
371+
372+
let field_name = ident
373+
.as_ref()
374+
.expect("only structs with named fields are supported");
375+
let project_ident = format_ident!("__project_{field_name}");
376+
let (init_ty, init_fn, project_ty, project_body, pin_safety) = if f.pinned {
377+
(
378+
quote!(PinInit),
379+
quote!(__pinned_init),
380+
quote!(::core::pin::Pin<&'__slot mut #ty>),
381+
// SAFETY: this field is structurally pinned.
382+
quote!(unsafe { ::core::pin::Pin::new_unchecked(slot) }),
383+
quote!(
384+
/// - `slot` will not move until it is dropped, i.e. it will be pinned.
385+
),
386+
)
387+
} else {
388+
(
389+
quote!(Init),
390+
quote!(__init),
391+
quote!(&'__slot mut #ty),
392+
quote!(slot),
393+
quote!(),
394+
)
395+
};
396+
let slot_safety = format!(
397+
" `slot` points at the field `{field_name}` inside of `{struct_name}`, which is pinned.",
398+
);
399+
quote! {
400+
/// # Safety
401+
///
402+
/// - `slot` is a valid pointer to uninitialized memory.
403+
/// - the caller does not touch `slot` when `Err` is returned, they are only
404+
/// permitted to deallocate.
405+
#pin_safety
406+
#(#attrs)*
407+
#vis unsafe fn #field_name<E>(
408+
self,
409+
slot: *mut #ty,
410+
init: impl ::pin_init::#init_ty<#ty, E>,
411+
) -> ::core::result::Result<(), E> {
412+
// SAFETY: this function has the same safety requirements as the __init function
413+
// called below.
414+
unsafe { ::pin_init::#init_ty::#init_fn(init, slot) }
415+
}
416+
417+
/// # Safety
418+
///
419+
#[doc = #slot_safety]
420+
#(#attrs)*
421+
#vis unsafe fn #project_ident<'__slot>(
422+
self,
423+
slot: &'__slot mut #ty,
424+
) -> #project_ty {
425+
#project_body
426+
}
427+
}
428+
})
422429
.collect::<TokenStream>();
423430
quote! {
424431
// We declare this struct which will host all of the projection function for our type. It
@@ -428,7 +435,7 @@ fn generate_the_pin_data(
428435
#whr
429436
{
430437
__phantom: ::core::marker::PhantomData<
431-
fn(#ident #ty_generics) -> #ident #ty_generics
438+
fn(#struct_name #ty_generics) -> #struct_name #ty_generics
432439
>,
433440
}
434441

@@ -452,7 +459,7 @@ fn generate_the_pin_data(
452459

453460
// SAFETY: We have added the correct projection functions above to `__ThePinData` and
454461
// we also use the least restrictive generics possible.
455-
unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #ident #ty_generics
462+
unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #struct_name #ty_generics
456463
#whr
457464
{
458465
type PinData = __ThePinData #ty_generics;
@@ -466,7 +473,7 @@ fn generate_the_pin_data(
466473
unsafe impl #impl_generics ::pin_init::__internal::PinData for __ThePinData #ty_generics
467474
#whr
468475
{
469-
type Datee = #ident #ty_generics;
476+
type Datee = #struct_name #ty_generics;
470477
}
471478
}
472479
}

tests/ui/expand/many_generics.expanded.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ const _: () = {
8787
/// # Safety
8888
///
8989
/// - `slot` is a valid pointer to uninitialized memory.
90-
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
91-
/// to deallocate.
90+
/// - the caller does not touch `slot` when `Err` is returned, they are only
91+
/// permitted to deallocate.
9292
unsafe fn array<E>(
9393
self,
9494
slot: *mut [u8; 1024 * 1024],
@@ -108,8 +108,8 @@ const _: () = {
108108
/// # Safety
109109
///
110110
/// - `slot` is a valid pointer to uninitialized memory.
111-
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
112-
/// to deallocate.
111+
/// - the caller does not touch `slot` when `Err` is returned, they are only
112+
/// permitted to deallocate.
113113
unsafe fn r<E>(
114114
self,
115115
slot: *mut &'b mut [&'a mut T; SIZE],
@@ -129,8 +129,8 @@ const _: () = {
129129
/// # Safety
130130
///
131131
/// - `slot` is a valid pointer to uninitialized memory.
132-
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
133-
/// to deallocate.
132+
/// - the caller does not touch `slot` when `Err` is returned, they are only
133+
/// permitted to deallocate.
134134
/// - `slot` will not move until it is dropped, i.e. it will be pinned.
135135
unsafe fn _pin<E>(
136136
self,

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ const _: () = {
4949
/// # Safety
5050
///
5151
/// - `slot` is a valid pointer to uninitialized memory.
52-
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
53-
/// to deallocate.
52+
/// - the caller does not touch `slot` when `Err` is returned, they are only
53+
/// permitted to deallocate.
5454
unsafe fn array<E>(
5555
self,
5656
slot: *mut [u8; 1024 * 1024],
@@ -70,8 +70,8 @@ const _: () = {
7070
/// # Safety
7171
///
7272
/// - `slot` is a valid pointer to uninitialized memory.
73-
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
74-
/// to deallocate.
73+
/// - the caller does not touch `slot` when `Err` is returned, they are only
74+
/// permitted to deallocate.
7575
/// - `slot` will not move until it is dropped, i.e. it will be pinned.
7676
unsafe fn _pin<E>(
7777
self,

tests/ui/expand/pinned_drop.expanded.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ const _: () = {
4949
/// # Safety
5050
///
5151
/// - `slot` is a valid pointer to uninitialized memory.
52-
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
53-
/// to deallocate.
52+
/// - the caller does not touch `slot` when `Err` is returned, they are only
53+
/// permitted to deallocate.
5454
unsafe fn array<E>(
5555
self,
5656
slot: *mut [u8; 1024 * 1024],
@@ -70,8 +70,8 @@ const _: () = {
7070
/// # Safety
7171
///
7272
/// - `slot` is a valid pointer to uninitialized memory.
73-
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
74-
/// to deallocate.
73+
/// - the caller does not touch `slot` when `Err` is returned, they are only
74+
/// permitted to deallocate.
7575
/// - `slot` will not move until it is dropped, i.e. it will be pinned.
7676
unsafe fn _pin<E>(
7777
self,

0 commit comments

Comments
 (0)