Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

Commit

Permalink
Merge #159
Browse files Browse the repository at this point in the history
159: static mut transform: forward `#[cfg]` r=therealprof a=japaric

as reported in japaric/cortex-m-rtfm#110 the following code fails to compile

``` rust
 #[entry]
fn main() -> ! {
    #[cfg(something)]
    static mut FOO: u32 = 0; //~ ERROR cannot find value `FOO` in this scope
}
```

the issue is that the expansion of the static looks like this:

``` rust
let FOO = unsafe {
    #[cfg(never)]
    static mut FOO: u32 = 0;

    &mut FOO
};
```

so when the `#[cfg]` evals to false the static is gone but the `let FOO` is not
removed.

this PR forwards `#[cfg]` attributes to the `let` expression and fixes the error

``` rust
 #[cfg(never)] // <- added
let FOO = unsafe {
    #[cfg(never)]
    static mut FOO: u32 = 0;

    &mut FOO
};
```

Co-authored-by: Jorge Aparicio <jorge@japaric.io>
  • Loading branch information
bors[bot] and japaric committed Dec 15, 2018
2 parents abed79f + c829d0a commit b4927ea
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 6 deletions.
25 changes: 25 additions & 0 deletions examples/cfg-static.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! using `#[cfg]` on `static` shouldn't cause compile errors
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

extern crate cortex_m_rt as rt;
extern crate panic_halt;

use rt::{entry, exception};

#[entry]
fn main() -> ! {
#[cfg(never)]
static mut COUNT: u32 = 0;

loop {}
}

#[exception]
fn SysTick() {
#[cfg(never)]
static mut FOO: u32 = 0;
}
41 changes: 35 additions & 6 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use std::collections::HashSet;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
use syn::{
parse, spanned::Spanned, FnArg, Ident, Item, ItemFn, ItemStatic, ReturnType, Stmt, Type,
Visibility,
parse, spanned::Spanned, AttrStyle, Attribute, FnArg, Ident, Item, ItemFn, ItemStatic,
PathArguments, ReturnType, Stmt, Type, Visibility,
};

static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
Expand Down Expand Up @@ -128,15 +128,17 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
let vars = statics
.into_iter()
.map(|var| {
let attrs = var.attrs;
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
Expand Down Expand Up @@ -405,7 +407,6 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {

// further type check of the input argument
let #pat: &cortex_m_rt::ExceptionFrame = #pat;

#(#stmts)*
}
)
Expand Down Expand Up @@ -446,15 +447,17 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
let vars = statics
.into_iter()
.map(|var| {
let attrs = var.attrs;
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
Expand Down Expand Up @@ -603,15 +606,17 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
let vars = statics
.into_iter()
.map(|var| {
let attrs = var.attrs;
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
Expand Down Expand Up @@ -776,3 +781,27 @@ fn extract_static_muts(stmts: Vec<Stmt>) -> Result<(Vec<ItemStatic>, Vec<Stmt>),

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
}
}

0 comments on commit b4927ea

Please sign in to comment.