466: Fix for type aliases in `mod app`, UB in `spawn_at`, and `#[cfg]` in hardware tasks r=AfoHT a=korken89

Type aliases such as the following did not work in `0.6-alpha`:

```rust
use rtic::app;

#[app(device = lm3s6965, dispatchers = [SSI0])]
mod app {
    type Test = u32;

    #[task]
    fn t1(_: t1::Context, _val: Test) {}
}
```

Plus that accessing associated constants of monotonic timers was not working as it should dues to the syntax and codegen transforming:

```rust
    #[monotonic(binds = SysTick, default = true)]
    type MyMono = DwtSystick<8_000_000>; // 8 MHz
```

into

```rust
    mod MyMono {
        // ...
    }
```

causing the original `type MyMono` to not exist anymore.

This PR fixes this and adds test to check for this by doing the following expansion instead:

 ```rust
    #[monotonic(binds = SysTick, default = true)]
    type MyMono = DwtSystick<8_000_000>; // 8 MHz
```

into

```rust
    type MyMono = DwtSystick<8_000_000>;

    mod monotonics {
        mod MyMono {
            // ...
        }

        // And other monotonics go here as well
    }
```

**Breaking change**

This causes a breaking change in accessing the `MyMono::now()` method which now exists under `monotonics::MyMono::now()`.

---

Moreover a UB issue was found and fixed in `spawn_at` and hardware tasks properly propagate `#[cfg]`s.

Closes #460
Closes #462
Closes #463

Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
This commit is contained in:
bors[bot] 2021-04-08 08:15:05 +00:00 committed by GitHub
commit 83cdf00eec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 75 additions and 39 deletions

View file

