@@ -14,17 +14,15 @@ pub enum Fn {
1414impl Fn {
1515 /// Convenience method to generate the token stream for the `post_init` attribute
1616 pub fn post_init ( args : TokenStream , input : TokenStream ) -> TokenStream {
17- match Self :: PostInit . check_args_empty ( args) {
18- Ok ( _) => Self :: PostInit . quote_fn ( input) ,
19- Err ( e) => e. to_compile_error ( ) . into ( ) ,
20- }
17+ let errors = Self :: PostInit . check_args_empty ( args) . err ( ) ;
18+ Self :: PostInit . quote_fn ( input, errors)
2119 }
2220
2321 /// Generate the token stream for the function with the given attribute
24- fn quote_fn ( & self , item : TokenStream ) -> TokenStream {
22+ fn quote_fn ( & self , item : TokenStream , errors : Option < Error > ) -> TokenStream {
2523 let mut func = parse_macro_input ! ( item as ItemFn ) ;
2624
27- if let Err ( e) = self . check_fn ( & func) {
25+ if let Err ( e) = self . check_fn ( & func, errors ) {
2826 return e. to_compile_error ( ) . into ( ) ;
2927 }
3028
@@ -47,67 +45,80 @@ impl Fn {
4745 }
4846
4947 /// Check if the function signature is valid for the given attribute
50- fn check_fn ( & self , f : & ItemFn ) -> Result < ( ) > {
48+ fn check_fn ( & self , f : & ItemFn , mut errors : Option < Error > ) -> Result < ( ) > {
5149 // First, check that the function is private
5250 if f. vis != Visibility :: Inherited {
53- let attr = self . attr_name ( ) ;
54- return Err ( Error :: new (
55- f. vis . span ( ) ,
56- format ! ( "`#[{attr}]` function must be private" ) ,
57- ) ) ;
51+ combine_err (
52+ & mut errors,
53+ Error :: new ( f. vis . span ( ) , "function must be private" ) ,
54+ ) ;
5855 }
56+
5957 let sig = & f. sig ;
58+ // Next, check common aspects of the signature individually to accumulate errors
59+ if let Some ( constness) = sig. constness {
60+ combine_err (
61+ & mut errors,
62+ Error :: new ( constness. span ( ) , "function must not be const" ) ,
63+ ) ;
64+ }
65+ if let Some ( asyncness) = sig. asyncness {
66+ combine_err (
67+ & mut errors,
68+ Error :: new ( asyncness. span ( ) , "function must not be async" ) ,
69+ ) ;
70+ }
71+ if let Some ( abi) = & sig. abi {
72+ combine_err (
73+ & mut errors,
74+ Error :: new ( abi. span ( ) , "ABI must not be specified" ) ,
75+ ) ;
76+ }
77+ if !sig. generics . params . is_empty ( ) {
78+ // Use to_token_stream to get a span covering the entire <...> block
79+ let span = sig. generics . params . span ( ) ;
80+ combine_err ( & mut errors, Error :: new ( span, "generics are not allowed" ) ) ;
81+ }
6082
61- // Next, check common aspects of the signature (constness, asyncness, generics, etc.)
62- let valid_signature = sig. constness . is_none ( )
63- && sig. asyncness . is_none ( )
64- && sig. abi . is_none ( )
65- && sig. generics . params . is_empty ( )
66- && sig. generics . where_clause . is_none ( )
67- && sig. variadic . is_none ( ) ;
68- if !valid_signature {
69- let attr = self . attr_name ( ) ;
70- let expected = self . expected_signature ( ) ;
71- return Err ( Error :: new (
72- sig. span ( ) ,
73- format ! ( "`#[{attr}]` function signature must be `{expected}`" ) ,
74- ) ) ;
75- }
76-
77- // Finally, check that input arguments and output type are valid
78- self . check_inputs ( & sig. inputs ) ?;
79- self . check_output ( & sig. output )
80- }
83+ // Check input parameters...
84+ self . check_inputs ( & sig. inputs , & mut errors) ;
85+ // ... and variadic arguments (they are at the end of input parameters)
86+ if let Some ( variadic) = & sig. variadic {
87+ combine_err (
88+ & mut errors,
89+ Error :: new ( variadic. span ( ) , "variadic arguments are not allowed" ) ,
90+ ) ;
91+ }
8192
82- /// Utility method for printing attribute name in error messages
83- const fn attr_name ( & self ) -> & ' static str {
84- // Use this match to specify attribute names for different functions in the future
85- match self {
86- Self :: PostInit => "post_init" ,
93+ // Check output type...
94+ self . check_output ( & sig. output , & mut errors) ;
95+ // ... and where clause (they are after output type)
96+ if let Some ( where_clause) = & sig. generics . where_clause {
97+ combine_err (
98+ & mut errors,
99+ Error :: new ( where_clause. span ( ) , "where clause is not allowed" ) ,
100+ ) ;
87101 }
88- }
89102
90- /// Utility method for printing expected function signature in error messages
91- const fn expected_signature ( & self ) -> & ' static str {
92- // Use this match to specify expected signatures for different functions in the future
93- match self {
94- Self :: PostInit => "[unsafe] fn([usize])" ,
103+ match errors {
104+ Some ( e) => Err ( e) ,
105+ None => Ok ( ( ) ) ,
95106 }
96107 }
97108
98109 /// Check if the function has valid input arguments for the given attribute
99- fn check_inputs ( & self , inputs : & Punctuated < FnArg , Comma > ) -> Result < ( ) > {
110+ fn check_inputs ( & self , inputs : & Punctuated < FnArg , Comma > , errors : & mut Option < Error > ) {
100111 // Use this match to specify expected input arguments for different functions in the future
101112 match self {
102- Self :: PostInit => self . check_fn_args ( inputs, & [ "usize" ] ) ,
113+ Self :: PostInit => self . check_fn_args ( inputs, & [ "usize" ] , errors ) ,
103114 }
104115 }
105116
106117 /// Check if the function has a valid output type for the given attribute
107- fn check_output ( & self , output : & ReturnType ) -> Result < ( ) > {
118+ fn check_output ( & self , output : & ReturnType , errors : & mut Option < Error > ) {
108119 // Use this match to specify expected output types for different functions in the future
109120 match self {
110- Self :: PostInit => check_output_empty ( output) ,
121+ Self :: PostInit => check_output_empty ( output, errors ) ,
111122 }
112123 }
113124
@@ -120,7 +131,7 @@ impl Fn {
120131
121132 export_name. map ( |name| {
122133 quote ! {
123- #[ cfg_attr ( any ( target_arch = "riscv32" , target_arch = "riscv64" ) , export_name = #name) ]
134+ #[ export_name = #name]
124135 }
125136 } )
126137 }
@@ -143,11 +154,7 @@ impl Fn {
143154 Ok ( ( ) )
144155 } else {
145156 let args: TokenStream2 = args. into ( ) ;
146- let attr = self . attr_name ( ) ;
147- Err ( Error :: new (
148- args. span ( ) ,
149- format ! ( "`#[{attr}]` function does not accept any arguments" ) ,
150- ) )
157+ Err ( Error :: new ( args. span ( ) , "macro arguments are not allowed" ) )
151158 }
152159 }
153160
@@ -156,21 +163,29 @@ impl Fn {
156163 & self ,
157164 inputs : & Punctuated < FnArg , Comma > ,
158165 expected_types : & [ & str ] ,
159- ) -> Result < ( ) > {
166+ errors : & mut Option < Error > ,
167+ ) {
160168 let mut expected_iter = expected_types. iter ( ) ;
161169 for arg in inputs. iter ( ) {
162170 match expected_iter. next ( ) {
163- Some ( expected) => check_arg_type ( arg, expected) ?,
171+ Some ( expected) => {
172+ if let Err ( e) = check_arg_type ( arg, expected) {
173+ combine_err ( errors, e) ;
174+ }
175+ }
164176 None => {
165- let attr = self . attr_name ( ) ;
166- return Err ( Error :: new (
167- arg. span ( ) ,
168- format ! ( "`#[{attr}]` function has too many input arguments" ) ,
169- ) ) ;
177+ combine_err ( errors, Error :: new ( arg. span ( ) , "too many input arguments" ) ) ;
170178 }
171179 }
172180 }
173- Ok ( ( ) )
181+ }
182+ }
183+
184+ /// Combine a new error into an optional accumulator
185+ fn combine_err ( acc : & mut Option < Error > , err : Error ) {
186+ match acc {
187+ Some ( e) => e. combine ( err) ,
188+ None => * acc = Some ( err) ,
174189 }
175190}
176191
@@ -181,7 +196,7 @@ fn check_arg_type(arg: &FnArg, expected: &str) -> Result<()> {
181196 if !is_correct_type ( & argument. ty , expected) {
182197 Err ( Error :: new (
183198 argument. ty . span ( ) ,
184- format ! ( "argument type must be {expected}" ) ,
199+ format ! ( "argument type must be ` {expected}` " ) ,
185200 ) )
186201 } else {
187202 Ok ( ( ) )
@@ -221,18 +236,16 @@ fn strip_type_path(ty: &Type) -> Option<Type> {
221236}
222237
223238/// Make sure the output type is either `()` or absent
224- fn check_output_empty ( output : & ReturnType ) -> Result < ( ) > {
239+ fn check_output_empty ( output : & ReturnType , errors : & mut Option < Error > ) {
225240 match output {
226- ReturnType :: Default => Ok ( ( ) ) ,
241+ ReturnType :: Default => { }
227242 ReturnType :: Type ( _, ty) => match * * ty {
228243 Type :: Tuple ( ref tuple) => {
229- if tuple. elems . is_empty ( ) {
230- Ok ( ( ) )
231- } else {
232- Err ( Error :: new ( tuple. span ( ) , "return type must be ()" ) )
244+ if !tuple. elems . is_empty ( ) {
245+ combine_err ( errors, Error :: new ( tuple. span ( ) , "return type must be ()" ) ) ;
233246 }
234247 }
235- _ => Err ( Error :: new ( ty. span ( ) , "return type must be ()" ) ) ,
248+ _ => combine_err ( errors , Error :: new ( ty. span ( ) , "return type must be ()" ) ) ,
236249 } ,
237250 }
238251}
0 commit comments