1use proc_macro2::Span;
2use syn::{ItemFn, ReturnType, Type, Visibility, parse, parse_macro_input, spanned::Spanned};
3
4use proc_macro::TokenStream;
5use quote::quote;
6
7#[proc_macro_attribute]
8pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
9 let f = parse_macro_input!(input as ItemFn);
10
11 if !f.sig.inputs.is_empty() {
13 return parse::Error::new(
14 f.sig.inputs.last().unwrap().span(),
15 "`#[entry]` function accepts no arguments",
16 )
17 .to_compile_error()
18 .into();
19 }
20
21 let valid_signature = f.sig.constness.is_none()
23 && f.sig.asyncness.is_none()
24 && f.vis == Visibility::Inherited
25 && f.sig.abi.is_none()
26 && f.sig.generics.params.is_empty()
27 && f.sig.generics.where_clause.is_none()
28 && f.sig.variadic.is_none()
29 && match f.sig.output {
30 ReturnType::Default => false,
31 ReturnType::Type(_, ref ty) => matches!(**ty, Type::Never(_)),
32 };
33
34 if !valid_signature {
35 return parse::Error::new(
36 f.span(),
37 "`#[entry]` function must have signature `[unsafe] fn() -> !`",
38 )
39 .to_compile_error()
40 .into();
41 }
42
43 if !args.is_empty() {
44 return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
45 .to_compile_error()
46 .into();
47 }
48
49 let attrs = f.attrs;
51 let unsafety = f.sig.unsafety;
52 let args = f.sig.inputs;
53 let stmts = f.block.stmts;
54
55 quote!(
56 #[allow(non_snake_case)]
57 #[unsafe(export_name = "__start_rust")]
58 #(#attrs)*
59 pub #unsafety fn __risc_v_rt__main(#args) -> ! {
60 #(#stmts)*
61 }
62 )
63 .into()
64}