mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
d0fdc39612
The `PinnedDrop` trait that facilitates destruction of pinned types. It has to be implemented via the `#[pinned_drop]` macro, since the `drop` function should not be called by normal code, only by other destructors. It also only works on structs that are annotated with `#[pin_data(PinnedDrop)]`. Co-developed-by: Gary Guo <gary@garyguo.net> Signed-off-by: Gary Guo <gary@garyguo.net> Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com> Link: https://lore.kernel.org/r/20230408122429.1103522-10-y86-dev@protonmail.com Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
49 lines
1.8 KiB
Rust
49 lines
1.8 KiB
Rust
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
|
|
use proc_macro::{TokenStream, TokenTree};
|
|
|
|
pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream {
|
|
let mut toks = input.into_iter().collect::<Vec<_>>();
|
|
assert!(!toks.is_empty());
|
|
// Ensure that we have an `impl` item.
|
|
assert!(matches!(&toks[0], TokenTree::Ident(i) if i.to_string() == "impl"));
|
|
// Ensure that we are implementing `PinnedDrop`.
|
|
let mut nesting: usize = 0;
|
|
let mut pinned_drop_idx = None;
|
|
for (i, tt) in toks.iter().enumerate() {
|
|
match tt {
|
|
TokenTree::Punct(p) if p.as_char() == '<' => {
|
|
nesting += 1;
|
|
}
|
|
TokenTree::Punct(p) if p.as_char() == '>' => {
|
|
nesting = nesting.checked_sub(1).unwrap();
|
|
continue;
|
|
}
|
|
_ => {}
|
|
}
|
|
if i >= 1 && nesting == 0 {
|
|
// Found the end of the generics, this should be `PinnedDrop`.
|
|
assert!(
|
|
matches!(tt, TokenTree::Ident(i) if i.to_string() == "PinnedDrop"),
|
|
"expected 'PinnedDrop', found: '{:?}'",
|
|
tt
|
|
);
|
|
pinned_drop_idx = Some(i);
|
|
break;
|
|
}
|
|
}
|
|
let idx = pinned_drop_idx
|
|
.unwrap_or_else(|| panic!("Expected an `impl` block implementing `PinnedDrop`."));
|
|
// Fully qualify the `PinnedDrop`, as to avoid any tampering.
|
|
toks.splice(idx..idx, quote!(::kernel::init::));
|
|
// Take the `{}` body and call the declarative macro.
|
|
if let Some(TokenTree::Group(last)) = toks.pop() {
|
|
let last = last.stream();
|
|
quote!(::kernel::__pinned_drop! {
|
|
@impl_sig(#(#toks)*),
|
|
@impl_body(#last),
|
|
})
|
|
} else {
|
|
TokenStream::from_iter(toks)
|
|
}
|
|
}
|