mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 18:20:25 +02:00 
			
		
		
		
	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)
 | 
						|
    }
 | 
						|
}
 |