forked from mirrors/linux
		
	 d0fdc39612
			
		
	
	
		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)
 | |
|     }
 | |
| }
 |