Skip to content

Commit 6921137

Browse files
committed
rust: pin-init: internal: init: add support for attributes on initializer fields
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. Signed-off-by: Benno Lossin <lossin@kernel.org>
1 parent 7fe950a commit 6921137

1 file changed

Lines changed: 50 additions & 14 deletions

File tree

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

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ struct This {
2525
_in_token: Token![in],
2626
}
2727

28-
enum InitializerField {
28+
struct InitializerField {
29+
attrs: Vec<Attribute>,
30+
kind: InitializerKind,
31+
}
32+
33+
enum InitializerKind {
2934
Value {
3035
ident: Ident,
3136
value: Option<(Token![:], Expr)>,
@@ -42,7 +47,7 @@ enum InitializerField {
4247
},
4348
}
4449

45-
impl InitializerField {
50+
impl InitializerKind {
4651
fn ident(&self) -> Option<&Ident> {
4752
match self {
4853
Self::Value { ident, .. } | Self::Init { ident, .. } => Some(ident),
@@ -224,10 +229,11 @@ fn init_fields(
224229
slot: &Ident,
225230
) -> TokenStream {
226231
let mut guards = vec![];
232+
let mut guard_attrs = vec![];
227233
let mut res = TokenStream::new();
228-
for field in fields {
229-
let init = match field {
230-
InitializerField::Value { ident, value } => {
234+
for InitializerField { attrs, kind } in fields {
235+
let init = match kind {
236+
InitializerKind::Value { ident, value } => {
231237
let mut value_ident = ident.clone();
232238
let value_prep = value.as_ref().map(|value| &value.1).map(|value| {
233239
// Setting the span of `value_ident` to `value`'s span improves error messages
@@ -250,21 +256,24 @@ fn init_fields(
250256
}
251257
};
252258
quote! {
259+
#(#attrs)*
253260
{
254261
#value_prep
255262
// SAFETY: TODO
256263
unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
257264
}
265+
#(#attrs)*
258266
#[allow(unused_variables)]
259267
let #ident = #accessor;
260268
}
261269
}
262-
InitializerField::Init { ident, value, .. } => {
270+
InitializerKind::Init { ident, value, .. } => {
263271
// Again span for better diagnostics
264272
let init = format_ident!("init", span = value.span());
265273
if pinned {
266274
let project_ident = format_ident!("__project_{ident}");
267275
quote! {
276+
#(#attrs)*
268277
{
269278
let #init = #value;
270279
// SAFETY:
@@ -274,12 +283,14 @@ fn init_fields(
274283
// for `#ident`.
275284
unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? };
276285
}
286+
#(#attrs)*
277287
// SAFETY: TODO
278288
#[allow(unused_variables)]
279289
let #ident = unsafe { #data.#project_ident(&mut (*#slot).#ident) };
280290
}
281291
} else {
282292
quote! {
293+
#(#attrs)*
283294
{
284295
let #init = #value;
285296
// SAFETY: `slot` is valid, because we are inside of an initializer
@@ -291,20 +302,25 @@ fn init_fields(
291302
)?
292303
};
293304
}
305+
#(#attrs)*
294306
// SAFETY: TODO
295307
#[allow(unused_variables)]
296308
let #ident = unsafe { &mut (*#slot).#ident };
297309
}
298310
}
299311
}
300-
InitializerField::Code { block: value, .. } => quote!(#[allow(unused_braces)] #value),
312+
InitializerKind::Code { block: value, .. } => quote! {
313+
#(#attrs)*
314+
#[allow(unused_braces)]
315+
#value
316+
},
301317
};
302318
res.extend(init);
303-
if let Some(ident) = field.ident() {
319+
if let Some(ident) = kind.ident() {
304320
// `mixed_site` ensures that the guard is not accessible to the user-controlled code.
305321
let guard = format_ident!("__{ident}_guard", span = Span::mixed_site());
306-
guards.push(guard.clone());
307322
res.extend(quote! {
323+
#(#attrs)*
308324
// Create the drop guard:
309325
//
310326
// We rely on macro hygiene to make it impossible for users to access this local
@@ -316,13 +332,18 @@ fn init_fields(
316332
)
317333
};
318334
});
335+
guards.push(guard);
336+
guard_attrs.push(attrs);
319337
}
320338
}
321339
quote! {
322340
#res
323341
// If execution reaches this point, all fields have been initialized. Therefore we can now
324342
// dismiss the guards by forgetting them.
325-
#(::core::mem::forget(#guards);)*
343+
#(
344+
#(#guard_attrs)*
345+
::core::mem::forget(#guards);
346+
)*
326347
}
327348
}
328349

@@ -332,7 +353,10 @@ fn make_field_check(
332353
init_kind: InitKind,
333354
path: &Path,
334355
) -> TokenStream {
335-
let fields = fields.iter().filter_map(|f| f.ident());
356+
let field_attrs = fields
357+
.iter()
358+
.filter_map(|f| f.kind.ident().map(|_| &f.attrs));
359+
let field_name = fields.iter().filter_map(|f| f.kind.ident());
336360
match init_kind {
337361
InitKind::Normal => quote! {
338362
// We use unreachable code to ensure that all fields have been mentioned exactly once,
@@ -343,7 +367,8 @@ fn make_field_check(
343367
let _ = || unsafe {
344368
::core::ptr::write(slot, #path {
345369
#(
346-
#fields: ::core::panic!(),
370+
#(#field_attrs)*
371+
#field_name: ::core::panic!(),
347372
)*
348373
})
349374
};
@@ -361,7 +386,8 @@ fn make_field_check(
361386
zeroed = ::core::mem::zeroed();
362387
::core::ptr::write(slot, #path {
363388
#(
364-
#fields: ::core::panic!(),
389+
#(#field_attrs)*
390+
#field_name: ::core::panic!(),
365391
)*
366392
..zeroed
367393
})
@@ -382,7 +408,7 @@ impl Parse for Initializer {
382408
let lh = content.lookahead1();
383409
if lh.peek(End) || lh.peek(Token![..]) {
384410
break;
385-
} else if lh.peek(Ident) || lh.peek(Token![_]) {
411+
} else if lh.peek(Ident) || lh.peek(Token![_]) || lh.peek(Token![#]) {
386412
fields.push_value(content.parse()?);
387413
let lh = content.lookahead1();
388414
if lh.peek(End) {
@@ -448,6 +474,16 @@ impl Parse for This {
448474
}
449475

450476
impl Parse for InitializerField {
477+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
478+
let attrs = input.call(Attribute::parse_outer)?;
479+
Ok(Self {
480+
attrs,
481+
kind: input.parse()?,
482+
})
483+
}
484+
}
485+
486+
impl Parse for InitializerKind {
451487
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
452488
let lh = input.lookahead1();
453489
if lh.peek(Token![_]) {

0 commit comments

Comments
 (0)