114: properly handle conditional compilation r=japaric a=japaric

of resources and tasks

Co-authored-by: Jorge Aparicio <jorge@japaric.io>
This commit is contained in:
bors[bot] 2018-12-16 18:18:17 +00:00
commit c2fbb28488
11 changed files with 455 additions and 119 deletions

View file

@ -3,6 +3,7 @@ authors = ["Jorge Aparicio <jorge@japaric.io>"]
categories = ["concurrency", "embedded", "no-std"] categories = ["concurrency", "embedded", "no-std"]
description = "Procedural macros of the cortex-m-rtfm crate" description = "Procedural macros of the cortex-m-rtfm crate"
documentation = "https://japaric.github.io/cortex-m-rtfm/api/cortex_m_rtfm" documentation = "https://japaric.github.io/cortex-m-rtfm/api/cortex_m_rtfm"
edition = "2018"
keywords = ["arm", "cortex-m"] keywords = ["arm", "cortex-m"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
name = "cortex-m-rtfm-macros" name = "cortex-m-rtfm-macros"
@ -14,12 +15,12 @@ version = "0.4.0-beta.3"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
quote = "0.6.8" quote = "0.6.10"
proc-macro2 = "0.4.20" proc-macro2 = "0.4.24"
[dependencies.syn] [dependencies.syn]
features = ["extra-traits", "full"] features = ["extra-traits", "full"]
version = "0.15.6" version = "0.15.23"
[dependencies.rand] [dependencies.rand]
default-features = false default-features = false

View file

@ -5,7 +5,7 @@ use std::{
use syn::{Attribute, Ident, Type}; use syn::{Attribute, Ident, Type};
use syntax::{App, Idents}; use crate::syntax::{App, Idents};
pub type Ownerships = HashMap<Ident, Ownership>; pub type Ownerships = HashMap<Ident, Ownership>;

View file

@ -3,14 +3,14 @@ use std::{collections::HashSet, iter};
use proc_macro2::Span; use proc_macro2::Span;
use syn::parse; use syn::parse;
use syntax::App; use crate::syntax::App;
pub fn app(app: &App) -> parse::Result<()> { pub fn app(app: &App) -> parse::Result<()> {
// Check that all referenced resources have been declared // Check that all referenced resources have been declared
for res in app for res in app
.idle .idle
.as_ref() .as_ref()
.map(|idle| -> Box<Iterator<Item = _>> { Box::new(idle.args.resources.iter()) }) .map(|idle| -> Box<dyn Iterator<Item = _>> { Box::new(idle.args.resources.iter()) })
.unwrap_or_else(|| Box::new(iter::empty())) .unwrap_or_else(|| Box::new(iter::empty()))
.chain(&app.init.args.resources) .chain(&app.init.args.resources)
.chain(app.exceptions.values().flat_map(|e| &e.args.resources)) .chain(app.exceptions.values().flat_map(|e| &e.args.resources))
@ -53,7 +53,7 @@ pub fn app(app: &App) -> parse::Result<()> {
for task in app for task in app
.idle .idle
.as_ref() .as_ref()
.map(|idle| -> Box<Iterator<Item = _>> { .map(|idle| -> Box<dyn Iterator<Item = _>> {
Box::new(idle.args.schedule.iter().chain(&idle.args.spawn)) Box::new(idle.args.schedule.iter().chain(&idle.args.spawn))
}) })
.unwrap_or_else(|| Box::new(iter::empty())) .unwrap_or_else(|| Box::new(iter::empty()))
@ -73,7 +73,8 @@ pub fn app(app: &App) -> parse::Result<()> {
app.tasks app.tasks
.values() .values()
.flat_map(|t| t.args.schedule.iter().chain(&t.args.spawn)), .flat_map(|t| t.args.schedule.iter().chain(&t.args.spawn)),
) { )
{
if !app.tasks.contains_key(task) { if !app.tasks.contains_key(task) {
return Err(parse::Error::new( return Err(parse::Error::new(
task.span(), task.span(),

View file

@ -10,10 +10,12 @@ use std::{
use proc_macro2::Span; use proc_macro2::Span;
use quote::quote; use quote::quote;
use rand::{Rng, SeedableRng}; use rand::{Rng, SeedableRng};
use syn::{ArgCaptured, Ident, IntSuffix, LitInt}; use syn::{parse_quote, ArgCaptured, Attribute, Ident, IntSuffix, LitInt};
use analyze::{Analysis, Ownership}; use crate::{
use syntax::{App, Idents, Static}; analyze::{Analysis, Ownership},
syntax::{App, Idents, Static},
};
// NOTE to avoid polluting the user namespaces we map some identifiers to pseudo-hygienic names. // NOTE to avoid polluting the user namespaces we map some identifiers to pseudo-hygienic names.
// In some instances we also use the pseudo-hygienic names for safety, for example the user should // In some instances we also use the pseudo-hygienic names for safety, for example the user should
@ -86,8 +88,6 @@ struct Resources {
pub fn app(app: &App, analysis: &Analysis) -> TokenStream { pub fn app(app: &App, analysis: &Analysis) -> TokenStream {
let mut ctxt = Context::default(); let mut ctxt = Context::default();
let device = &app.args.device;
let resources = resources(&mut ctxt, &app, analysis); let resources = resources(&mut ctxt, &app, analysis);
let tasks = tasks(&mut ctxt, &app, analysis); let tasks = tasks(&mut ctxt, &app, analysis);
@ -146,6 +146,7 @@ pub fn app(app: &App, analysis: &Analysis) -> TokenStream {
let assertions = assertions(app, analysis); let assertions = assertions(app, analysis);
let main = mk_ident(None);
let init = &ctxt.init; let init = &ctxt.init;
quote!( quote!(
#resources #resources
@ -162,11 +163,7 @@ pub fn app(app: &App, analysis: &Analysis) -> TokenStream {
#root_interrupts #root_interrupts
// We put these items into a pseudo-module to avoid a collision between the `interrupt`
// import and user code
const APP: () = { const APP: () = {
use #device::interrupt;
#scoped_interrupts #scoped_interrupts
#(#dispatchers)* #(#dispatchers)*
@ -178,10 +175,10 @@ pub fn app(app: &App, analysis: &Analysis) -> TokenStream {
#idle_fn #idle_fn
#[export_name = "main"]
#[allow(unsafe_code)] #[allow(unsafe_code)]
#[rtfm::export::entry]
#[doc(hidden)] #[doc(hidden)]
unsafe fn main() -> ! { unsafe fn #main() -> ! {
#assertions #assertions
rtfm::export::interrupt::disable(); rtfm::export::interrupt::disable();
@ -204,6 +201,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
let mut items = vec![]; let mut items = vec![];
let mut module = vec![]; let mut module = vec![];
for (name, res) in &app.resources { for (name, res) in &app.resources {
let cfgs = &res.cfgs;
let attrs = &res.attrs; let attrs = &res.attrs;
let mut_ = &res.mutability; let mut_ = &res.mutability;
let ty = &res.ty; let ty = &res.ty;
@ -219,6 +217,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) { if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) {
items.push(mk_resource( items.push(mk_resource(
ctxt, ctxt,
cfgs,
name, name,
quote!(#name), quote!(#name),
*ceiling, *ceiling,
@ -238,6 +237,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
.map(|expr| { .map(|expr| {
quote!( quote!(
#(#attrs)* #(#attrs)*
#(#cfgs)*
#[doc = #symbol] #[doc = #symbol]
static mut #alias: #ty = #expr; static mut #alias: #ty = #expr;
) )
@ -245,6 +245,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
.unwrap_or_else(|| { .unwrap_or_else(|| {
quote!( quote!(
#(#attrs)* #(#attrs)*
#(#cfgs)*
#[doc = #symbol] #[doc = #symbol]
static mut #alias: rtfm::export::MaybeUninit<#ty> = static mut #alias: rtfm::export::MaybeUninit<#ty> =
rtfm::export::MaybeUninit::uninitialized(); rtfm::export::MaybeUninit::uninitialized();
@ -262,6 +263,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
items.push(mk_resource( items.push(mk_resource(
ctxt, ctxt,
cfgs,
name, name,
quote!(#ty), quote!(#ty),
*ceiling, *ceiling,
@ -297,6 +299,7 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Toke
.assigns .assigns
.iter() .iter()
.map(|assign| { .map(|assign| {
let attrs = &assign.attrs;
if app if app
.resources .resources
.get(&assign.left) .get(&assign.left)
@ -305,11 +308,17 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Toke
{ {
let alias = &ctxt.statics[&assign.left]; let alias = &ctxt.statics[&assign.left];
let expr = &assign.right; let expr = &assign.right;
quote!(unsafe { #alias.set(#expr); }) quote!(
#(#attrs)*
unsafe { #alias.set(#expr); }
)
} else { } else {
let left = &assign.left; let left = &assign.left;
let right = &assign.right; let right = &assign.right;
quote!(#left = #right;) quote!(
#(#attrs)*
#left = #right;
)
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -607,12 +616,14 @@ fn prelude(
// NOTE This field is just to avoid unused type parameter errors around `'a` // NOTE This field is just to avoid unused type parameter errors around `'a`
defs.push(quote!(#[allow(dead_code)] #priority: &'a core::cell::Cell<u8>)); defs.push(quote!(#[allow(dead_code)] #priority: &'a core::cell::Cell<u8>));
exprs.push(quote!(#priority)); exprs.push(parse_quote!(#priority));
let mut may_call_lock = false; let mut may_call_lock = false;
let mut needs_unsafe = false; let mut needs_unsafe = false;
for name in resources { for name in resources {
let res = &app.resources[name]; let res = &app.resources[name];
let cfgs = &res.cfgs;
let initialized = res.expr.is_some(); let initialized = res.expr.is_some();
let singleton = res.singleton; let singleton = res.singleton;
let mut_ = res.mutability; let mut_ = res.mutability;
@ -624,23 +635,40 @@ fn prelude(
// owned by Init // owned by Init
if singleton { if singleton {
needs_unsafe = true; needs_unsafe = true;
defs.push(quote!(pub #name: #name)); defs.push(quote!(
exprs.push(quote!(#name: <#name as owned_singleton::Singleton>::new())); #(#cfgs)*
pub #name: #name
));
exprs.push(quote!(
#(#cfgs)*
#name: <#name as owned_singleton::Singleton>::new()
));
continue; continue;
} else { } else {
defs.push(quote!(pub #name: &'static #mut_ #ty)); defs.push(quote!(
#(#cfgs)*
pub #name: &'static #mut_ #ty
));
} }
} else { } else {
// owned by someone else // owned by someone else
if singleton { if singleton {
needs_unsafe = true; needs_unsafe = true;
defs.push(quote!(pub #name: &'a mut #name)); defs.push(quote!(
exprs #(#cfgs)*
.push(quote!(#name: &mut <#name as owned_singleton::Singleton>::new())); pub #name: &'a mut #name
));
exprs.push(quote!(
#(#cfgs)*
#name: &mut <#name as owned_singleton::Singleton>::new()
));
continue; continue;
} else { } else {
force_mut = true; force_mut = true;
defs.push(quote!(pub #name: &'a mut #ty)); defs.push(quote!(
#(#cfgs)*
pub #name: &'a mut #ty
));
} }
} }
@ -648,9 +676,15 @@ fn prelude(
// Resources assigned to init are always const initialized // Resources assigned to init are always const initialized
needs_unsafe = true; needs_unsafe = true;
if force_mut { if force_mut {
exprs.push(quote!(#name: &mut #alias)); exprs.push(quote!(
#(#cfgs)*
#name: &mut #alias
));
} else { } else {
exprs.push(quote!(#name: &#mut_ #alias)); exprs.push(quote!(
#(#cfgs)*
#name: &#mut_ #alias
));
} }
} else { } else {
let ownership = &analysis.ownerships[name]; let ownership = &analysis.ownerships[name];
@ -661,23 +695,43 @@ fn prelude(
if singleton { if singleton {
if mut_.is_none() { if mut_.is_none() {
needs_unsafe = true; needs_unsafe = true;
defs.push(quote!(pub #name: &'a #name)); defs.push(quote!(
exprs #(#cfgs)*
.push(quote!(#name: &<#name as owned_singleton::Singleton>::new())); pub #name: &'a #name
));
exprs.push(quote!(
#(#cfgs)*
#name: &<#name as owned_singleton::Singleton>::new()
));
continue; continue;
} else { } else {
// Generate a resource proxy // Generate a resource proxy
defs.push(quote!(pub #name: resources::#name<'a>)); defs.push(quote!(
exprs.push(quote!(#name: resources::#name { #priority })); #(#cfgs)*
pub #name: resources::#name<'a>
));
exprs.push(quote!(
#(#cfgs)*
#name: resources::#name { #priority }
));
continue; continue;
} }
} else { } else {
if mut_.is_none() { if mut_.is_none() {
defs.push(quote!(pub #name: &'a #ty)); defs.push(quote!(
#(#cfgs)*
pub #name: &'a #ty
));
} else { } else {
// Generate a resource proxy // Generate a resource proxy
defs.push(quote!(pub #name: resources::#name<'a>)); defs.push(quote!(
exprs.push(quote!(#name: resources::#name { #priority })); #(#cfgs)*
pub #name: resources::#name<'a>
));
exprs.push(quote!(
#(#cfgs)*
#name: resources::#name { #priority }
));
continue; continue;
} }
} }
@ -685,29 +739,47 @@ fn prelude(
if singleton { if singleton {
if kind.runs_once() { if kind.runs_once() {
needs_unsafe = true; needs_unsafe = true;
defs.push(quote!(pub #name: #name)); defs.push(quote!(
exprs.push(quote!(#name: <#name as owned_singleton::Singleton>::new())); #(#cfgs)*
pub #name: #name
));
exprs.push(quote!(
#(#cfgs)*
#name: <#name as owned_singleton::Singleton>::new()
));
} else { } else {
needs_unsafe = true; needs_unsafe = true;
if ownership.is_owned() || mut_.is_none() { if ownership.is_owned() || mut_.is_none() {
defs.push(quote!(pub #name: &'a #mut_ #name)); defs.push(quote!(
let alias = mk_ident(None); #(#cfgs)*
items.push(quote!( pub #name: &'a #mut_ #name
let #mut_ #alias = unsafe {
<#name as owned_singleton::Singleton>::new()
};
)); ));
exprs.push(quote!(#name: &#mut_ #alias));
} else {
may_call_lock = true;
defs.push(quote!(pub #name: rtfm::Exclusive<'a, #name>));
let alias = mk_ident(None); let alias = mk_ident(None);
items.push(quote!( items.push(quote!(
#(#cfgs)*
let #mut_ #alias = unsafe { let #mut_ #alias = unsafe {
<#name as owned_singleton::Singleton>::new() <#name as owned_singleton::Singleton>::new()
}; };
)); ));
exprs.push(quote!( exprs.push(quote!(
#(#cfgs)*
#name: &#mut_ #alias
));
} else {
may_call_lock = true;
defs.push(quote!(
#(#cfgs)*
pub #name: rtfm::Exclusive<'a, #name>
));
let alias = mk_ident(None);
items.push(quote!(
#(#cfgs)*
let #mut_ #alias = unsafe {
<#name as owned_singleton::Singleton>::new()
};
));
exprs.push(quote!(
#(#cfgs)*
#name: rtfm::Exclusive(&mut #alias) #name: rtfm::Exclusive(&mut #alias)
)); ));
} }
@ -715,11 +787,17 @@ fn prelude(
continue; continue;
} else { } else {
if ownership.is_owned() || mut_.is_none() { if ownership.is_owned() || mut_.is_none() {
defs.push(quote!(pub #name: &#lt #mut_ #ty)); defs.push(quote!(
#(#cfgs)*
pub #name: &#lt #mut_ #ty
));
} else { } else {
exclusive = true; exclusive = true;
may_call_lock = true; may_call_lock = true;
defs.push(quote!(pub #name: rtfm::Exclusive<#lt, #ty>)); defs.push(quote!(
#(#cfgs)*
pub #name: rtfm::Exclusive<#lt, #ty>
));
} }
} }
} }
@ -728,9 +806,15 @@ fn prelude(
needs_unsafe = true; needs_unsafe = true;
if initialized { if initialized {
if exclusive { if exclusive {
exprs.push(quote!(#name: rtfm::Exclusive(&mut #alias))); exprs.push(quote!(
#(#cfgs)*
#name: rtfm::Exclusive(&mut #alias)
));
} else { } else {
exprs.push(quote!(#name: &#mut_ #alias)); exprs.push(quote!(
#(#cfgs)*
#name: &#mut_ #alias
));
} }
} else { } else {
let method = if mut_.is_some() { let method = if mut_.is_some() {
@ -740,9 +824,15 @@ fn prelude(
}; };
if exclusive { if exclusive {
exprs.push(quote!(#name: rtfm::Exclusive(#alias.#method()) )); exprs.push(quote!(
#(#cfgs)*
#name: rtfm::Exclusive(#alias.#method())
));
} else { } else {
exprs.push(quote!(#name: #alias.#method() )); exprs.push(quote!(
#(#cfgs)*
#name: #alias.#method()
));
} }
} }
} }
@ -755,6 +845,7 @@ fn prelude(
None None
}; };
let defs = &defs;
let doc = format!("`{}::Resources`", kind.ident().to_string()); let doc = format!("`{}::Resources`", kind.ident().to_string());
let decl = quote!( let decl = quote!(
#[doc = #doc] #[doc = #doc]
@ -893,7 +984,6 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec<proc_ma
.iter() .iter()
.map(|(ident, exception)| { .map(|(ident, exception)| {
let attrs = &exception.attrs; let attrs = &exception.attrs;
let statics = &exception.statics;
let stmts = &exception.stmts; let stmts = &exception.stmts;
let prelude = prelude( let prelude = prelude(
@ -934,15 +1024,18 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec<proc_ma
() => quote!(), () => quote!(),
}; };
let locals = mk_locals(&exception.statics, false);
let symbol = ident.to_string();
let alias = mk_ident(None);
let unsafety = &exception.unsafety; let unsafety = &exception.unsafety;
quote!( quote!(
#module #module
#[rtfm::export::exception]
#[doc(hidden)] #[doc(hidden)]
#[export_name = #symbol]
#(#attrs)* #(#attrs)*
#unsafety fn #ident() { #unsafety fn #alias() {
#(#statics)* #(#locals)*
#baseline_let #baseline_let
@ -967,9 +1060,9 @@ fn interrupts(
let mut root = vec![]; let mut root = vec![];
let mut scoped = vec![]; let mut scoped = vec![];
let device = &app.args.device;
for (ident, interrupt) in &app.interrupts { for (ident, interrupt) in &app.interrupts {
let attrs = &interrupt.attrs; let attrs = &interrupt.attrs;
let statics = &interrupt.statics;
let stmts = &interrupt.stmts; let stmts = &interrupt.stmts;
let prelude = prelude( let prelude = prelude(
@ -1010,12 +1103,18 @@ fn interrupts(
() => quote!(), () => quote!(),
}; };
let locals = mk_locals(&interrupt.statics, false);
let alias = mk_ident(None);
let symbol = ident.to_string();
let unsafety = &interrupt.unsafety; let unsafety = &interrupt.unsafety;
scoped.push(quote!( scoped.push(quote!(
#[interrupt]
#(#attrs)* #(#attrs)*
#unsafety fn #ident() { #[export_name = #symbol]
#(#statics)* #unsafety fn #alias() {
// check that this interrupt exists
let _ = #device::interrupt::#ident;
#(#locals)*
#baseline_let #baseline_let
@ -1053,6 +1152,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
let resource = mk_resource( let resource = mk_resource(
ctxt, ctxt,
&[],
&free_alias, &free_alias,
quote!(rtfm::export::FreeQueue<#capacity_ty>), quote!(rtfm::export::FreeQueue<#capacity_ty>),
*analysis.free_queues.get(name).unwrap_or(&0), *analysis.free_queues.get(name).unwrap_or(&0),
@ -1112,7 +1212,6 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
// second pass to generate the actual task function // second pass to generate the actual task function
for (name, task) in &app.tasks { for (name, task) in &app.tasks {
let attrs = &task.attrs;
let inputs = &task.inputs; let inputs = &task.inputs;
let locals = mk_locals(&task.statics, false); let locals = mk_locals(&task.statics, false);
let stmts = &task.stmts; let stmts = &task.stmts;
@ -1147,6 +1246,8 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
app, app,
)); ));
let attrs = &task.attrs;
let cfgs = &task.cfgs;
let task_alias = &ctxt.tasks[name].alias; let task_alias = &ctxt.tasks[name].alias;
let baseline_arg = match () { let baseline_arg = match () {
#[cfg(feature = "timer-queue")] #[cfg(feature = "timer-queue")]
@ -1159,6 +1260,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
}; };
items.push(quote!( items.push(quote!(
#(#attrs)* #(#attrs)*
#(#cfgs)*
#unsafety fn #task_alias(#baseline_arg #(#inputs,)*) { #unsafety fn #task_alias(#baseline_arg #(#inputs,)*) {
#(#locals)* #(#locals)*
@ -1182,18 +1284,32 @@ fn dispatchers(
let mut data = vec![]; let mut data = vec![];
let mut dispatchers = vec![]; let mut dispatchers = vec![];
let device = &app.args.device;
for (level, dispatcher) in &analysis.dispatchers { for (level, dispatcher) in &analysis.dispatchers {
let ready_alias = mk_ident(None); let ready_alias = mk_ident(None);
let enum_alias = mk_ident(None); let enum_alias = mk_ident(None);
let tasks = &dispatcher.tasks;
let capacity = mk_typenum_capacity(dispatcher.capacity, true); let capacity = mk_typenum_capacity(dispatcher.capacity, true);
let variants = dispatcher
.tasks
.iter()
.map(|task| {
let task_ = &app.tasks[task];
let cfgs = &task_.cfgs;
quote!(
#(#cfgs)*
#task
)
})
.collect::<Vec<_>>();
let symbol = format!("P{}::READY_QUEUE::{}", level, ready_alias); let symbol = format!("P{}::READY_QUEUE::{}", level, ready_alias);
let e = quote!(rtfm::export); let e = quote!(rtfm::export);
let ty = quote!(#e::ReadyQueue<#enum_alias, #capacity>); let ty = quote!(#e::ReadyQueue<#enum_alias, #capacity>);
let ceiling = *analysis.ready_queues.get(&level).unwrap_or(&0); let ceiling = *analysis.ready_queues.get(&level).unwrap_or(&0);
let resource = mk_resource( let resource = mk_resource(
ctxt, ctxt,
&[],
&ready_alias, &ready_alias,
ty.clone(), ty.clone(),
ceiling, ceiling,
@ -1204,7 +1320,7 @@ fn dispatchers(
data.push(quote!( data.push(quote!(
#[allow(dead_code)] #[allow(dead_code)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
enum #enum_alias { #(#tasks,)* } enum #enum_alias { #(#variants,)* }
#[doc = #symbol] #[doc = #symbol]
static mut #ready_alias: #e::MaybeUninit<#ty> = #e::MaybeUninit::uninitialized(); static mut #ready_alias: #e::MaybeUninit<#ty> = #e::MaybeUninit::uninitialized();
@ -1212,8 +1328,6 @@ fn dispatchers(
#resource #resource
)); ));
let interrupt = &dispatcher.interrupt;
let arms = dispatcher let arms = dispatcher
.tasks .tasks
.iter() .iter()
@ -1221,9 +1335,12 @@ fn dispatchers(
let task_ = &ctxt.tasks[task]; let task_ = &ctxt.tasks[task];
let inputs = &task_.inputs; let inputs = &task_.inputs;
let free = &task_.free_queue; let free = &task_.free_queue;
let pats = tuple_pat(&app.tasks[task].inputs);
let alias = &task_.alias; let alias = &task_.alias;
let task__ = &app.tasks[task];
let pats = tuple_pat(&task__.inputs);
let cfgs = &task__.cfgs;
let baseline_let; let baseline_let;
let call; let call;
match () { match () {
@ -1243,23 +1360,32 @@ fn dispatchers(
} }
}; };
quote!(#enum_alias::#task => { quote!(
#(#cfgs)*
#enum_alias::#task => {
#baseline_let #baseline_let
let input = ptr::read(#inputs.get_ref().get_unchecked(usize::from(index))); let input = ptr::read(#inputs.get_ref().get_unchecked(usize::from(index)));
#free.get_mut().split().0.enqueue_unchecked(index); #free.get_mut().split().0.enqueue_unchecked(index);
let (#pats) = input; let (#pats) = input;
#call #call
}) }
)
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let attrs = &dispatcher.attrs; let attrs = &dispatcher.attrs;
let interrupt = &dispatcher.interrupt;
let symbol = interrupt.to_string();
let alias = mk_ident(None);
dispatchers.push(quote!( dispatchers.push(quote!(
#(#attrs)* #(#attrs)*
#[interrupt] #[export_name = #symbol]
unsafe fn #interrupt() { unsafe fn #alias() {
use core::ptr; use core::ptr;
// check that this interrupt exists
let _ = #device::interrupt::#interrupt;
rtfm::export::run(|| { rtfm::export::run(|| {
while let Some((task, index)) = #ready_alias.get_mut().split().1.dequeue() { while let Some((task, index)) = #ready_alias.get_mut().split().1.dequeue() {
match task { match task {
@ -1293,6 +1419,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
for (name, task) in &ctxt.tasks { for (name, task) in &ctxt.tasks {
let alias = &task.spawn_fn; let alias = &task.spawn_fn;
let task_ = &app.tasks[name]; let task_ = &app.tasks[name];
let cfgs = &task_.cfgs;
let free = &task.free_queue; let free = &task.free_queue;
let level = task_.args.priority; let level = task_.args.priority;
let dispatcher = &ctxt.dispatchers[&level]; let dispatcher = &ctxt.dispatchers[&level];
@ -1328,6 +1455,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
items.push(quote!( items.push(quote!(
#[inline(always)] #[inline(always)]
#(#cfgs)*
unsafe fn #alias( unsafe fn #alias(
#baseline_arg #baseline_arg
#priority: &core::cell::Cell<u8>, #priority: &core::cell::Cell<u8>,
@ -1366,8 +1494,10 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
let mut methods = vec![]; let mut methods = vec![];
for task in spawn { for task in spawn {
let task_ = &app.tasks[task];
let alias = &ctxt.tasks[task].spawn_fn; let alias = &ctxt.tasks[task].spawn_fn;
let inputs = &app.tasks[task].inputs; let inputs = &task_.inputs;
let cfgs = &task_.cfgs;
let ty = tuple_ty(inputs); let ty = tuple_ty(inputs);
let pats = tuple_pat(inputs); let pats = tuple_pat(inputs);
@ -1386,6 +1516,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
methods.push(quote!( methods.push(quote!(
#[allow(unsafe_code)] #[allow(unsafe_code)]
#[inline] #[inline]
#(#cfgs)*
pub fn #task(&self, #(#inputs,)*) -> Result<(), #ty> { pub fn #task(&self, #(#inputs,)*) -> Result<(), #ty> {
unsafe { #alias(#instant &self.#priority, #pats) } unsafe { #alias(#instant &self.#priority, #pats) }
} }
@ -1415,12 +1546,15 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream {
let enum_ = &ctxt.schedule_enum; let enum_ = &ctxt.schedule_enum;
let inputs = &task_.inputs; let inputs = &task_.inputs;
let scheduleds = &task_.scheduleds; let scheduleds = &task_.scheduleds;
let args = &app.tasks[task].inputs; let task__ = &app.tasks[task];
let args = &task__.inputs;
let cfgs = &task__.cfgs;
let ty = tuple_ty(args); let ty = tuple_ty(args);
let pats = tuple_pat(args); let pats = tuple_pat(args);
items.push(quote!( items.push(quote!(
#[inline(always)] #[inline(always)]
#(#cfgs)*
unsafe fn #alias( unsafe fn #alias(
#priority: &core::cell::Cell<u8>, #priority: &core::cell::Cell<u8>,
instant: rtfm::Instant, instant: rtfm::Instant,
@ -1464,12 +1598,15 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream {
let mut methods = vec![]; let mut methods = vec![];
for task in schedule { for task in schedule {
let alias = &ctxt.schedule_fn[task]; let alias = &ctxt.schedule_fn[task];
let inputs = &app.tasks[task].inputs; let task_ = &app.tasks[task];
let inputs = &task_.inputs;
let cfgs = &task_.cfgs;
let ty = tuple_ty(inputs); let ty = tuple_ty(inputs);
let pats = tuple_pat(inputs); let pats = tuple_pat(inputs);
methods.push(quote!( methods.push(quote!(
#[inline] #[inline]
#(#cfgs)*
pub fn #task( pub fn #task(
&self, &self,
instant: rtfm::Instant, instant: rtfm::Instant,
@ -1499,12 +1636,22 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T
let mut items = vec![]; let mut items = vec![];
let variants = tasks
.iter()
.map(|task| {
let cfgs = &app.tasks[task].cfgs;
quote!(
#(#cfgs)*
#task
)
})
.collect::<Vec<_>>();
let enum_ = &ctxt.schedule_enum; let enum_ = &ctxt.schedule_enum;
items.push(quote!( items.push(quote!(
#[allow(dead_code)] #[allow(dead_code)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum #enum_ { #(#tasks,)* } enum #enum_ { #(#variants,)* }
)); ));
let cap = mk_typenum_capacity(analysis.timer_queue.capacity, false); let cap = mk_typenum_capacity(analysis.timer_queue.capacity, false);
@ -1519,6 +1666,7 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T
items.push(mk_resource( items.push(mk_resource(
ctxt, ctxt,
&[],
tq, tq,
quote!(rtfm::export::TimerQueue<#enum_, #cap>), quote!(rtfm::export::TimerQueue<#enum_, #cap>),
analysis.timer_queue.ceiling, analysis.timer_queue.ceiling,
@ -1532,13 +1680,16 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T
let arms = tasks let arms = tasks
.iter() .iter()
.map(|task| { .map(|task| {
let level = app.tasks[task].args.priority; let task_ = &app.tasks[task];
let level = task_.args.priority;
let cfgs = &task_.cfgs;
let dispatcher_ = &ctxt.dispatchers[&level]; let dispatcher_ = &ctxt.dispatchers[&level];
let tenum = &dispatcher_.enum_; let tenum = &dispatcher_.enum_;
let ready = &dispatcher_.ready_queue; let ready = &dispatcher_.ready_queue;
let dispatcher = &analysis.dispatchers[&level].interrupt; let dispatcher = &analysis.dispatchers[&level].interrupt;
quote!( quote!(
#(#cfgs)*
#enum_::#task => { #enum_::#task => {
(#ready { #priority }).lock(|rq| { (#ready { #priority }).lock(|rq| {
rq.split().0.enqueue_unchecked((#tenum::#task, index)) rq.split().0.enqueue_unchecked((#tenum::#task, index))
@ -1551,10 +1702,11 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let logical_prio = analysis.timer_queue.priority; let logical_prio = analysis.timer_queue.priority;
let alias = mk_ident(None);
items.push(quote!( items.push(quote!(
#[rtfm::export::exception] #[export_name = "SysTick"]
#[doc(hidden)] #[doc(hidden)]
unsafe fn SysTick() { unsafe fn #alias() {
use rtfm::Mutex; use rtfm::Mutex;
let ref #priority = core::cell::Cell::new(#logical_prio); let ref #priority = core::cell::Cell::new(#logical_prio);
@ -1680,6 +1832,7 @@ fn assertions(app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
fn mk_resource( fn mk_resource(
ctxt: &Context, ctxt: &Context,
cfgs: &[Attribute],
struct_: &Ident, struct_: &Ident,
ty: proc_macro2::TokenStream, ty: proc_macro2::TokenStream,
ceiling: u8, ceiling: u8,
@ -1696,6 +1849,7 @@ fn mk_resource(
let doc = format!("`{}`", ty); let doc = format!("`{}`", ty);
module.push(quote!( module.push(quote!(
#[doc = #doc] #[doc = #doc]
#(#cfgs)*
pub struct #struct_<'a> { pub struct #struct_<'a> {
#[doc(hidden)] #[doc(hidden)]
pub #priority: &'a core::cell::Cell<u8>, pub #priority: &'a core::cell::Cell<u8>,
@ -1705,6 +1859,7 @@ fn mk_resource(
quote!(resources::#struct_) quote!(resources::#struct_)
} else { } else {
items.push(quote!( items.push(quote!(
#(#cfgs)*
struct #struct_<'a> { struct #struct_<'a> {
#priority: &'a core::cell::Cell<u8>, #priority: &'a core::cell::Cell<u8>,
} }
@ -1714,6 +1869,7 @@ fn mk_resource(
}; };
items.push(quote!( items.push(quote!(
#(#cfgs)*
impl<'a> rtfm::Mutex for #path<'a> { impl<'a> rtfm::Mutex for #path<'a> {
type T = #ty; type T = #ty;
@ -1852,7 +2008,7 @@ fn tuple_ty(inputs: &[ArgCaptured]) -> proc_macro2::TokenStream {
} }
} }
#[derive(Clone, Eq, Hash, PartialEq)] #[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum Kind { enum Kind {
Exception(Ident), Exception(Ident),
Idle, Idle,

View file

@ -1,11 +1,7 @@
// #![deny(warnings)] #![deny(warnings)]
#![recursion_limit = "128"] #![recursion_limit = "128"]
extern crate proc_macro; extern crate proc_macro;
extern crate proc_macro2;
extern crate quote;
extern crate rand;
extern crate syn;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use syn::parse_macro_input; use syn::parse_macro_input;
@ -308,5 +304,5 @@ pub fn app(args: TokenStream, input: TokenStream) -> TokenStream {
let analysis = analyze::app(&app); let analysis = analyze::app(&app);
// Code generation // Code generation
codegen::app(&app, &analysis) codegen::app(&app, &analysis).into()
} }

View file

@ -20,7 +20,7 @@ pub struct AppArgs {
} }
impl Parse for AppArgs { impl Parse for AppArgs {
fn parse(input: ParseStream) -> parse::Result<Self> { fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
let mut device = None; let mut device = None;
loop { loop {
if input.is_empty() { if input.is_empty() {
@ -47,7 +47,7 @@ impl Parse for AppArgs {
return Err(parse::Error::new( return Err(parse::Error::new(
ident.span(), ident.span(),
"expected `device`; other keys are not accepted", "expected `device`; other keys are not accepted",
)) ));
} }
} }
@ -80,8 +80,8 @@ pub struct Input {
} }
impl Parse for Input { impl Parse for Input {
fn parse(input: ParseStream) -> parse::Result<Self> { fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
fn parse_items(input: ParseStream) -> parse::Result<Vec<Item>> { fn parse_items(input: ParseStream<'_>) -> parse::Result<Vec<Item>> {
let mut items = vec![]; let mut items = vec![];
while !input.is_empty() { while !input.is_empty() {
@ -228,7 +228,7 @@ impl App {
return Err(parse::Error::new( return Err(parse::Error::new(
item.span(), item.span(),
"this item must live outside the `#[app]` module", "this item must live outside the `#[app]` module",
)) ));
} }
} }
} }
@ -254,7 +254,7 @@ impl App {
pub fn resource_accesses(&self) -> impl Iterator<Item = (u8, &Ident)> { pub fn resource_accesses(&self) -> impl Iterator<Item = (u8, &Ident)> {
self.idle self.idle
.as_ref() .as_ref()
.map(|idle| -> Box<Iterator<Item = _>> { .map(|idle| -> Box<dyn Iterator<Item = _>> {
Box::new(idle.args.resources.iter().map(|res| (0, res))) Box::new(idle.args.resources.iter().map(|res| (0, res)))
}) })
.unwrap_or_else(|| Box::new(iter::empty())) .unwrap_or_else(|| Box::new(iter::empty()))
@ -293,7 +293,7 @@ impl App {
.chain( .chain(
self.idle self.idle
.as_ref() .as_ref()
.map(|idle| -> Box<Iterator<Item = _>> { .map(|idle| -> Box<dyn Iterator<Item = _>> {
Box::new(idle.args.spawn.iter().map(|s| (Some(0), s))) Box::new(idle.args.spawn.iter().map(|s| (Some(0), s)))
}) })
.unwrap_or_else(|| Box::new(iter::empty())), .unwrap_or_else(|| Box::new(iter::empty())),
@ -329,7 +329,7 @@ impl App {
.chain( .chain(
self.idle self.idle
.as_ref() .as_ref()
.map(|idle| -> Box<Iterator<Item = _>> { .map(|idle| -> Box<dyn Iterator<Item = _>> {
Box::new(idle.args.schedule.iter().map(|s| (Some(0), s))) Box::new(idle.args.schedule.iter().map(|s| (Some(0), s)))
}) })
.unwrap_or_else(|| Box::new(iter::empty())), .unwrap_or_else(|| Box::new(iter::empty())),
@ -358,7 +358,7 @@ impl App {
pub fn schedule_callers(&self) -> impl Iterator<Item = (Ident, &Idents)> { pub fn schedule_callers(&self) -> impl Iterator<Item = (Ident, &Idents)> {
self.idle self.idle
.as_ref() .as_ref()
.map(|idle| -> Box<Iterator<Item = _>> { .map(|idle| -> Box<dyn Iterator<Item = _>> {
Box::new(iter::once(( Box::new(iter::once((
Ident::new("idle", Span::call_site()), Ident::new("idle", Span::call_site()),
&idle.args.schedule, &idle.args.schedule,
@ -389,7 +389,7 @@ impl App {
pub fn spawn_callers(&self) -> impl Iterator<Item = (Ident, &Idents)> { pub fn spawn_callers(&self) -> impl Iterator<Item = (Ident, &Idents)> {
self.idle self.idle
.as_ref() .as_ref()
.map(|idle| -> Box<Iterator<Item = _>> { .map(|idle| -> Box<dyn Iterator<Item = _>> {
Box::new(iter::once(( Box::new(iter::once((
Ident::new("idle", Span::call_site()), Ident::new("idle", Span::call_site()),
&idle.args.spawn, &idle.args.spawn,
@ -492,7 +492,7 @@ impl Default for InitArgs {
} }
impl Parse for InitArgs { impl Parse for InitArgs {
fn parse(input: ParseStream) -> parse::Result<InitArgs> { fn parse(input: ParseStream<'_>) -> parse::Result<InitArgs> {
if input.is_empty() { if input.is_empty() {
return Ok(InitArgs::default()); return Ok(InitArgs::default());
} }
@ -526,7 +526,7 @@ impl Parse for InitArgs {
return Err(parse::Error::new( return Err(parse::Error::new(
ident.span(), ident.span(),
"expected one of: resources, schedule or spawn", "expected one of: resources, schedule or spawn",
)) ));
} }
} }
@ -597,6 +597,7 @@ impl Parse for InitArgs {
} }
pub struct Assign { pub struct Assign {
pub attrs: Vec<Attribute>,
pub left: Ident, pub left: Ident,
pub right: Box<Expr>, pub right: Box<Expr>,
} }
@ -649,7 +650,7 @@ pub struct Exception {
pub args: ExceptionArgs, pub args: ExceptionArgs,
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub unsafety: Option<Token![unsafe]>, pub unsafety: Option<Token![unsafe]>,
pub statics: Statics, pub statics: HashMap<Ident, Static>,
pub stmts: Vec<Stmt>, pub stmts: Vec<Stmt>,
} }
@ -661,7 +662,7 @@ pub struct ExceptionArgs {
} }
impl Parse for ExceptionArgs { impl Parse for ExceptionArgs {
fn parse(input: ParseStream) -> parse::Result<Self> { fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
parse_args(input, false).map( parse_args(input, false).map(
|TaskArgs { |TaskArgs {
priority, priority,
@ -727,7 +728,7 @@ impl Exception {
args, args,
attrs: item.attrs, attrs: item.attrs,
unsafety: item.unsafety, unsafety: item.unsafety,
statics, statics: Static::parse(statics)?,
stmts, stmts,
}) })
} }
@ -737,7 +738,7 @@ pub struct Interrupt {
pub args: InterruptArgs, pub args: InterruptArgs,
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub unsafety: Option<Token![unsafe]>, pub unsafety: Option<Token![unsafe]>,
pub statics: Statics, pub statics: HashMap<Ident, Static>,
pub stmts: Vec<Stmt>, pub stmts: Vec<Stmt>,
} }
@ -780,7 +781,7 @@ impl Interrupt {
args, args,
attrs: item.attrs, attrs: item.attrs,
unsafety: item.unsafety, unsafety: item.unsafety,
statics, statics: Static::parse(statics)?,
stmts, stmts,
}) })
} }
@ -788,6 +789,7 @@ impl Interrupt {
pub struct Resource { pub struct Resource {
pub singleton: bool, pub singleton: bool,
pub cfgs: Vec<Attribute>,
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub mutability: Option<Token![mut]>, pub mutability: Option<Token![mut]>,
pub ty: Box<Type>, pub ty: Box<Type>,
@ -817,9 +819,12 @@ impl Resource {
); );
} }
let (cfgs, attrs) = extract_cfgs(item.attrs);
Ok(Resource { Ok(Resource {
singleton: pos.is_some(), singleton: pos.is_some(),
attrs: item.attrs, cfgs,
attrs,
mutability: item.mutability, mutability: item.mutability,
ty: item.ty, ty: item.ty,
expr: if uninitialized { None } else { Some(item.expr) }, expr: if uninitialized { None } else { Some(item.expr) },
@ -848,13 +853,13 @@ impl Default for TaskArgs {
} }
impl Parse for TaskArgs { impl Parse for TaskArgs {
fn parse(input: ParseStream) -> parse::Result<Self> { fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
parse_args(input, true) parse_args(input, true)
} }
} }
// Parser shared by TaskArgs and ExceptionArgs / InterruptArgs // Parser shared by TaskArgs and ExceptionArgs / InterruptArgs
fn parse_args(input: ParseStream, accept_capacity: bool) -> parse::Result<TaskArgs> { fn parse_args(input: ParseStream<'_>, accept_capacity: bool) -> parse::Result<TaskArgs> {
if input.is_empty() { if input.is_empty() {
return Ok(TaskArgs::default()); return Ok(TaskArgs::default());
} }
@ -981,7 +986,7 @@ fn parse_args(input: ParseStream, accept_capacity: bool) -> parse::Result<TaskAr
return Err(parse::Error::new( return Err(parse::Error::new(
ident.span(), ident.span(),
"expected one of: priority, resources, schedule or spawn", "expected one of: priority, resources, schedule or spawn",
)) ));
} }
} }
@ -1042,6 +1047,7 @@ impl Static {
pub struct Task { pub struct Task {
pub args: TaskArgs, pub args: TaskArgs,
pub cfgs: Vec<Attribute>,
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub unsafety: Option<Token![unsafe]>, pub unsafety: Option<Token![unsafe]>,
pub inputs: Vec<ArgCaptured>, pub inputs: Vec<ArgCaptured>,
@ -1093,9 +1099,11 @@ impl Task {
_ => {} _ => {}
} }
let (cfgs, attrs) = extract_cfgs(item.attrs);
Ok(Task { Ok(Task {
args, args,
attrs: item.attrs, cfgs,
attrs,
unsafety: item.unsafety, unsafety: item.unsafety,
inputs, inputs,
statics: Static::parse(statics)?, statics: Static::parse(statics)?,
@ -1210,6 +1218,7 @@ fn extract_assignments(stmts: Vec<Stmt>) -> (Vec<Stmt>, Vec<Assign>) {
if let Expr::Path(ref expr) = *assign.left { if let Expr::Path(ref expr) = *assign.left {
if expr.path.segments.len() == 1 { if expr.path.segments.len() == 1 {
assigns.push(Assign { assigns.push(Assign {
attrs: assign.attrs,
left: expr.path.segments[0].ident.clone(), left: expr.path.segments[0].ident.clone(),
right: assign.right, right: assign.right,
}); });

View file

@ -10,7 +10,6 @@ pub use cortex_m::{
asm::wfi, interrupt, peripheral::scb::SystemHandler, peripheral::syst::SystClkSource, asm::wfi, interrupt, peripheral::scb::SystemHandler, peripheral::syst::SystClkSource,
peripheral::Peripherals, peripheral::Peripherals,
}; };
pub use cortex_m_rt::{entry, exception};
pub use heapless::consts; pub use heapless::consts;
use heapless::spsc::{Queue, SingleCore}; use heapless::spsc::{Queue, SingleCore};

View file

@ -295,7 +295,7 @@ impl<'a, T> fmt::Debug for Exclusive<'a, T>
where where
T: fmt::Debug, T: fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f) (**self).fmt(f)
} }
} }
@ -304,7 +304,7 @@ impl<'a, T> fmt::Display for Exclusive<'a, T>
where where
T: fmt::Display, T: fmt::Display,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f) (**self).fmt(f)
} }
} }

View file

@ -0,0 +1,64 @@
#![no_main]
#![no_std]
extern crate lm3s6965;
extern crate panic_halt;
extern crate rtfm;
use rtfm::app;
#[app(device = lm3s6965)]
const APP: () = {
#[cfg(never)]
static mut O1: u32 = 0; // init
#[cfg(never)]
static mut O2: u32 = 0; // idle
#[cfg(never)]
static mut O3: u32 = 0; // EXTI0
#[cfg(never)]
static O4: u32 = 0; // idle
#[cfg(never)]
static O5: u32 = 0; // EXTI1
#[cfg(never)]
static O6: u32 = 0; // init
#[cfg(never)]
static mut S1: u32 = 0; // idle & EXTI0
#[cfg(never)]
static mut S2: u32 = 0; // EXTI0 & EXTI1
#[cfg(never)]
static S3: u32 = 0;
#[init(resources = [O1, O4, O5, O6, S3])]
fn init() {
resources.O1; //~ ERROR no field `O1`
resources.O4; //~ ERROR no field `O4`
resources.O5; //~ ERROR no field `O5`
resources.O6; //~ ERROR no field `O6`
resources.S3; //~ ERROR no field `S3`
}
#[idle(resources = [O2, O4, S1, S3])]
fn idle() -> ! {
resources.O2; //~ ERROR no field `O2`
resources.O4; //~ ERROR no field `O4`
resources.S1; //~ ERROR no field `S1`
resources.S3; //~ ERROR no field `S3`
loop {}
}
#[interrupt(resources = [O3, S1, S2, S3])]
fn UART0() {
resources.O3; //~ ERROR no field `O3`
resources.S1; //~ ERROR no field `S1`
resources.S2; //~ ERROR no field `S2`
resources.S3; //~ ERROR no field `S3`
}
#[interrupt(resources = [S2, O5])]
fn UART1() {
resources.S2; //~ ERROR no field `S2`
resources.O5; //~ ERROR no field `O5`
}
};

57
tests/cfail/cfg-static.rs Normal file
View file

@ -0,0 +1,57 @@
#![no_main]
#![no_std]
extern crate lm3s6965;
extern crate panic_halt;
extern crate rtfm;
use rtfm::app;
#[app(device = lm3s6965)]
const APP: () = {
#[init]
fn init() {
#[cfg(never)]
static mut FOO: u32 = 0;
FOO; //~ ERROR cannot find value `FOO` in this scope
}
#[idle]
fn idle() -> ! {
#[cfg(never)]
static mut FOO: u32 = 0;
FOO; //~ ERROR cannot find value `FOO` in this scope
loop {}
}
#[exception]
fn SVCall() {
#[cfg(never)]
static mut FOO: u32 = 0;
FOO; //~ ERROR cannot find value `FOO` in this scope
}
#[interrupt]
fn UART0() {
#[cfg(never)]
static mut FOO: u32 = 0;
FOO; //~ ERROR cannot find value `FOO` in this scope
}
#[task]
fn foo() {
#[cfg(never)]
static mut FOO: u32 = 0;
FOO; //~ ERROR cannot find value `FOO` in this scope
}
extern "C" {
fn UART1();
}
};

53
tests/cpass/cfg.rs Normal file
View file

@ -0,0 +1,53 @@
//! Compile-pass test that checks that `#[cfg]` attributes are respected
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
extern crate lm3s6965;
extern crate panic_semihosting;
extern crate rtfm;
use rtfm::app;
#[app(device = lm3s6965)]
const APP: () = {
#[cfg(never)]
static mut FOO: u32 = 0;
#[init]
fn init() {
#[cfg(never)]
static mut BAR: u32 = 0;
}
#[idle]
fn idle() -> ! {
#[cfg(never)]
static mut BAR: u32 = 0;
loop {}
}
#[task(resources = [FOO], schedule = [quux], spawn = [quux])]
fn foo() {
#[cfg(never)]
static mut BAR: u32 = 0;
}
#[task(priority = 3, resources = [FOO], schedule = [quux], spawn = [quux])]
fn bar() {
#[cfg(never)]
static mut BAR: u32 = 0;
}
#[cfg(never)]
#[task]
fn quux() {}
extern "C" {
fn UART0();
fn UART1();
}
};