1use proc_macro::TokenStream;
12use quote::quote;
13use syn::{ImplItemFn, ItemFn, TraitItemFn};
14
15#[proc_macro_attribute]
16pub fn no_alloc(args: TokenStream, item: TokenStream) -> TokenStream {
17 if !args.is_empty() {
18 let args = proc_macro2::TokenStream::from(args);
19 return syn::Error::new_spanned(args, "#[no_alloc] takes no arguments")
20 .to_compile_error()
21 .into();
22 }
23
24 let tokens = proc_macro2::TokenStream::from(item);
25 let (is_async, is_trait_declaration) =
26 if let Ok(function) = syn::parse2::<ItemFn>(tokens.clone()) {
27 (function.sig.asyncness.is_some(), false)
28 } else if let Ok(function) = syn::parse2::<ImplItemFn>(tokens.clone()) {
29 (function.sig.asyncness.is_some(), false)
30 } else if let Ok(function) = syn::parse2::<TraitItemFn>(tokens.clone()) {
31 (function.sig.asyncness.is_some(), function.default.is_none())
32 } else {
33 return syn::Error::new_spanned(
34 tokens,
35 "#[no_alloc] can only be applied to functions and methods",
36 )
37 .to_compile_error()
38 .into();
39 };
40
41 if is_async {
42 return syn::Error::new_spanned(tokens, "#[no_alloc] does not yet support async functions")
43 .to_compile_error()
44 .into();
45 }
46 if is_trait_declaration {
47 return syn::Error::new_spanned(
48 tokens,
49 "#[no_alloc] cannot be applied to a trait method without a body",
50 )
51 .to_compile_error()
52 .into();
53 }
54
55 quote! {
56 #[cfg_attr(no_alloc_check, no_alloc_tool::root)]
57 #tokens
58 }
59 .into()
60}