#![allow(unreachable_code)]
#![no_std]
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, FnArg, ItemFn, ReturnType, Type};
#[proc_macro_attribute]
pub fn define_panic(_attr: TokenStream, input: TokenStream) -> TokenStream {
let input_fn = parse_macro_input!(input as ItemFn);
let vis = &input_fn.vis;
let attrs = &input_fn.attrs;
let block = &input_fn.block;
let inputs = &input_fn.sig.inputs;
let output = &input_fn.sig.output;
if let FnArg::Typed(arg) = inputs.first().unwrap() {
if let Type::Reference(reference) = &*arg.ty {
if let Type::Path(type_path) = &*reference.elem {
if let Some(ident) = type_path.path.get_ident() {
if ident != "PanicInfo" {
return syn::Error::new_spanned(
&input_fn.sig,
"The parameter of the panic handler function must be of type `&PanicInfo`.",
)
.to_compile_error()
.into();
}
}
}
} else {
return syn::Error::new_spanned(
&input_fn.sig,
"The parameter must be a reference of type `PanicInfo` ",
)
.to_compile_error()
.into();
}
} else {
return syn::Error::new_spanned(
&input_fn.sig,
"The parameter of type `&PanicInfo` is not found.",
)
.to_compile_error()
.into();
}
if let ReturnType::Type(_, ty) = output {
match ty.as_ref() {
Type::Never(_) => (),
_ => {
return syn::Error::new_spanned(
output,
"The panic handler function must diverge (return `!`).",
)
.to_compile_error()
.into();
},
}
}
let new_fn = quote! {
#(#attrs)*
#vis
#[panic_handler]
fn panic(_: &::core::panic::PanicInfo) -> ! {
unsafe {
#block
}
}
};
new_fn.into()
}