@@ -9,7 +9,7 @@ extern crate syn;
99
1010use proc_macro2:: Span ;
1111use rand:: Rng ;
12- use syn:: { FnArg , Ident , Item , ItemFn , ReturnType , Stmt , Type , Visibility } ;
12+ use syn:: { FnArg , Ident , Item , ItemFn , ItemStatic , ReturnType , Stmt , Type , Visibility } ;
1313
1414use proc_macro:: TokenStream ;
1515
@@ -24,13 +24,45 @@ use proc_macro::TokenStream;
2424///
2525/// The type of the specified function must be `fn() -> !` (never ending function)
2626///
27+ /// # Properties
28+ ///
29+ /// The entry point will be called by the reset handler. The program can't reference to the entry
30+ /// point, much less invoke it.
31+ ///
32+ /// `static mut` variables declared within the entry point are safe to access. The compiler can't
33+ /// prove this is safe so the attribute will help by making a transformation to the source code: for
34+ /// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note
35+ /// that `&'static mut` references have move semantics.
36+ ///
2737/// # Examples
2838///
39+ /// - Simple entry point
40+ ///
41+ /// ``` no_run
42+ /// # #![no_main]
43+ /// # use cortex_m_rt_macros::entry;
44+ /// #[entry]
45+ /// fn main() -> ! {
46+ /// loop {
47+ /// /* .. */
48+ /// }
49+ /// }
50+ /// ```
51+ ///
52+ /// - `static mut` variables local to the entry point are safe to modify.
53+ ///
2954/// ``` no_run
3055/// # #![no_main]
3156/// # use cortex_m_rt_macros::entry;
3257/// #[entry]
3358/// fn main() -> ! {
59+ /// static mut FOO: u32 = 0;
60+ ///
61+ /// let foo: &'static mut u32 = FOO;
62+ /// assert_eq!(*foo, 0);
63+ /// *foo = 1;
64+ /// assert_eq!(*foo, 1);
65+ ///
3466/// loop {
3567/// /* .. */
3668/// }
@@ -69,12 +101,36 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
69101 // XXX should we blacklist other attributes?
70102 let attrs = f. attrs ;
71103 let ident = f. ident ;
72- let block = f. block ;
104+ let ( statics, stmts) = extract_static_muts ( f. block . stmts ) ;
105+
106+ let vars = statics
107+ . into_iter ( )
108+ . map ( |var| {
109+ let ident = var. ident ;
110+ // `let` can't shadow a `static mut` so we must give the `static` a different
111+ // name. We'll create a new name by appending an underscore to the original name
112+ // of the `static`.
113+ let mut ident_ = ident. to_string ( ) ;
114+ ident_. push ( '_' ) ;
115+ let ident_ = Ident :: new ( & ident_, Span :: call_site ( ) ) ;
116+ let ty = var. ty ;
117+ let expr = var. expr ;
118+
119+ quote ! (
120+ static mut #ident_: #ty = #expr;
121+ #[ allow( non_snake_case, unsafe_code) ]
122+ let #ident: & ' static mut #ty = unsafe { & mut #ident_ } ;
123+ )
124+ } ) . collect :: < Vec < _ > > ( ) ;
73125
74126 quote ! (
75127 #[ export_name = "main" ]
76128 #( #attrs) *
77- pub fn #ident( ) -> ! #block
129+ pub fn #ident( ) -> ! {
130+ #( #vars) *
131+
132+ #( #stmts) *
133+ }
78134 ) . into ( )
79135}
80136
@@ -130,8 +186,15 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
130186/// mut` variables at the beginning of the body of the function. These variables will be safe to
131187/// access from the function body.
132188///
189+ /// # Properties
190+ ///
133191/// Exception handlers can only be called by the hardware. Other parts of the program can't refer to
134- /// the exception handler much less invoke them as if they were functions.
192+ /// the exception handlers, much less invoke them as if they were functions.
193+ ///
194+ /// `static mut` variables declared within an exception handler are safe to access and can be used
195+ /// to preserve state across invocations of the handler. The compiler can't prove this is safe so
196+ /// the attribute will help by making a transformation to the source code: for this reason a
197+ /// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`.
135198///
136199/// # Examples
137200///
@@ -215,17 +278,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
215278 let block = f. block ;
216279 let stmts = block. stmts ;
217280
218- let mut rng = rand:: thread_rng ( ) ;
219- let hash = ( 0 ..16 )
220- . map ( |i| {
221- if i == 0 || rng. gen ( ) {
222- ( 'a' as u8 + rng. gen :: < u8 > ( ) % 25 ) as char
223- } else {
224- ( '0' as u8 + rng. gen :: < u8 > ( ) % 10 ) as char
225- }
226- } ) . collect :: < String > ( ) ;
227- let hash = Ident :: new ( & hash, Span :: call_site ( ) ) ;
228-
281+ let hash = random_ident ( ) ;
229282 match exn {
230283 Exception :: DefaultHandler => {
231284 assert ! (
@@ -336,27 +389,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
336389 have signature `fn()`"
337390 ) ;
338391
339- // Collect all the `static mut` at the beginning of the function body. We'll make them
340- // safe
341- let mut istmts = stmts. into_iter ( ) ;
342-
343- let mut statics = vec ! [ ] ;
344- let mut stmts = vec ! [ ] ;
345- while let Some ( stmt) = istmts. next ( ) {
346- match stmt {
347- Stmt :: Item ( Item :: Static ( var) ) => if var. mutability . is_some ( ) {
348- statics. push ( var) ;
349- } else {
350- stmts. push ( Stmt :: Item ( Item :: Static ( var) ) ) ;
351- } ,
352- _ => {
353- stmts. push ( stmt) ;
354- break ;
355- }
356- }
357- }
358-
359- stmts. extend ( istmts) ;
392+ let ( statics, stmts) = extract_static_muts ( stmts) ;
360393
361394 let vars = statics
362395 . into_iter ( )
@@ -455,3 +488,44 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
455488 pub unsafe fn #ident( ) #block
456489 ) . into ( )
457490}
491+
492+ // Creates a random identifier
493+ fn random_ident ( ) -> Ident {
494+ let mut rng = rand:: thread_rng ( ) ;
495+ Ident :: new (
496+ & ( 0 ..16 )
497+ . map ( |i| {
498+ if i == 0 || rng. gen ( ) {
499+ ( 'a' as u8 + rng. gen :: < u8 > ( ) % 25 ) as char
500+ } else {
501+ ( '0' as u8 + rng. gen :: < u8 > ( ) % 10 ) as char
502+ }
503+ } ) . collect :: < String > ( ) ,
504+ Span :: call_site ( ) ,
505+ )
506+ }
507+
508+ /// Extracts `static mut` vars from the beginning of the given statements
509+ fn extract_static_muts ( stmts : Vec < Stmt > ) -> ( Vec < ItemStatic > , Vec < Stmt > ) {
510+ let mut istmts = stmts. into_iter ( ) ;
511+
512+ let mut statics = vec ! [ ] ;
513+ let mut stmts = vec ! [ ] ;
514+ while let Some ( stmt) = istmts. next ( ) {
515+ match stmt {
516+ Stmt :: Item ( Item :: Static ( var) ) => if var. mutability . is_some ( ) {
517+ statics. push ( var) ;
518+ } else {
519+ stmts. push ( Stmt :: Item ( Item :: Static ( var) ) ) ;
520+ } ,
521+ _ => {
522+ stmts. push ( stmt) ;
523+ break ;
524+ }
525+ }
526+ }
527+
528+ stmts. extend ( istmts) ;
529+
530+ ( statics, stmts)
531+ }
0 commit comments