linker_set_proc/
lib.rs

1#![warn(missing_docs)]
2
3//! Procedural macro crate to accompany the linker-set crate.
4
5use proc_macro::TokenStream;
6use quote::{format_ident, quote};
7use syn::parse::*;
8use syn::punctuated::*;
9use syn::*;
10
11struct Name(String);
12
13impl Parse for Name {
14    fn parse(input: ParseStream) -> Result<Self> {
15        let name = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
16        assert!(name.len() == 1, "set_entry macro takes one argument");
17        Ok(Self(name[0].to_string()))
18    }
19}
20
21/// Attribute macro that puts an item into a linker set.
22#[proc_macro_attribute]
23pub fn set_entry(meta: TokenStream, decl: TokenStream) -> TokenStream {
24    let meta = parse_macro_input!(meta as Name);
25    let decl = parse_macro_input!(decl as ItemStatic);
26
27    let set = meta.0;
28    let set_section = format!("set_{}", set);
29    let set_ident = format_ident!("{}", set);
30    let start_set = format_ident!("__start_set_{}", set);
31    let fn_name = format_ident!(
32        "__set_{}_typecheck_{}",
33        set,
34        decl.ident.to_string().to_lowercase()
35    );
36    let expr = decl.expr.clone();
37
38    let g = quote! {
39        #[unsafe(link_section = #set_section)]
40        #[used]
41        #decl
42
43        #[cfg(any(debug_assertions, test))]
44        #[allow(unused)]
45        fn #fn_name() -> bool {
46            // for typechecking
47            #[allow(clippy::fn_address_comparisons)]
48            unsafe { #set_ident::#start_set == #expr }
49        }
50    };
51    TokenStream::from(g)
52}