Browse Source

[macros] Remove 'static mut' hack

Vadim Kaushan 6 years ago
parent
commit
253aa88fff
1 changed files with 4 additions and 230 deletions
  1. 4 230
      riscv-rt/macros/src/lib.rs

+ 4 - 230
riscv-rt/macros/src/lib.rs

@@ -12,12 +12,10 @@ extern crate syn;
 use proc_macro2::Span;
 use rand::Rng;
 use rand::SeedableRng;
-use std::collections::HashSet;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::time::{SystemTime, UNIX_EPOCH};
 use syn::{
-    parse, spanned::Spanned, AttrStyle, Attribute, FnArg, Ident, Item, ItemFn, ItemStatic,
-    PathArguments, ReturnType, Stmt, Type, Visibility,
+    parse, spanned::Spanned, FnArg, Ident, ItemFn, ReturnType, Type, Visibility,
 };
 
 static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
@@ -42,11 +40,6 @@ use proc_macro::TokenStream;
 /// The entry point will be called by the reset handler. The program can't reference to the entry
 /// point, much less invoke it.
 ///
-/// `static mut` variables declared within the entry point are safe to access. The compiler can't
-/// prove this is safe so the attribute will help by making a transformation to the source code: for
-/// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note
-/// that `&'static mut` references have move semantics.
-///
 /// # Examples
 ///
 /// - Simple entry point
@@ -61,26 +54,6 @@ use proc_macro::TokenStream;
 ///     }
 /// }
 /// ```
-///
-/// - `static mut` variables local to the entry point are safe to modify.
-///
-/// ``` no_run
-/// # #![no_main]
-/// # use riscv_rt_macros::entry;
-/// #[entry]
-/// fn main() -> ! {
-///     static mut FOO: u32 = 0;
-///
-///     let foo: &'static mut u32 = FOO;
-///     assert_eq!(*foo, 0);
-///     *foo = 1;
-///     assert_eq!(*foo, 1);
-///
-///     loop {
-///         /* .. */
-///     }
-/// }
-/// ```
 #[proc_macro_attribute]
 pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
     let f = parse_macro_input!(input as ItemFn);
@@ -120,39 +93,12 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
     let attrs = f.attrs;
     let unsafety = f.unsafety;
     let hash = random_ident();
-    let (statics, stmts) = match extract_static_muts(f.block.stmts) {
-        Err(e) => return e.to_compile_error().into(),
-        Ok(x) => x,
-    };
-
-    let vars = statics
-        .into_iter()
-        .map(|var| {
-            let (ref cfgs, ref attrs) = extract_cfgs(var.attrs);
-            let ident = var.ident;
-            let ty = var.ty;
-            let expr = var.expr;
-
-            quote!(
-                #[allow(non_snake_case)]
-                #(#cfgs)*
-                let #ident: &'static mut #ty = unsafe {
-                    #(#attrs)*
-                    #(#cfgs)*
-                    static mut #ident: #ty = #expr;
-
-                    &mut #ident
-                };
-            )
-        })
-        .collect::<Vec<_>>();
+    let stmts = f.block.stmts;
 
     quote!(
         #[export_name = "main"]
         #(#attrs)*
         pub #unsafety fn #hash() -> ! {
-            #(#vars)*
-
             #(#stmts)*
         }
     )
@@ -209,20 +155,13 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
 /// handler is servicing a device specific exception (interrupt).
 ///
 /// `#[exception] fn Name(..` overrides the default handler for the exception with the given `Name`.
-/// These handlers must have signature `[unsafe] fn() [-> !]`. When overriding these other exception
-/// it's possible to add state to them by declaring `static mut` variables at the beginning of the
-/// body of the function. These variables will be safe to access from the function body.
+/// These handlers must have signature `[unsafe] fn() [-> !]`.
 ///
 /// # Properties
 ///
 /// Exception handlers can only be called by the hardware. Other parts of the program can't refer to
 /// the exception handlers, much less invoke them as if they were functions.
 ///
-/// `static mut` variables declared within an exception handler are safe to access and can be used
-/// to preserve state across invocations of the handler. The compiler can't prove this is safe so
-/// the attribute will help by making a transformation to the source code: for this reason a
-/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`.
-///
 /// # Examples
 ///
 /// - Setting the `HardFault` handler
@@ -251,26 +190,6 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
 ///
 /// # fn main() {}
 /// ```
-///
-/// - Overriding the `SysTick` handler
-///
-/// ```
-/// extern crate riscv_rt as rt;
-///
-/// use rt::exception;
-///
-/// #[exception]
-/// fn SysTick() {
-///     static mut COUNT: i32 = 0;
-///
-///     // `COUNT` is safe to access and has type `&mut i32`
-///     *COUNT += 1;
-///
-///     println!("{}", COUNT);
-/// }
-///
-/// # fn main() {}
-/// ```
 #[proc_macro_attribute]
 pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
     let f = parse_macro_input!(input as ItemFn);
@@ -439,33 +358,6 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
                 .into();
             }
 
