@@ -8,8 +8,8 @@ use proc_macro2::TokenStream as TokenStream2;
88use quote:: { quote, quote_spanned, TokenStreamExt } ;
99use syn:: spanned:: Spanned ;
1010use syn:: {
11- parse_macro_input, parse_quote, parse_quote_spanned, Error , Expr , ExprLit , ExprPath , FnArg ,
12- Ident , ItemFn , ItemStruct , Lit , Pat , Visibility ,
11+ parse_macro_input, parse_quote, parse_quote_spanned, Error , Expr , ExprLit , ExprPath , ItemFn ,
12+ ItemStruct , Lit , Visibility ,
1313} ;
1414
1515macro_rules! err {
@@ -93,49 +93,19 @@ pub fn unsafe_protocol(args: TokenStream, input: TokenStream) -> TokenStream {
9393 . into ( )
9494}
9595
96- /// Get the name of a function's argument at `arg_index`.
97- fn get_function_arg_name ( f : & ItemFn , arg_index : usize , errors : & mut TokenStream2 ) -> Option < Ident > {
98- if let Some ( FnArg :: Typed ( arg) ) = f. sig . inputs . iter ( ) . nth ( arg_index) {
99- if let Pat :: Ident ( pat_ident) = & * arg. pat {
100- // The argument has a valid name such as `handle` or `_handle`.
101- Some ( pat_ident. ident . clone ( ) )
102- } else {
103- // The argument is unnamed, i.e. `_`.
104- errors. append_all ( err ! (
105- arg. pat. span( ) ,
106- "Entry function's arguments must be named"
107- ) ) ;
108- None
109- }
110- } else {
111- // Either there are too few arguments, or it's the wrong kind of
112- // argument (e.g. `self`).
113- //
114- // Don't append an error in this case. The error will be caught
115- // by the typecheck later on, which will give a better error
116- // message.
117- None
118- }
119- }
120-
12196/// Custom attribute for a UEFI executable entry point.
12297///
12398/// This attribute modifies a function to mark it as the entry point for
12499/// a UEFI executable. The function:
125100/// * Must return [`Status`].
126- /// * Must have either zero parameters or two: [`Handle`] and [`SystemTable<Boot>`] .
101+ /// * Must have zero parameters.
127102/// * Can optionally be `unsafe`.
128103///
129- /// Due to internal implementation details the parameters must both be
130- /// named, so `arg` or `_arg` are allowed, but not `_`.
131- ///
132104/// The global system table pointer and global image handle will be set
133105/// automatically.
134106///
135107/// # Examples
136108///
137- /// With no arguments:
138- ///
139109/// ```no_run
140110/// #![no_main]
141111///
@@ -147,23 +117,7 @@ fn get_function_arg_name(f: &ItemFn, arg_index: usize, errors: &mut TokenStream2
147117/// }
148118/// ```
149119///
150- /// With two arguments:
151- ///
152- /// ```no_run
153- /// #![no_main]
154- ///
155- /// use uefi::prelude::*;
156- ///
157- /// #[entry]
158- /// fn main(image: Handle, st: SystemTable<Boot>) -> Status {
159- /// Status::SUCCESS
160- /// }
161- /// ```
162- ///
163- /// [`Handle`]: https://docs.rs/uefi/latest/uefi/data_types/struct.Handle.html
164- /// [`SystemTable<Boot>`]: https://docs.rs/uefi/latest/uefi/table/struct.SystemTable.html
165120/// [`Status`]: https://docs.rs/uefi/latest/uefi/struct.Status.html
166- /// [`BootServices::set_image_handle`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.set_image_handle
167121#[ proc_macro_attribute]
168122pub fn entry ( args : TokenStream , input : TokenStream ) -> TokenStream {
169123 // This code is inspired by the approach in this embedded Rust crate:
@@ -195,78 +149,50 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
195149 "Entry function should not be generic"
196150 ) ) ;
197151 }
198-
199- let signature_span = f. sig . span ( ) ;
200-
201- // If the user doesn't specify any arguments to the entry function, fill in
202- // the image handle and system table arguments automatically.
203- let generated_args = f. sig . inputs . is_empty ( ) ;
204- if generated_args {
205- f. sig . inputs = parse_quote_spanned ! (
206- signature_span=>
207- internal_image_handle: :: uefi:: Handle ,
208- internal_system_table: * const :: core:: ffi:: c_void,
209- ) ;
152+ if !f. sig . inputs . is_empty ( ) {
153+ errors. append_all ( err ! ( f. sig. inputs, "Entry function must have no arguments" ) ) ;
210154 }
211155
212- let image_handle_ident = get_function_arg_name ( & f, 0 , & mut errors) ;
213- let system_table_ident = get_function_arg_name ( & f, 1 , & mut errors) ;
214-
215- // show most errors at once instead of one by one
156+ // Show most errors all at once instead of one by one.
216157 if !errors. is_empty ( ) {
217158 return errors. into ( ) ;
218159 }
219160
220- f . sig . abi = Some ( syn :: parse2 ( quote_spanned ! ( signature_span=> extern "efiapi" ) ) . unwrap ( ) ) ;
161+ let signature_span = f . sig . span ( ) ;
221162
222- // allow the entry function to be unsafe (by moving the keyword around so that it actually works)
223- let unsafety = & f. sig . unsafety ;
224- // strip any visibility modifiers
163+ // Fill in the image handle and system table arguments automatically.
164+ let image_handle_ident = quote ! ( internal_image_handle) ;
165+ let system_table_ident = quote ! ( internal_system_table) ;
166+ f. sig . inputs = parse_quote_spanned ! (
167+ signature_span=>
168+ #image_handle_ident: :: uefi:: Handle ,
169+ #system_table_ident: * const :: core:: ffi:: c_void,
170+ ) ;
171+
172+ // Insert code at the beginning of the entry function to set the global
173+ // image handle and system table pointer.
174+ f. block . stmts . insert (
175+ 0 ,
176+ parse_quote ! {
177+ unsafe {
178+ :: uefi:: boot:: set_image_handle( #image_handle_ident) ;
179+ :: uefi:: table:: set_system_table( #system_table_ident. cast( ) ) ;
180+ }
181+ } ,
182+ ) ;
183+
184+ // Set the required ABI.
185+ f. sig . abi = Some ( parse_quote_spanned ! ( signature_span=> extern "efiapi" ) ) ;
186+
187+ // Strip any visibility modifiers.
225188 f. vis = Visibility :: Inherited ;
226- // Set the global image handle. If `image_handle_ident` is `None`
227- // then the typecheck is going to fail anyway.
228- if let Some ( image_handle_ident) = image_handle_ident {
229- // Convert the system table arg (either `SystemTable<Boot>` or
230- // `*const c_void`) to a pointer of the correct type.
231- let system_table_ptr = if generated_args {
232- quote ! ( #system_table_ident. cast( ) )
233- } else {
234- quote ! ( #system_table_ident. as_ptr( ) . cast( ) )
235- } ;
236-
237- f. block . stmts . insert (
238- 0 ,
239- parse_quote ! {
240- unsafe {
241- :: uefi:: boot:: set_image_handle( #image_handle_ident) ;
242- :: uefi:: table:: set_system_table( #system_table_ptr) ;
243- }
244- } ,
245- ) ;
246- }
247189
190+ let unsafety = & f. sig . unsafety ;
248191 let fn_ident = & f. sig . ident ;
249- // Get an iterator of the function inputs types. This is needed instead of
250- // directly using `sig.inputs` because patterns you can use in fn items like
251- // `mut <arg>` aren't valid in fn pointers.
252- let fn_inputs = f. sig . inputs . iter ( ) . map ( |arg| match arg {
253- FnArg :: Receiver ( arg) => quote ! ( #arg) ,
254- FnArg :: Typed ( arg) => {
255- let ty = & arg. ty ;
256- quote ! ( #ty)
257- }
258- } ) ;
259192 let fn_output = & f. sig . output ;
260193
261194 // Get the expected argument types for the main function.
262- let expected_args = if generated_args {
263- quote ! ( :: uefi:: Handle , * const core:: ffi:: c_void)
264- } else {
265- quote ! (
266- :: uefi:: Handle ,
267- :: uefi:: table:: SystemTable <:: uefi:: table:: Boot >
268- )
269- } ;
195+ let expected_args = quote ! ( :: uefi:: Handle , * const core:: ffi:: c_void) ;
270196
271197 let fn_type_check = quote_spanned ! { signature_span=>
272198 // Cast from the function type to a function pointer with the same
@@ -281,7 +207,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
281207 // The expected fn pointer type.
282208 #unsafety extern "efiapi" fn ( #expected_args) -> :: uefi:: Status =
283209 // Cast from a fn item to a function pointer.
284- #fn_ident as #unsafety extern "efiapi" fn ( #( #fn_inputs ) , * ) #fn_output;
210+ #fn_ident as #unsafety extern "efiapi" fn ( #expected_args ) #fn_output;
285211 } ;
286212
287213 let result = quote ! {
0 commit comments