@@ -5,7 +5,7 @@ extern crate proc_macro;
55use proc_macro:: TokenStream ;
66
77use proc_macro2:: { TokenStream as TokenStream2 , TokenTree } ;
8- use quote:: { quote, ToTokens , TokenStreamExt } ;
8+ use quote:: { quote, quote_spanned , ToTokens , TokenStreamExt } ;
99use syn:: {
1010 parse_macro_input, parse_quote, spanned:: Spanned , Error , Fields , FnArg , Ident , ItemFn ,
1111 ItemStruct , LitStr , Pat , Visibility ,
@@ -302,14 +302,42 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
302302 ) ;
303303 }
304304
305- let ident = & f. sig . ident ;
305+ let fn_ident = & f. sig . ident ;
306+ // Get an iterator of the function inputs types. This is needed instead of
307+ // directly using `sig.inputs` because patterns you can use in fn items like
308+ // `mut <arg>` aren't valid in fn pointers.
309+ let fn_inputs = f. sig . inputs . iter ( ) . map ( |arg| match arg {
310+ FnArg :: Receiver ( arg) => quote ! ( #arg) ,
311+ FnArg :: Typed ( arg) => {
312+ let ty = & arg. ty ;
313+ quote ! ( #ty)
314+ }
315+ } ) ;
316+ let fn_output = & f. sig . output ;
317+ let signature_span = f. sig . span ( ) ;
318+
319+ let fn_type_check = quote_spanned ! { signature_span=>
320+ // Cast from the function type to a function pointer with the same
321+ // signature first, then try to assign that to an unnamed constant with
322+ // the desired function pointer type.
323+ //
324+ // The cast is used to avoid an "expected fn pointer, found fn item"
325+ // error if the signature is wrong, since that's not what we are
326+ // interested in here. Instead we want to tell the user what
327+ // specifically in the function signature is incorrect.
328+ const _:
329+ // The expected fn pointer type.
330+ #unsafety extern "efiapi" fn ( :: uefi:: Handle , :: uefi:: table:: SystemTable <:: uefi:: table:: Boot >) -> :: uefi:: Status =
331+ // Cast from a fn item to a function pointer.
332+ #fn_ident as #unsafety extern "efiapi" fn ( #( #fn_inputs) , * ) #fn_output;
333+ } ;
306334
307335 let result = quote ! {
336+ #fn_type_check
337+
308338 #[ export_name = "efi_main" ]
309339 #unsafety extern "efiapi" #f
310340
311- // typecheck the function pointer
312- const _: #unsafety extern "efiapi" fn ( :: uefi:: Handle , :: uefi:: table:: SystemTable <:: uefi:: table:: Boot >) -> :: uefi:: Status = #ident;
313341 } ;
314342 result. into ( )
315343}
0 commit comments