@@ -11,8 +11,9 @@ extern crate syn;
1111use proc_macro2:: Span ;
1212use syn:: {
1313 parse:: { self , Parse } ,
14+ punctuated:: Punctuated ,
1415 spanned:: Spanned ,
15- FnArg , ItemFn , LitInt , LitStr , PathArguments , ReturnType , Type , Visibility ,
16+ FnArg , ItemFn , LitInt , LitStr , PatType , ReturnType , Type , Visibility ,
1617} ;
1718
1819use proc_macro:: TokenStream ;
@@ -52,29 +53,57 @@ use proc_macro::TokenStream;
5253pub fn entry ( args : TokenStream , input : TokenStream ) -> TokenStream {
5354 let f = parse_macro_input ! ( input as ItemFn ) ;
5455
56+ #[ cfg( not( feature = "u-boot" ) ) ]
57+ let arguments_limit = 3 ;
58+ #[ cfg( feature = "u-boot" ) ]
59+ let arguments_limit = 2 ;
60+
5561 // check the function arguments
56- if f. sig . inputs . len ( ) > 3 {
62+ if f. sig . inputs . len ( ) > arguments_limit {
5763 return parse:: Error :: new (
5864 f. sig . inputs . last ( ) . unwrap ( ) . span ( ) ,
5965 "`#[entry]` function has too many arguments" ,
6066 )
6167 . to_compile_error ( )
6268 . into ( ) ;
6369 }
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;
78107 }
79108 }
80109
@@ -123,17 +152,32 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
123152 . into ( )
124153}
125154
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) )
134168 }
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
135180 }
136- false
137181}
138182
139183/// Attribute to mark which function will be called at the beginning of the reset handler.
@@ -505,15 +549,21 @@ _continue_interrupt_trap:
505549}
506550
507551#[ 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.
510557pub fn interrupt_riscv32 ( args : TokenStream , input : TokenStream ) -> TokenStream {
511558 interrupt ( args, input, RiscvArch :: Rv32 )
512559}
513560
514561#[ 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.
517567pub fn interrupt_riscv64 ( args : TokenStream , input : TokenStream ) -> TokenStream {
518568 interrupt ( args, input, RiscvArch :: Rv64 )
519569}
0 commit comments