1
1
extern crate proc_macro;
2
2
extern crate proc_macro2;
3
3
extern crate quote;
4
+ extern crate rand;
5
+ extern crate rand_xoshiro;
4
6
extern crate syn;
5
7
6
8
use proc_macro:: TokenStream ;
7
- use std:: collections:: HashSet ;
9
+ use std:: {
10
+ collections:: HashSet ,
11
+ sync:: atomic:: { AtomicUsize , Ordering } ,
12
+ time:: { SystemTime , UNIX_EPOCH } ,
13
+ } ;
8
14
9
15
use proc_macro2:: Span ;
10
16
use quote:: { quote, quote_spanned} ;
17
+ use rand:: Rng ;
18
+ use rand_xoshiro:: rand_core:: SeedableRng ;
11
19
use syn:: {
12
20
parenthesized,
13
21
parse:: { self , Parse } ,
@@ -164,7 +172,6 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
164
172
ReturnType :: Type ( _, ref ty) => matches ! ( * * ty, Type :: Never ( _) ) ,
165
173
} ;
166
174
167
- let fname = & f. sig . ident ;
168
175
let pair = match & interrupt_enable {
169
176
Some ( interrupt_enable) => interrupt_enable. extract_init_arg ( & f. sig . inputs ) ,
170
177
None => extract_critical_section_arg ( & f. sig . inputs ) ,
@@ -174,6 +181,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
174
181
// XXX should we blacklist other attributes?
175
182
let attrs = f. attrs ;
176
183
let unsafety = f. sig . unsafety ;
184
+ let hash = random_ident ( ) ;
177
185
let ( statics, stmts) = match extract_static_muts ( f. block . stmts ) {
178
186
Err ( e) => return e. to_compile_error ( ) . into ( ) ,
179
187
Ok ( x) => x,
@@ -209,15 +217,15 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
209
217
. map ( |arg| quote_spanned ! ( Span :: mixed_site( ) => let arg = #arg; ) ) ;
210
218
211
219
quote ! (
212
- #[ no_mangle ]
220
+ #[ export_name = "main" ]
213
221
#( #attrs) *
214
- pub #unsafety fn main ( ) -> ! {
215
- #unsafety fn #fname <' a>( #fn_param) -> ! {
222
+ pub #unsafety fn #hash ( ) -> ! {
223
+ #unsafety fn #hash <' a>( #fn_param) -> ! {
216
224
#( #vars) *
217
225
#( #stmts) *
218
226
}
219
227
#arg_def
220
- { #fname ( #arg_ident) }
228
+ { #hash ( #arg_ident) }
221
229
}
222
230
)
223
231
. into ( )
@@ -282,15 +290,17 @@ impl Parse for EntryInterruptEnable {
282
290
impl EntryInterruptEnable {
283
291
fn extract_init_arg ( & self , list : & Punctuated < FnArg , Token ! [ , ] > ) -> Result < ParamArgPair , ( ) > {
284
292
if let Some ( fn_name) = & self . pre_interrupt {
293
+ let hash = random_ident ( ) ;
285
294
let fn_arg = Some ( quote_spanned ! ( Span :: mixed_site( ) => {
286
295
let cs = unsafe { msp430:: interrupt:: CriticalSection :: new( ) } ;
287
296
288
297
// This struct forces the lifetime of the CriticalSection to match the lifetime of
289
298
// the reference. Since the reference lifetime is restricted to this scope, the
290
299
// compiler has to constrain the lifetime of the CriticalSection as well,
291
300
// preventing the CriticalSection from being leaked as a return value.
292
- mod inner { pub struct Cs <' a>( pub & ' a msp430:: interrupt:: CriticalSection <' a>) ; }
293
- let arg = #fn_name( * inner:: Cs ( & cs) . 0 ) ;
301
+ #[ allow( non_camel_case_types) ]
302
+ struct #hash<' a>( & ' a msp430:: interrupt:: CriticalSection <' a>) ;
303
+ let arg = #fn_name( * #hash( & cs) . 0 ) ;
294
304
295
305
unsafe { msp430:: interrupt:: enable( ) } ;
296
306
arg
@@ -475,17 +485,19 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
475
485
. collect :: < Vec < _ > > ( ) ;
476
486
477
487
let output = f. sig . output ;
488
+ let hash = random_ident ( ) ;
489
+ let ident = ident. to_string ( ) ;
478
490
quote ! (
479
- #[ no_mangle ]
491
+ #[ export_name = #ident ]
480
492
#( #attrs) *
481
- #unsafety extern "msp430-interrupt" fn #ident ( ) {
493
+ #unsafety extern "msp430-interrupt" fn #hash ( ) {
482
494
#check
483
495
484
- #unsafety fn #ident <' a>( #fn_param) #output {
496
+ #unsafety fn #hash <' a>( #fn_param) #output {
485
497
#( #vars) *
486
498
#( #stmts) *
487
499
}
488
- { #ident ( #fn_arg) }
500
+ { #hash ( #fn_arg) }
489
501
}
490
502
)
491
503
. into ( )
@@ -618,6 +630,41 @@ fn extract_critical_section_arg(list: &Punctuated<FnArg, Token![,]>) -> Result<P
618
630
Err ( ( ) )
619
631
}
620
632
633
+ // Creates a random identifier
634
+ fn random_ident ( ) -> Ident {
635
+ static CALL_COUNT : AtomicUsize = AtomicUsize :: new ( 0 ) ;
636
+
637
+ let secs = SystemTime :: now ( )
638
+ . duration_since ( UNIX_EPOCH )
639
+ . unwrap ( )
640
+ . as_secs ( ) ;
641
+
642
+ let count: u64 = CALL_COUNT . fetch_add ( 1 , Ordering :: SeqCst ) as u64 ;
643
+ let mut seed: [ u8 ; 16 ] = [ 0 ; 16 ] ;
644
+
645
+ for ( i, v) in seed. iter_mut ( ) . take ( 8 ) . enumerate ( ) {
646
+ * v = ( ( secs >> ( i * 8 ) ) & 0xFF ) as u8
647
+ }
648
+
649
+ for ( i, v) in seed. iter_mut ( ) . skip ( 8 ) . enumerate ( ) {
650
+ * v = ( ( count >> ( i * 8 ) ) & 0xFF ) as u8
651
+ }
652
+
653
+ let mut rng = rand_xoshiro:: Xoshiro128PlusPlus :: from_seed ( seed) ;
654
+ Ident :: new (
655
+ & ( 0 ..16 )
656
+ . map ( |i| {
657
+ if i == 0 || rng. gen ( ) {
658
+ ( b'a' + rng. gen :: < u8 > ( ) % 25 ) as char
659
+ } else {
660
+ ( b'0' + rng. gen :: < u8 > ( ) % 10 ) as char
661
+ }
662
+ } )
663
+ . collect :: < String > ( ) ,
664
+ Span :: call_site ( ) ,
665
+ )
666
+ }
667
+
621
668
/// Extracts `static mut` vars from the beginning of the given statements
622
669
fn extract_static_muts ( stmts : Vec < Stmt > ) -> Result < ( Vec < ItemStatic > , Vec < Stmt > ) , parse:: Error > {
623
670
let mut istmts = stmts. into_iter ( ) ;
@@ -653,24 +700,3 @@ fn extract_static_muts(stmts: Vec<Stmt>) -> Result<(Vec<ItemStatic>, Vec<Stmt>),
653
700
654
701
Ok ( ( statics, stmts) )
655
702
}
656
-
657
- /// ``` no_run
658
- /// #![no_main]
659
- /// use msp430_rt_macros::{entry, interrupt};
660
- /// use msp430::interrupt::CriticalSection;
661
- ///
662
- /// fn arg(cs: CriticalSection) -> u32 {
663
- /// arg(cs)
664
- /// }
665
- ///
666
- /// #[entry(interrupt_enable(pre_interrupt = arg))]
667
- /// fn main(i: u32) -> ! {
668
- /// main(i)
669
- /// }
670
- /// ```
671
- #[ cfg( doctest) ]
672
- #[ doc( hidden) ]
673
- #[ proc_macro]
674
- pub fn recursive_doc_test ( t : TokenStream ) -> TokenStream {
675
- t
676
- }
0 commit comments