@@ -11,8 +11,9 @@ extern crate syn;
11
11
use proc_macro2:: Span ;
12
12
use syn:: {
13
13
parse:: { self , Parse } ,
14
+ punctuated:: Punctuated ,
14
15
spanned:: Spanned ,
15
- FnArg , ItemFn , LitInt , LitStr , PathArguments , ReturnType , Type , Visibility ,
16
+ FnArg , ItemFn , LitInt , LitStr , PatType , ReturnType , Type , Visibility ,
16
17
} ;
17
18
18
19
use proc_macro:: TokenStream ;
@@ -52,29 +53,57 @@ use proc_macro::TokenStream;
52
53
pub fn entry ( args : TokenStream , input : TokenStream ) -> TokenStream {
53
54
let f = parse_macro_input ! ( input as ItemFn ) ;
54
55
56
+ #[ cfg( not( feature = "u-boot" ) ) ]
57
+ let arguments_limit = 3 ;
58
+ #[ cfg( feature = "u-boot" ) ]
59
+ let arguments_limit = 2 ;
60
+
55
61
// check the function arguments
56
- if f. sig . inputs . len ( ) > 3 {
62
+ if f. sig . inputs . len ( ) > arguments_limit {
57
63
return parse:: Error :: new (
58
64
f. sig . inputs . last ( ) . unwrap ( ) . span ( ) ,
59
65
"`#[entry]` function has too many arguments" ,
60
66
)
61
67
. to_compile_error ( )
62
68
. into ( ) ;
63
69
}
64
- for arg in & f. sig . inputs {
65
- match arg {
66
- FnArg :: Receiver ( _) => {
67
- return parse:: Error :: new ( arg. span ( ) , "invalid argument" )
68
- . to_compile_error ( )
69
- . into ( ) ;
70
- }
71
- FnArg :: Typed ( t) => {
72
- if !is_simple_type ( & t. ty , "usize" ) {
73
- return parse:: Error :: new ( t. ty . span ( ) , "argument type must be usize" )
74
- . to_compile_error ( )
75
- . into ( ) ;
76
- }
77
- }
70
+
71
+ fn check_correct_type ( argument : & PatType , ty : & str ) -> Option < TokenStream > {
72
+ let inv_type_message = format ! ( "argument type must be {}" , ty) ;
73
+
74
+ if !is_correct_type ( & argument. ty , ty) {
75
+ let error = parse:: Error :: new ( argument. ty . span ( ) , inv_type_message) ;
76
+
77
+ Some ( error. to_compile_error ( ) . into ( ) )
78
+ } else {
79
+ None
80
+ }
81
+ }
82
+ fn check_argument_type ( argument : & FnArg , ty : & str ) -> Option < TokenStream > {
83
+ let argument_error = parse:: Error :: new ( argument. span ( ) , "invalid argument" ) ;
84
+ let argument_error = argument_error. to_compile_error ( ) . into ( ) ;
85
+
86
+ match argument {
87
+ FnArg :: Typed ( argument) => check_correct_type ( argument, ty) ,
88
+ FnArg :: Receiver ( _) => Some ( argument_error) ,
89
+ }
90
+ }
91
+ #[ cfg( not( feature = "u-boot" ) ) ]
92
+ for argument in f. sig . inputs . iter ( ) {
93
+ if let Some ( message) = check_argument_type ( argument, "usize" ) {
94
+ return message;
95
+ } ;
96
+ }
97
+ #[ cfg( feature = "u-boot" ) ]
98
+ if let Some ( argument) = f. sig . inputs . get ( 0 ) {
99
+ if let Some ( message) = check_argument_type ( argument, "c_int" ) {
100
+ return message;
101
+ }
102
+ }
103
+ #[ cfg( feature = "u-boot" ) ]
104
+ if let Some ( argument) = f. sig . inputs . get ( 1 ) {
105
+ if let Some ( message) = check_argument_type ( argument, "*const *const c_char" ) {
106
+ return message;
78
107
}
79
108
}
80
109
@@ -123,17 +152,32 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
123
152
. into ( )
124
153
}
125
154
126
- #[ allow( unused) ]
127
- fn is_simple_type ( ty : & Type , name : & str ) -> bool {
128
- if let Type :: Path ( p) = ty {
129
- if p. qself . is_none ( ) && p. path . leading_colon . is_none ( ) && p. path . segments . len ( ) == 1 {
130
- let segment = p. path . segments . first ( ) . unwrap ( ) ;
131
- if segment. ident == name && segment. arguments == PathArguments :: None {
132
- return true ;
133
- }
155
+ fn strip_type_path ( ty : & Type ) -> Option < Type > {
156
+ match ty {
157
+ Type :: Ptr ( ty) => {
158
+ let mut ty = ty. clone ( ) ;
159
+ ty. elem = Box :: new ( strip_type_path ( & ty. elem ) ?) ;
160
+ Some ( Type :: Ptr ( ty) )
161
+ }
162
+ Type :: Path ( ty) => {
163
+ let mut ty = ty. clone ( ) ;
164
+ let last_segment = ty. path . segments . last ( ) . unwrap ( ) . clone ( ) ;
165
+ ty. path . segments = Punctuated :: new ( ) ;
166
+ ty. path . segments . push_value ( last_segment) ;
167
+ Some ( Type :: Path ( ty) )
134
168
}
169
+ _ => None ,
170
+ }
171
+ }
172
+
173
+ #[ allow( unused) ]
174
+ fn is_correct_type ( ty : & Type , name : & str ) -> bool {
175
+ let correct: Type = syn:: parse_str ( name) . unwrap ( ) ;
176
+ if let Some ( ty) = strip_type_path ( ty) {
177
+ ty == correct
178
+ } else {
179
+ false
135
180
}
136
- false
137
181
}
138
182
139
183
/// Attribute to mark which function will be called at the beginning of the reset handler.
@@ -505,15 +549,21 @@ _continue_interrupt_trap:
505
549
}
506
550
507
551
#[ proc_macro_attribute]
508
- /// Attribute to declare an interrupt handler. The function must have the signature `[unsafe] fn() [-> !]`.
509
- /// If the `v-trap` feature is enabled, this macro generates the interrupt trap handler in assembly for RISCV-32 targets.
552
+ /// Attribute to declare an interrupt handler.
553
+ ///
554
+ /// The function must have the signature `[unsafe] fn() [-> !]`.
555
+ /// If the `v-trap` feature is enabled, this macro generates the
556
+ /// interrupt trap handler in assembly for RISCV-32 targets.
510
557
pub fn interrupt_riscv32 ( args : TokenStream , input : TokenStream ) -> TokenStream {
511
558
interrupt ( args, input, RiscvArch :: Rv32 )
512
559
}
513
560
514
561
#[ proc_macro_attribute]
515
- /// Attribute to declare an interrupt handler. The function must have the signature `[unsafe] fn() [-> !]`.
516
- /// If the `v-trap` feature is enabled, this macro generates the interrupt trap handler in assembly for RISCV-32 targets.
562
+ /// Attribute to declare an interrupt handler.
563
+ ///
564
+ /// The function must have the signature `[unsafe] fn() [-> !]`.
565
+ /// If the `v-trap` feature is enabled, this macro generates the
566
+ /// interrupt trap handler in assembly for RISCV-64 targets.
517
567
pub fn interrupt_riscv64 ( args : TokenStream , input : TokenStream ) -> TokenStream {
518
568
interrupt ( args, input, RiscvArch :: Rv64 )
519
569
}
0 commit comments