@@ -8,8 +8,8 @@ use proc_macro2::TokenStream as TokenStream2;
8
8
use quote:: { quote, quote_spanned, TokenStreamExt } ;
9
9
use syn:: spanned:: Spanned ;
10
10
use 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 ,
13
13
} ;
14
14
15
15
macro_rules! err {
@@ -93,49 +93,19 @@ pub fn unsafe_protocol(args: TokenStream, input: TokenStream) -> TokenStream {
93
93
. into ( )
94
94
}
95
95
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 method'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
-
121
96
/// Custom attribute for a UEFI executable entry point.
122
97
///
123
98
/// This attribute modifies a function to mark it as the entry point for
124
99
/// a UEFI executable. The function:
125
100
/// * Must return [`Status`].
126
- /// * Must have either zero parameters or two: [`Handle`] and [`SystemTable<Boot>`] .
101
+ /// * Must have zero parameters.
127
102
/// * Can optionally be `unsafe`.
128
103
///
129
- /// Due to internal implementation details the parameters must both be
130
- /// named, so `arg` or `_arg` are allowed, but not `_`.
131
- ///
132
104
/// The global system table pointer and global image handle will be set
133
105
/// automatically.
134
106
///
135
107
/// # Examples
136
108
///
137
- /// With no arguments:
138
- ///
139
109
/// ```no_run
140
110
/// #![no_main]
141
111
///
@@ -147,23 +117,7 @@ fn get_function_arg_name(f: &ItemFn, arg_index: usize, errors: &mut TokenStream2
147
117
/// }
148
118
/// ```
149
119
///
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
165
120
/// [`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
167
121
#[ proc_macro_attribute]
168
122
pub fn entry ( args : TokenStream , input : TokenStream ) -> TokenStream {
169
123
// This code is inspired by the approach in this embedded Rust crate:
@@ -181,92 +135,64 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
181
135
let mut f = parse_macro_input ! ( input as ItemFn ) ;
182
136
183
137
if let Some ( ref abi) = f. sig . abi {
184
- errors. append_all ( err ! ( abi, "Entry method must have no ABI modifier" ) ) ;
138
+ errors. append_all ( err ! ( abi, "Entry function must have no ABI modifier" ) ) ;
185
139
}
186
140
if let Some ( asyncness) = f. sig . asyncness {
187
- errors. append_all ( err ! ( asyncness, "Entry method should not be async" ) ) ;
141
+ errors. append_all ( err ! ( asyncness, "Entry function should not be async" ) ) ;
188
142
}
189
143
if let Some ( constness) = f. sig . constness {
190
- errors. append_all ( err ! ( constness, "Entry method should not be const" ) ) ;
144
+ errors. append_all ( err ! ( constness, "Entry function should not be const" ) ) ;
191
145
}
192
146
if !f. sig . generics . params . is_empty ( ) {
193
147
errors. append_all ( err ! (
194
148
f. sig. generics. params,
195
- "Entry method should not be generic"
149
+ "Entry function should not be generic"
196
150
) ) ;
197
151
}
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" ) ) ;
210
154
}
211
155
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.
216
157
if !errors. is_empty ( ) {
217
158
return errors. into ( ) ;
218
159
}
219
160
220
- f . sig . abi = Some ( syn :: parse2 ( quote_spanned ! ( signature_span=> extern "efiapi" ) ) . unwrap ( ) ) ;
161
+ let signature_span = f . sig . span ( ) ;
221
162
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.
225
188
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
- }
247
189
190
+ let unsafety = & f. sig . unsafety ;
248
191
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
- } ) ;
259
192
let fn_output = & f. sig . output ;
260
193
261
194
// 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) ;
270
196
271
197
let fn_type_check = quote_spanned ! { signature_span=>
272
198
// Cast from the function type to a function pointer with the same
@@ -281,7 +207,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
281
207
// The expected fn pointer type.
282
208
#unsafety extern "efiapi" fn ( #expected_args) -> :: uefi:: Status =
283
209
// 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;
285
211
} ;
286
212
287
213
let result = quote ! {
0 commit comments