-            let (statics, stmts) = match extract_static_muts(stmts) {
-                Err(e) => return e.to_compile_error().into(),
-                Ok(x) => x,
-            };
-
-            let vars = statics
-                .into_iter()
-                .map(|var| {
-                    let (ref cfgs, ref attrs) = extract_cfgs(var.attrs);
-                    let ident = var.ident;
-                    let ty = var.ty;
-                    let expr = var.expr;
-
-                    quote!(
-                        #[allow(non_snake_case)]
-                        #(#cfgs)*
-                        let #ident: &mut #ty = unsafe {
-                            #(#attrs)*
-                            #(#cfgs)*
-                            static mut #ident: #ty = #expr;
-
-                            &mut #ident
-                        };
-                    )
-                })
-                .collect::<Vec<_>>();
-
             quote!(
                 #[export_name = #ident_s]
                 #(#attrs)*
@@ -475,8 +367,6 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
                     // check that this exception actually exists
                     riscv_rt::Exception::#ident;
 
-                    #(#vars)*
-
                     #(#stmts)*
                 }
             )
@@ -517,9 +407,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
 /// # Usage
 ///
 /// `#[interrupt] fn Name(..` overrides the default handler for the interrupt with the given `Name`.
-/// These handlers must have signature `[unsafe] fn() [-> !]`. It's possible to add state to these
-/// handlers by declaring `static mut` variables at the beginning of the body of the function. These
-/// variables will be safe to access from the function body.
+/// These handlers must have signature `[unsafe] fn() [-> !]`.
 ///
 /// If the interrupt handler has not been overridden it will be dispatched by the default exception
 /// handler (`DefaultHandler`).
@@ -528,31 +416,6 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
 ///
 /// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer
 /// to the interrupt handlers, much less invoke them as if they were functions.
-///
-/// `static mut` variables declared within an interrupt handler are safe to access and can be used
-/// to preserve state across invocations of the handler. The compiler can't prove this is safe so
-/// the attribute will help by making a transformation to the source code: for this reason a
-/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`.
-///
-/// # Examples
-///
-/// - Using state within an interrupt handler
-///
-/// ``` ignore
-/// extern crate device;
-///
-/// use device::interrupt;
-///
-/// #[interrupt]
-/// fn TIM2() {
-///     static mut COUNT: i32 = 0;
-///
-///     // `COUNT` is safe to access and has type `&mut i32`
-///     *COUNT += 1;
-///
-///     println!("{}", COUNT);
-/// }
-/// ```
 #[proc_macro_attribute]
 pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
     let f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function");
@@ -598,33 +461,6 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
         .into();
     }
 
-    let (statics, stmts) = match extract_static_muts(stmts) {
-        Err(e) => return e.to_compile_error().into(),
-        Ok(x) => x,
-    };
-
-    let vars = statics
-        .into_iter()
-        .map(|var| {
-            let (ref cfgs, ref attrs) = extract_cfgs(var.attrs);
-            let ident = var.ident;
-            let ty = var.ty;
-            let expr = var.expr;
-
-            quote!(
-                #[allow(non_snake_case)]
-                #(#cfgs)*
-                let #ident: &mut #ty = unsafe {
-                    #(#attrs)*
-                    #(#cfgs)*
-                    static mut #ident: #ty = #expr;
-
-                    &mut #ident
-                };
-            )
-        })
-        .collect::<Vec<_>>();
-
     let hash = random_ident();
     quote!(
         #[export_name = #ident_s]
@@ -632,8 +468,6 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
         pub #unsafety extern "C" fn #hash() {
             interrupt::#ident;
 
-            #(#vars)*
-
             #(#stmts)*
         }
     )
@@ -745,63 +579,3 @@ fn random_ident() -> Ident {
         Span::call_site(),
     )
 }
-
-/// Extracts `static mut` vars from the beginning of the given statements
-fn extract_static_muts(stmts: Vec<Stmt>) -> Result<(Vec<ItemStatic>, Vec<Stmt>), parse::Error> {
-    let mut istmts = stmts.into_iter();
-
-    let mut seen = HashSet::new();
-    let mut statics = vec![];
-    let mut stmts = vec![];
-    while let Some(stmt) = istmts.next() {
-        match stmt {
-            Stmt::Item(Item::Static(var)) => {
-                if var.mutability.is_some() {
-                    if seen.contains(&var.ident) {
-                        return Err(parse::Error::new(
-                            var.ident.span(),
-                            format!("the name `{}` is defined multiple times", var.ident),
-                        ));
-                    }
-
-                    seen.insert(var.ident.clone());
-                    statics.push(var);
-                } else {
-                    stmts.push(Stmt::Item(Item::Static(var)));
-                }
-            }
-            _ => {
-                stmts.push(stmt);
-                break;
-            }
-        }
-    }
-
-    stmts.extend(istmts);
-
-    Ok((statics, stmts))
-}
-
-fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) {
-    let mut cfgs = vec![];
-    let mut not_cfgs = vec![];
-
-    for attr in attrs {
-        if eq(&attr, "cfg") {
-            cfgs.push(attr);
-        } else {
-            not_cfgs.push(attr);
-        }
-    }
-
-    (cfgs, not_cfgs)
-}
-
-/// Returns `true` if `attr.path` matches `name`
-fn eq(attr: &Attribute, name: &str) -> bool {
-    attr.style == AttrStyle::Outer && attr.path.segments.len() == 1 && {
-        let pair = attr.path.segments.first().unwrap();
-        let segment = pair.value();
-        segment.arguments == PathArguments::None && segment.ident.to_string() == name
-    }
-}