mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-18 18:11:26 -04:00
Rewrite the two derive macros for `Zeroable` using `syn`. One positive
side effect of this change is that tuple structs are now supported by
them. Additionally, syntax errors and the error emitted when trying to
use one of the derive macros on an `enum` are improved. Otherwise no
functional changes intended.
For example:
#[derive(Zeroable)]
enum Num {
A(u32),
B(i32),
}
Produced this error before this commit:
error: no rules expected keyword `enum`
--> tests/ui/compile-fail/zeroable/enum.rs:5:1
|
5 | enum Num {
| ^^^^ no rules expected this token in macro call
|
note: while trying to match keyword `struct`
--> src/macros.rs
|
| $vis:vis struct $name:ident
| ^^^^^^
Now the error is:
error: cannot derive `Zeroable` for an enum
--> tests/ui/compile-fail/zeroable/enum.rs:5:1
|
5 | enum Num {
| ^^^^
error: cannot derive `Zeroable` for an enum
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Benno Lossin <lossin@kernel.org>
79 lines
2.7 KiB
Rust
79 lines
2.7 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
use proc_macro2::TokenStream;
|
|
use quote::quote;
|
|
use syn::{parse_quote, Data, DeriveInput, Field, Fields};
|
|
|
|
use crate::{diagnostics::ErrorGuaranteed, DiagCtxt};
|
|
|
|
pub(crate) fn derive(
|
|
input: DeriveInput,
|
|
dcx: &mut DiagCtxt,
|
|
) -> Result<TokenStream, ErrorGuaranteed> {
|
|
let fields = match input.data {
|
|
Data::Struct(data_struct) => data_struct.fields,
|
|
Data::Union(data_union) => Fields::Named(data_union.fields),
|
|
Data::Enum(data_enum) => {
|
|
return Err(dcx.error(data_enum.enum_token, "cannot derive `Zeroable` for an enum"));
|
|
}
|
|
};
|
|
let name = input.ident;
|
|
let mut generics = input.generics;
|
|
for param in generics.type_params_mut() {
|
|
param.bounds.insert(0, parse_quote!(::pin_init::Zeroable));
|
|
}
|
|
let (impl_gen, ty_gen, whr) = generics.split_for_impl();
|
|
let field_type = fields.iter().map(|field| &field.ty);
|
|
Ok(quote! {
|
|
// SAFETY: Every field type implements `Zeroable` and padding bytes may be zero.
|
|
#[automatically_derived]
|
|
unsafe impl #impl_gen ::pin_init::Zeroable for #name #ty_gen
|
|
#whr
|
|
{}
|
|
const _: () = {
|
|
fn assert_zeroable<T: ?::core::marker::Sized + ::pin_init::Zeroable>() {}
|
|
fn ensure_zeroable #impl_gen ()
|
|
#whr
|
|
{
|
|
#(
|
|
assert_zeroable::<#field_type>();
|
|
)*
|
|
}
|
|
};
|
|
})
|
|
}
|
|
|
|
pub(crate) fn maybe_derive(
|
|
input: DeriveInput,
|
|
dcx: &mut DiagCtxt,
|
|
) -> Result<TokenStream, ErrorGuaranteed> {
|
|
let fields = match input.data {
|
|
Data::Struct(data_struct) => data_struct.fields,
|
|
Data::Union(data_union) => Fields::Named(data_union.fields),
|
|
Data::Enum(data_enum) => {
|
|
return Err(dcx.error(data_enum.enum_token, "cannot derive `Zeroable` for an enum"));
|
|
}
|
|
};
|
|
let name = input.ident;
|
|
let mut generics = input.generics;
|
|
for param in generics.type_params_mut() {
|
|
param.bounds.insert(0, parse_quote!(::pin_init::Zeroable));
|
|
}
|
|
for Field { ty, .. } in fields {
|
|
generics
|
|
.make_where_clause()
|
|
.predicates
|
|
// the `for<'__dummy>` HRTB makes this not error without the `trivial_bounds`
|
|
// feature <https://github.com/rust-lang/rust/issues/48214#issuecomment-2557829956>.
|
|
.push(parse_quote!(#ty: for<'__dummy> ::pin_init::Zeroable));
|
|
}
|
|
let (impl_gen, ty_gen, whr) = generics.split_for_impl();
|
|
Ok(quote! {
|
|
// SAFETY: Every field type implements `Zeroable` and padding bytes may be zero.
|
|
#[automatically_derived]
|
|
unsafe impl #impl_gen ::pin_init::Zeroable for #name #ty_gen
|
|
#whr
|
|
{}
|
|
})
|
|
}
|