@ -26,24 +26,27 @@ mod app {
// Task without message passing // Task without message passing
// Not default // Not default
let _: Result<foo::MyMono::SpawnHandle, ()> = foo::MyMono::spawn_at(MyMono::now()); let _: Result<foo::MyMono::SpawnHandle, ()> =
foo::MyMono::spawn_at(monotonics::MyMono::now());
let handle: Result<foo::MyMono::SpawnHandle, ()> = foo::MyMono::spawn_after(Seconds(1_u32)); let handle: Result<foo::MyMono::SpawnHandle, ()> = foo::MyMono::spawn_after(Seconds(1_u32));
let _: Result<foo::MyMono::SpawnHandle, ()> = let _: Result<foo::MyMono::SpawnHandle, ()> =
handle.unwrap().reschedule_after(Seconds(1_u32)); handle.unwrap().reschedule_after(Seconds(1_u32));
let handle: Result<foo::MyMono::SpawnHandle, ()> = foo::MyMono::spawn_after(Seconds(1_u32)); let handle: Result<foo::MyMono::SpawnHandle, ()> = foo::MyMono::spawn_after(Seconds(1_u32));
let _: Result<foo::MyMono::SpawnHandle, ()> = handle.unwrap().reschedule_at(MyMono::now()); let _: Result<foo::MyMono::SpawnHandle, ()> =
handle.unwrap().reschedule_at(monotonics::MyMono::now());
let handle: Result<foo::MyMono::SpawnHandle, ()> = foo::MyMono::spawn_after(Seconds(1_u32)); let handle: Result<foo::MyMono::SpawnHandle, ()> = foo::MyMono::spawn_after(Seconds(1_u32));
let _: Result<(), ()> = handle.unwrap().cancel(); let _: Result<(), ()> = handle.unwrap().cancel();
// Using default // Using default
let _: Result<foo::SpawnHandle, ()> = foo::spawn_at(MyMono::now()); let _: Result<foo::SpawnHandle, ()> = foo::spawn_at(monotonics::MyMono::now());
let handle: Result<foo::SpawnHandle, ()> = foo::spawn_after(Seconds(1_u32)); let handle: Result<foo::SpawnHandle, ()> = foo::spawn_after(Seconds(1_u32));
let _: Result<foo::SpawnHandle, ()> = handle.unwrap().reschedule_after(Seconds(1_u32)); let _: Result<foo::SpawnHandle, ()> = handle.unwrap().reschedule_after(Seconds(1_u32));
let handle: Result<foo::SpawnHandle, ()> = foo::spawn_after(Seconds(1_u32)); let handle: Result<foo::SpawnHandle, ()> = foo::spawn_after(Seconds(1_u32));
let _: Result<foo::SpawnHandle, ()> = handle.unwrap().reschedule_at(MyMono::now()); let _: Result<foo::SpawnHandle, ()> =
handle.unwrap().reschedule_at(monotonics::MyMono::now());
let handle: Result<foo::SpawnHandle, ()> = foo::spawn_after(Seconds(1_u32)); let handle: Result<foo::SpawnHandle, ()> = foo::spawn_after(Seconds(1_u32));
let _: Result<(), ()> = handle.unwrap().cancel(); let _: Result<(), ()> = handle.unwrap().cancel();
@ -51,7 +54,8 @@ mod app {
// Task with single message passing // Task with single message passing
// Not default // Not default
let _: Result<bar::MyMono::SpawnHandle, u32> = bar::MyMono::spawn_at(MyMono::now(), 0); let _: Result<bar::MyMono::SpawnHandle, u32> =
bar::MyMono::spawn_at(monotonics::MyMono::now(), 0);
let handle: Result<bar::MyMono::SpawnHandle, u32> = let handle: Result<bar::MyMono::SpawnHandle, u32> =
bar::MyMono::spawn_after(Seconds(1_u32), 0); bar::MyMono::spawn_after(Seconds(1_u32), 0);
let _: Result<bar::MyMono::SpawnHandle, ()> = let _: Result<bar::MyMono::SpawnHandle, ()> =
@ -59,19 +63,21 @@ mod app {
let handle: Result<bar::MyMono::SpawnHandle, u32> = let handle: Result<bar::MyMono::SpawnHandle, u32> =
bar::MyMono::spawn_after(Seconds(1_u32), 0); bar::MyMono::spawn_after(Seconds(1_u32), 0);
let _: Result<bar::MyMono::SpawnHandle, ()> = handle.unwrap().reschedule_at(MyMono::now()); let _: Result<bar::MyMono::SpawnHandle, ()> =
handle.unwrap().reschedule_at(monotonics::MyMono::now());
let handle: Result<bar::MyMono::SpawnHandle, u32> = let handle: Result<bar::MyMono::SpawnHandle, u32> =
bar::MyMono::spawn_after(Seconds(1_u32), 0); bar::MyMono::spawn_after(Seconds(1_u32), 0);
let _: Result<u32, ()> = handle.unwrap().cancel(); let _: Result<u32, ()> = handle.unwrap().cancel();
// Using default // Using default
let _: Result<bar::SpawnHandle, u32> = bar::spawn_at(MyMono::now(), 0); let _: Result<bar::SpawnHandle, u32> = bar::spawn_at(monotonics::MyMono::now(), 0);
let handle: Result<bar::SpawnHandle, u32> = bar::spawn_after(Seconds(1_u32), 0); let handle: Result<bar::SpawnHandle, u32> = bar::spawn_after(Seconds(1_u32), 0);
let _: Result<bar::SpawnHandle, ()> = handle.unwrap().reschedule_after(Seconds(1_u32)); let _: Result<bar::SpawnHandle, ()> = handle.unwrap().reschedule_after(Seconds(1_u32));
let handle: Result<bar::SpawnHandle, u32> = bar::spawn_after(Seconds(1_u32), 0); let handle: Result<bar::SpawnHandle, u32> = bar::spawn_after(Seconds(1_u32), 0);
let _: Result<bar::SpawnHandle, ()> = handle.unwrap().reschedule_at(MyMono::now()); let _: Result<bar::SpawnHandle, ()> =
handle.unwrap().reschedule_at(monotonics::MyMono::now());
let handle: Result<bar::SpawnHandle, u32> = bar::spawn_after(Seconds(1_u32), 0); let handle: Result<bar::SpawnHandle, u32> = bar::spawn_after(Seconds(1_u32), 0);
let _: Result<u32, ()> = handle.unwrap().cancel(); let _: Result<u32, ()> = handle.unwrap().cancel();
@ -80,7 +86,7 @@ mod app {
// Not default // Not default
let _: Result<baz::MyMono::SpawnHandle, (u32, u32)> = let _: Result<baz::MyMono::SpawnHandle, (u32, u32)> =
baz::MyMono::spawn_at(MyMono::now(), 0, 1); baz::MyMono::spawn_at(monotonics::MyMono::now(), 0, 1);
let handle: Result<baz::MyMono::SpawnHandle, (u32, u32)> = let handle: Result<baz::MyMono::SpawnHandle, (u32, u32)> =
baz::MyMono::spawn_after(Seconds(1_u32), 0, 1); baz::MyMono::spawn_after(Seconds(1_u32), 0, 1);
let _: Result<baz::MyMono::SpawnHandle, ()> = let _: Result<baz::MyMono::SpawnHandle, ()> =
@ -88,19 +94,22 @@ mod app {
let handle: Result<baz::MyMono::SpawnHandle, (u32, u32)> = let handle: Result<baz::MyMono::SpawnHandle, (u32, u32)> =
baz::MyMono::spawn_after(Seconds(1_u32), 0, 1); baz::MyMono::spawn_after(Seconds(1_u32), 0, 1);
let _: Result<baz::MyMono::SpawnHandle, ()> = handle.unwrap().reschedule_at(MyMono::now()); let _: Result<baz::MyMono::SpawnHandle, ()> =
handle.unwrap().reschedule_at(monotonics::MyMono::now());
let handle: Result<baz::MyMono::SpawnHandle, (u32, u32)> = let handle: Result<baz::MyMono::SpawnHandle, (u32, u32)> =
baz::MyMono::spawn_after(Seconds(1_u32), 0, 1); baz::MyMono::spawn_after(Seconds(1_u32), 0, 1);
let _: Result<(u32, u32), ()> = handle.unwrap().cancel(); let _: Result<(u32, u32), ()> = handle.unwrap().cancel();
// Using default // Using default
let _: Result<baz::SpawnHandle, (u32, u32)> = baz::spawn_at(MyMono::now(), 0, 1); let _: Result<baz::SpawnHandle, (u32, u32)> =
baz::spawn_at(monotonics::MyMono::now(), 0, 1);
let handle: Result<baz::SpawnHandle, (u32, u32)> = baz::spawn_after(Seconds(1_u32), 0, 1); let handle: Result<baz::SpawnHandle, (u32, u32)> = baz::spawn_after(Seconds(1_u32), 0, 1);
let _: Result<baz::SpawnHandle, ()> = handle.unwrap().reschedule_after(Seconds(1_u32)); let _: Result<baz::SpawnHandle, ()> = handle.unwrap().reschedule_after(Seconds(1_u32));
let handle: Result<baz::SpawnHandle, (u32, u32)> = baz::spawn_after(Seconds(1_u32), 0, 1); let handle: Result<baz::SpawnHandle, (u32, u32)> = baz::spawn_after(Seconds(1_u32), 0, 1);
let _: Result<baz::SpawnHandle, ()> = handle.unwrap().reschedule_at(MyMono::now()); let _: Result<baz::SpawnHandle, ()> =
handle.unwrap().reschedule_at(monotonics::MyMono::now());
let handle: Result<baz::SpawnHandle, (u32, u32)> = baz::spawn_after(Seconds(1_u32), 0, 1); let handle: Result<baz::SpawnHandle, (u32, u32)> = baz::spawn_after(Seconds(1_u32), 0, 1);
let _: Result<(u32, u32), ()> = handle.unwrap().cancel(); let _: Result<(u32, u32), ()> = handle.unwrap().cancel();

15
examples/type-usage.rs Normal file
View file

@ -0,0 +1,15 @@
//! examples/type-usage.rs
#![no_main]
#![no_std]
use panic_semihosting as _; // panic handler
use rtic::app;
#[app(device = lm3s6965, dispatchers = [SSI0])]
mod app {
type Test = u32;
#[task]
fn t1(_: t1::Context, _val: Test) {}
}

View file

@ -22,5 +22,4 @@ proc-macro2 = "1"
proc-macro-error = "1" proc-macro-error = "1"
quote = "1" quote = "1"
syn = "1" syn = "1"
rtic-syntax = "0.5.0-alpha.1" rtic-syntax = "0.5.0-alpha.2"

View file

@ -112,8 +112,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
let user_imports = &app.user_imports; let user_imports = &app.user_imports;
quote! { quote! {
pub use rtic::Monotonic as _;
#[doc = #doc] #[doc = #doc]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub mod #name { pub mod #name {
@ -143,6 +141,18 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
}) })
.collect(); .collect();
let monotonics = if !monotonic_parts.is_empty() {
quote!(
pub use rtic::Monotonic as _;
/// Holds static methods for each monotonic.
pub mod monotonics {
#(#monotonic_parts)*
}
)
} else {
quote!()
};
let rt_err = util::rt_err_ident(); let rt_err = util::rt_err_ident();
quote!( quote!(
@ -151,7 +161,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
/// Always include the device crate which contains the vector table /// Always include the device crate which contains the vector table
use #device as #rt_err; use #device as #rt_err;
#(#monotonic_parts)* #monotonics
#(#user_imports)* #(#user_imports)*

View file

@ -37,12 +37,16 @@ pub fn codegen(
let symbol = task.args.binds.clone(); let symbol = task.args.binds.clone();
let priority = task.args.priority; let priority = task.args.priority;
let cfgs = &task.cfgs;
let attrs = &task.attrs;
let app_name = &app.name; let app_name = &app.name;
let app_path = quote! {crate::#app_name}; let app_path = quote! {crate::#app_name};
mod_app.push(quote!( mod_app.push(quote!(
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[no_mangle] #[no_mangle]
#(#attrs)*
#(#cfgs)*
unsafe fn #symbol() { unsafe fn #symbol() {
const PRIORITY: u8 = #priority; const PRIORITY: u8 = #priority;

View file

@ -21,7 +21,7 @@ pub fn codegen(
let app_name = &app.name; let app_name = &app.name;
let app_path = quote! {crate::#app_name}; let app_path = quote! {crate::#app_name};
let all_task_names: Vec<_> = app let all_task_imports: Vec<_> = app
.software_tasks .software_tasks
.iter() .iter()
.map(|(name, st)| { .map(|(name, st)| {
@ -46,6 +46,13 @@ pub fn codegen(
quote!() quote!()
} }
})) }))
.chain(app.user_types.iter().map(|ty| {
let t = &ty.ident;
quote! {
#[allow(unused_imports)]
use super::#t;
}
}))
.collect(); .collect();
let mut lt = None; let mut lt = None;
@ -230,7 +237,7 @@ pub fn codegen(
// Spawn caller // Spawn caller
items.push(quote!( items.push(quote!(
#(#all_task_names)* #(#all_task_imports)*
#(#cfgs)* #(#cfgs)*
/// Spawns the task directly /// Spawns the task directly
@ -268,7 +275,7 @@ pub fn codegen(
let tq = util::mark_internal_ident(&tq); let tq = util::mark_internal_ident(&tq);
let t = util::schedule_t_ident(); let t = util::schedule_t_ident();
let m = &monotonic.ident; let m = &monotonic.ident;
let mono_type = &monotonic.ty; let mono_type = &monotonic.ident;
let m_ident = util::monotonic_ident(&monotonic_name); let m_ident = util::monotonic_ident(&monotonic_name);
let m_ident = util::mark_internal_ident(&m_ident); let m_ident = util::mark_internal_ident(&m_ident);
let m_isr = &monotonic.args.binds; let m_isr = &monotonic.args.binds;
@ -300,10 +307,6 @@ pub fn codegen(
items.push(quote!( items.push(quote!(
/// Holds methods related to this monotonic /// Holds methods related to this monotonic
pub mod #m { pub mod #m {
// #(
// #[allow(unused_imports)]
// use #app_path::#all_task_names as #all_task_names;
// )*
use super::*; use super::*;
#[allow(unused_imports)] #[allow(unused_imports)]
use #app_path::#tq_marker; use #app_path::#tq_marker;
@ -341,7 +344,7 @@ pub fn codegen(
where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint, where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>, D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
{ {
self.reschedule_at(#app_path::#m::now() + duration) self.reschedule_at(#app_path::monotonics::#m::now() + duration)
} }
pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result<Self, ()> pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result<Self, ()>
@ -373,7 +376,7 @@ pub fn codegen(
let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.is_none() }) { let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.is_none() }) {
rtic::time::Instant::new(0) rtic::time::Instant::new(0)
} else { } else {
#app_path::#m::now() #app_path::monotonics::#m::now()
}; };
spawn_at(instant + duration #(,#untupled)*) spawn_at(instant + duration #(,#untupled)*)
@ -411,17 +414,11 @@ pub fn codegen(
let tq = unsafe { &mut *#app_path::#tq.as_mut_ptr() }; let tq = unsafe { &mut *#app_path::#tq.as_mut_ptr() };
if let Some(mono) = #app_path::#m_ident.as_mut() { tq.enqueue_unchecked(
tq.enqueue_unchecked( nr,
nr, || #enable_interrupt,
|| #enable_interrupt, || #pend,
|| #pend, #app_path::#m_ident.as_mut());
mono)
} else {
// We can only use the timer queue if `init` has returned, and it
// writes the `Some(monotonic)` we are accessing here.
core::hint::unreachable_unchecked()
}
Ok(SpawnHandle { marker }) Ok(SpawnHandle { marker })
}) })

View file

@ -42,7 +42,7 @@ where
nr: NotReady<Mono, Task>, nr: NotReady<Mono, Task>,
enable_interrupt: F1, enable_interrupt: F1,
pend_handler: F2, pend_handler: F2,
mono: &mut Mono, mono: Option<&mut Mono>,
) where ) where
F1: FnOnce(), F1: FnOnce(),
F2: FnOnce(), F2: FnOnce(),
@ -57,7 +57,9 @@ where
if if_heap_max_greater_than_nr { if if_heap_max_greater_than_nr {
if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE && self.0.is_empty() { if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE && self.0.is_empty() {
mono.enable_timer(); if let Some(mono) = mono {
mono.enable_timer();
}
enable_interrupt(); enable_interrupt();
} }