diff --git a/examples/lockall_soundness.rs b/examples/lockall_soundness.rs deleted file mode 100644 index a5537bc1b1..0000000000 --- a/examples/lockall_soundness.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! examples/lockall_soundness.rs - -// #![deny(unsafe_code)] -#![deny(warnings)] -#![no_main] -#![no_std] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - a: u32, - b: i64, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { - foo::spawn().unwrap(); - - (Shared { a: 1, b: 2 }, Local {}, init::Monotonics()) - } - - // when omitted priority is assumed to be `1` - #[task(shared = [a, b])] - fn foo(mut c: foo::Context) { - static mut X: Option<&'static mut u32> = None; - static mut Y: u32 = 0; - c.shared.lock(|s| { - hprintln!("s.a = {}, s.b = {}", s.a, s.b).ok(); - *s.a += 1; - - // soundness check - // c.shared.lock(|s| {}); // borrow error - // c.shared.a.lock(|s| {}); // borrow error - - unsafe { - X = Some(&mut Y); - // X = Some(s.a); // lifetime issue - // X = Some(&mut *s.a); // lifetime issue - // X = Some(&'static mut *s.a); // not rust - } - hprintln!("s.a = {}, s.b = {}", s.a, s.b).ok(); - }); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/examples/lockall_soundness2.rs b/examples/lockall_soundness2.rs deleted file mode 100644 index f3d71dd532..0000000000 --- a/examples/lockall_soundness2.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! examples/lockall_soundness2.rs - -// #![deny(unsafe_code)] -#![deny(warnings)] -#![no_main] -#![no_std] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - a: u32, - b: i64, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { - foo::spawn().unwrap(); - - (Shared { a: 1, b: 2 }, Local {}, init::Monotonics()) - } - - // when omitted priority is assumed to be `1` - #[task(shared = [a, b])] - fn foo(mut c: foo::Context) { - static mut X: Option<&'static mut u32> = None; - static mut Y: u32 = 0; - c.shared.lock(|foo::Shared { a, b }| { - hprintln!("s.a = {}, s.b = {}", a, b).ok(); - **a += 1; - - // soundness check - // c.shared.lock(|s| {}); // borrow error - // c.shared.a.lock(|s| {}); // borrow error - - unsafe { - X = Some(&mut Y); - // X = Some(*a); // lifetime issue - // X = Some(&mut **a); // lifetime issue - // X = Some(&'static mut **a); // not rust - } - hprintln!("s.a = {}, s.b = {}", a, b).ok(); - }); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/examples/lockall_soundness3.rs b/examples/lockall_soundness3.rs deleted file mode 100644 index 9e3376d2b9..0000000000 --- a/examples/lockall_soundness3.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! examples/lockall_soundness3.rs - -#![deny(unsafe_code)] -// #![deny(warnings)] -#![no_main] -#![no_std] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - a: u32, - b: i64, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { - foo::spawn().unwrap(); - - (Shared { a: 1, b: 2 }, Local {}, init::Monotonics()) - } - - // when omitted priority is assumed to be `1` - #[task(shared = [a, b])] - fn foo(mut c: foo::Context) { - // let s = c.shared.lock(|s| s); // lifetime error - // hprintln!("a {}", s.a).ok(); - - // let a = c.shared.lock(|foo::Shared { a, b: _ }| a); // lifetime error - // hprintln!("a {}", a).ok(); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/examples/multilock_problem.rs b/examples/multilock_problem.rs deleted file mode 100644 index 5fd86ef7a1..0000000000 --- a/examples/multilock_problem.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! examples/multilock_vs_lockall.rs - -#![deny(unsafe_code)] -#![deny(warnings)] -#![no_main] -#![no_std] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - shared1: u32, - shared2: u32, - shared3: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { - locks::spawn().unwrap(); - - ( - Shared { - shared1: 0, - shared2: 0, - shared3: 0, - }, - Local {}, - init::Monotonics(), - ) - } - - // when omitted priority is assumed to be `1` - #[task(shared = [shared1, shared2, shared3])] - fn locks(c: locks::Context) { - // nested multi-lock - let s1 = c.shared.shared1; - let s2 = c.shared.shared2; - let s3 = c.shared.shared3; - - (s1, s2, s3).lock(|s1, s2, s3| { - *s1 += 1; - *s2 += 2; - *s3 += 3; - - hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", s1, s2, s3).ok(); - }); - - // re-construct gives error (consumed by above lock) - let s = locks::SharedResources { - shared1: s1, - shared2: s2, - shared3: s3, - }; - - // nested multi-lock destruct - let locks::SharedResources { - shared1, - shared2, - shared3, - } = s; - - (shared1, shared2, shared3).lock(|s1, s2, s3| { - *s1 += 1; - *s2 += 2; - *s3 += 3; - - hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", s1, s2, s3).ok(); - }); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/examples/multilock_problem_workaround.rs b/examples/multilock_sequence.rs similarity index 94% rename from examples/multilock_problem_workaround.rs rename to examples/multilock_sequence.rs index 652d568241..a4f4641557 100644 --- a/examples/multilock_problem_workaround.rs +++ b/examples/multilock_sequence.rs @@ -52,14 +52,14 @@ mod app { hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", s1, s2, s3).ok(); }); - // re-construct gives error (consumed by above lock) + // re-construct let s = locks::SharedResources { shared1: s1, shared2: s2, shared3: s3, }; - // nested multi-lock destruct + // second nested multi-lock destruct let locks::SharedResources { shared1, shared2, diff --git a/ui/lockall_borrow_shared.rs b/ui/lockall_borrow_shared.rs new file mode 100644 index 0000000000..c57e539cfe --- /dev/null +++ b/ui/lockall_borrow_shared.rs @@ -0,0 +1,24 @@ +#![no_main] + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] +mod app { + #[shared] + struct Shared { + a: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { + (Shared { a: 0 }, Local {}, init::Monotonics()) + } + + #[task(shared = [a])] + fn foo(mut c: foo::Context) { + c.shared.lock(|_| { + c.shared.lock(|_| {}); // borrow error + }); + } +} diff --git a/ui/lockall_borrow_shared.stderr b/ui/lockall_borrow_shared.stderr new file mode 100644 index 0000000000..97d0e7856a --- /dev/null +++ b/ui/lockall_borrow_shared.stderr @@ -0,0 +1,25 @@ +error[E0499]: cannot borrow `c.shared` as mutable more than once at a time + --> ui/lockall_borrow_shared.rs:20:9 + | +20 | c.shared.lock(|_| { + | ^ ---- --- first mutable borrow occurs here + | | | + | _________| first borrow later used by call + | | +21 | | c.shared.lock(|_| {}); // borrow error + | | -------- first borrow occurs due to use of `c` in closure +22 | | }); + | |__________^ second mutable borrow occurs here + +error[E0499]: cannot borrow `c` as mutable more than once at a time + --> ui/lockall_borrow_shared.rs:20:23 + | +20 | c.shared.lock(|_| { + | - ---- ^^^ second mutable borrow occurs here + | | | + | _________| first borrow later used by call + | | +21 | | c.shared.lock(|_| {}); // borrow error + | | -------- second borrow occurs due to use of `c` in closure +22 | | }); + | |__________- first mutable borrow occurs here diff --git a/ui/lockall_borrow_shared_a.rs b/ui/lockall_borrow_shared_a.rs new file mode 100644 index 0000000000..f500af0495 --- /dev/null +++ b/ui/lockall_borrow_shared_a.rs @@ -0,0 +1,24 @@ +#![no_main] + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] +mod app { + #[shared] + struct Shared { + a: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { + (Shared { a: 0 }, Local {}, init::Monotonics()) + } + + #[task(shared = [a])] + fn foo(mut c: foo::Context) { + c.shared.lock(|_| { + c.shared.a.lock(|_| {}); // borrow error + }); + } +} diff --git a/ui/lockall_borrow_shared_a.stderr b/ui/lockall_borrow_shared_a.stderr new file mode 100644 index 0000000000..bc1a5bfd60 --- /dev/null +++ b/ui/lockall_borrow_shared_a.stderr @@ -0,0 +1,25 @@ +error[E0499]: cannot borrow `c.shared` as mutable more than once at a time + --> ui/lockall_borrow_shared_a.rs:20:9 + | +20 | c.shared.lock(|_| { + | ^ ---- --- first mutable borrow occurs here + | | | + | _________| first borrow later used by call + | | +21 | | c.shared.a.lock(|_| {}); // borrow error + | | ---------- first borrow occurs due to use of `c` in closure +22 | | }); + | |__________^ second mutable borrow occurs here + +error[E0499]: cannot borrow `c` as mutable more than once at a time + --> ui/lockall_borrow_shared_a.rs:20:23 + | +20 | c.shared.lock(|_| { + | - ---- ^^^ second mutable borrow occurs here + | | | + | _________| first borrow later used by call + | | +21 | | c.shared.a.lock(|_| {}); // borrow error + | | ---------- second borrow occurs due to use of `c` in closure +22 | | }); + | |__________- first mutable borrow occurs here diff --git a/ui/lockall_lifetime.rs b/ui/lockall_lifetime.rs new file mode 100644 index 0000000000..b32fbce1f5 --- /dev/null +++ b/ui/lockall_lifetime.rs @@ -0,0 +1,22 @@ +#![no_main] + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] +mod app { + #[shared] + struct Shared { + a: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { + (Shared { a: 0 }, Local {}, init::Monotonics()) + } + + #[task(shared = [a])] + fn foo(mut c: foo::Context) { + let _ = c.shared.lock(|s| s); // lifetime + } +} diff --git a/ui/lockall_lifetime.stderr b/ui/lockall_lifetime.stderr new file mode 100644 index 0000000000..d42b5ef5c3 --- /dev/null +++ b/ui/lockall_lifetime.stderr @@ -0,0 +1,8 @@ +error: lifetime may not live long enough + --> ui/lockall_lifetime.rs:20:35 + | +20 | let _ = c.shared.lock(|s| s); // lifetime + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 mut __rtic_internal_fooShared + | has type `&'1 mut __rtic_internal_fooShared` diff --git a/ui/lockall_lifetime_destruct_field.rs b/ui/lockall_lifetime_destruct_field.rs new file mode 100644 index 0000000000..3eb56150ed --- /dev/null +++ b/ui/lockall_lifetime_destruct_field.rs @@ -0,0 +1,31 @@ +//! examples/lockall_soundness.rs + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] +mod app { + #[shared] + struct Shared { + a: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { + (Shared { a: 0 }, Local {}, init::Monotonics()) + } + + #[task(shared = [a])] + fn foo(mut c: foo::Context) { + let _ = c.shared.lock(|foo::Shared { a }| { + a // lifetime + }); + } +} diff --git a/ui/lockall_lifetime_destruct_field.stderr b/ui/lockall_lifetime_destruct_field.stderr new file mode 100644 index 0000000000..67e73d5c28 --- /dev/null +++ b/ui/lockall_lifetime_destruct_field.stderr @@ -0,0 +1,9 @@ +error: lifetime may not live long enough + --> ui/lockall_lifetime_destruct_field.rs:28:13 + | +27 | let _ = c.shared.lock(|foo::Shared { a }| { + | ------------------ return type of closure is &'2 mut &mut u32 + | | + | has type `&'1 mut __rtic_internal_fooShared` +28 | a // lifetime + | ^ returning this value requires that `'1` must outlive `'2` diff --git a/ui/lockall_lifetime_reborrow.rs b/ui/lockall_lifetime_reborrow.rs new file mode 100644 index 0000000000..2c9c43fe74 --- /dev/null +++ b/ui/lockall_lifetime_reborrow.rs @@ -0,0 +1,22 @@ +#![no_main] + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] +mod app { + #[shared] + struct Shared { + a: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { + (Shared { a: 0 }, Local {}, init::Monotonics()) + } + + #[task(shared = [a])] + fn foo(mut c: foo::Context) { + let _ = c.shared.lock(|s| &mut *s.a); // lifetime + } +} diff --git a/ui/lockall_lifetime_reborrow.stderr b/ui/lockall_lifetime_reborrow.stderr new file mode 100644 index 0000000000..b2980c5819 --- /dev/null +++ b/ui/lockall_lifetime_reborrow.stderr @@ -0,0 +1,8 @@ +error: lifetime may not live long enough + --> ui/lockall_lifetime_reborrow.rs:20:35 + | +20 | let _ = c.shared.lock(|s| &mut *s.a); // lifetime + | -- ^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 mut u32 + | has type `&'1 mut __rtic_internal_fooShared` diff --git a/ui/lockall_move_out_field.rs b/ui/lockall_move_out_field.rs new file mode 100644 index 0000000000..dadeefcdb4 --- /dev/null +++ b/ui/lockall_move_out_field.rs @@ -0,0 +1,24 @@ +#![no_main] + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] +mod app { + #[shared] + struct Shared { + a: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { + foo::spawn().unwrap(); + + (Shared { a: 0 }, Local {}, init::Monotonics()) + } + + #[task(shared = [a])] + fn foo(mut c: foo::Context) { + let _ = c.shared.lock(|s| s.a); + } +} diff --git a/ui/lockall_move_out_field.stderr b/ui/lockall_move_out_field.stderr new file mode 100644 index 0000000000..8272717b43 --- /dev/null +++ b/ui/lockall_move_out_field.stderr @@ -0,0 +1,5 @@ +error[E0507]: cannot move out of `s.a` which is behind a mutable reference + --> ui/lockall_move_out_field.rs:22:35 + | +22 | let _ = c.shared.lock(|s| s.a); + | ^^^ move occurs because `s.a` has type `&mut u32`, which does not implement the `Copy` trait