Skip to content

Commit 83ac287

Browse files
nbdd0121ojeda
authored andcommitted
rust: pin-init: internal: move alignment check to make_field_check
Instead of having the reference creation serving dual-purpose as both for let bindings and alignment check, detangle them so that the alignment check is done explicitly in `make_field_check`. This is more robust against refactors that may change the way let bindings are created. Cc: stable@vger.kernel.org Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260427-pin-init-fix-v3-1-496a699674dd@garyguo.net [ Reworded for typo. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent ba6b328 commit 83ac287

1 file changed

Lines changed: 37 additions & 41 deletions

File tree

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

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,6 @@ fn init_fields(
249249
});
250250
// Again span for better diagnostics
251251
let write = quote_spanned!(ident.span()=> ::core::ptr::write);
252-
// NOTE: the field accessor ensures that the initialized field is properly aligned.
253-
// Unaligned fields will cause the compiler to emit E0793. We do not support
254-
// unaligned fields since `Init::__init` requires an aligned pointer; the call to
255-
// `ptr::write` below has the same requirement.
256252
let accessor = if pinned {
257253
let project_ident = format_ident!("__project_{ident}");
258254
quote! {
@@ -367,49 +363,49 @@ fn init_fields(
367363
}
368364
}
369365

370-
/// Generate the check for ensuring that every field has been initialized.
366+
/// Generate the check for ensuring that every field has been initialized and aligned.
371367
fn make_field_check(
372368
fields: &Punctuated<InitializerField, Token![,]>,
373369
init_kind: InitKind,
374370
path: &Path,
375371
) -> TokenStream {
376-
let field_attrs = fields
372+
let field_attrs: Vec<_> = fields
377373
.iter()
378-
.filter_map(|f| f.kind.ident().map(|_| &f.attrs));
379-
let field_name = fields.iter().filter_map(|f| f.kind.ident());
380-
match init_kind {
381-
InitKind::Normal => quote! {
382-
// We use unreachable code to ensure that all fields have been mentioned exactly once,
383-
// this struct initializer will still be type-checked and complain with a very natural
384-
// error message if a field is forgotten/mentioned more than once.
385-
#[allow(unreachable_code, clippy::diverging_sub_expression)]
386-
// SAFETY: this code is never executed.
387-
let _ = || unsafe {
388-
::core::ptr::write(slot, #path {
389-
#(
390-
#(#field_attrs)*
391-
#field_name: ::core::panic!(),
392-
)*
393-
})
394-
};
395-
},
396-
InitKind::Zeroing => quote! {
397-
// We use unreachable code to ensure that all fields have been mentioned at most once.
398-
// Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will
399-
// be zeroed. This struct initializer will still be type-checked and complain with a
400-
// very natural error message if a field is mentioned more than once, or doesn't exist.
401-
#[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)]
402-
// SAFETY: this code is never executed.
403-
let _ = || unsafe {
404-
::core::ptr::write(slot, #path {
405-
#(
406-
#(#field_attrs)*
407-
#field_name: ::core::panic!(),
408-
)*
409-
..::core::mem::zeroed()
410-
})
411-
};
412-
},
374+
.filter_map(|f| f.kind.ident().map(|_| &f.attrs))
375+
.collect();
376+
let field_name: Vec<_> = fields.iter().filter_map(|f| f.kind.ident()).collect();
377+
let zeroing_trailer = match init_kind {
378+
InitKind::Normal => None,
379+
InitKind::Zeroing => Some(quote! {
380+
..::core::mem::zeroed()
381+
}),
382+
};
383+
quote! {
384+
#[allow(unreachable_code, clippy::diverging_sub_expression)]
385+
// We use unreachable code to perform field checks. They're still checked by the compiler.
386+
// SAFETY: this code is never executed.
387+
let _ = || unsafe {
388+
// Create references to ensure that the initialized field is properly aligned.
389+
// Unaligned fields will cause the compiler to emit E0793. We do not support
390+
// unaligned fields since `Init::__init` requires an aligned pointer; the call to
391+
// `ptr::write` for value-initialization case has the same requirement.
392+
#(
393+
#(#field_attrs)*
394+
let _ = &(*slot).#field_name;
395+
)*
396+
397+
// If the zeroing trailer is not present, this checks that all fields have been
398+
// mentioned exactly once. If the zeroing trailer is present, all missing fields will be
399+
// zeroed, so this checks that all fields have been mentioned at most once. The use of
400+
// struct initializer will still generate very natural error messages for any misuse.
401+
::core::ptr::write(slot, #path {
402+
#(
403+
#(#field_attrs)*
404+
#field_name: ::core::panic!(),
405+
)*
406+
#zeroing_trailer
407+
})
408+
};
413409
}
414410
}
415411

0 commit comments

Comments
 (0)