diff --git a/rtic-macros/CHANGELOG.md b/rtic-macros/CHANGELOG.md index b262f6491bbd..75bf5047da2f 100644 --- a/rtic-macros/CHANGELOG.md +++ b/rtic-macros/CHANGELOG.md @@ -11,6 +11,10 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top! - Added `waker` getter to software tasks +### Fixed + +- Support Rust edition 2024 `unsafe(link_section)` attribute + ## [v2.1.3] - 2025-06-08 ### Changed diff --git a/rtic-macros/src/codegen/local_resources.rs b/rtic-macros/src/codegen/local_resources.rs index c73ad56d6ede..86dda8626b37 100644 --- a/rtic-macros/src/codegen/local_resources.rs +++ b/rtic-macros/src/codegen/local_resources.rs @@ -19,10 +19,19 @@ pub fn codegen(app: &App, _analysis: &Analysis) -> TokenStream2 { // late resources in `util::link_section_uninit` // unless user specifies custom link section - let section = if attrs - .iter() - .any(|attr| attr.path().is_ident("link_section")) - { + let section = if attrs.iter().any(|attr| { + let is_link_section = attr.path().is_ident("link_section"); + let is_unsafe = attr.path().is_ident("unsafe"); + let is_embedded_link_section = match attr.parse_args() { + Ok(syn::Expr::Assign(assign)) => match &*assign.left { + syn::Expr::Path(path) => path.path.is_ident("link_section"), + _ => false, + }, + _ => false, + }; + + is_link_section || (is_unsafe && is_embedded_link_section) + }) { None } else { Some(util::link_section_uninit()) diff --git a/rtic-macros/src/codegen/shared_resources.rs b/rtic-macros/src/codegen/shared_resources.rs index d89f0c24e705..5e8ca9ae77ca 100644 --- a/rtic-macros/src/codegen/shared_resources.rs +++ b/rtic-macros/src/codegen/shared_resources.rs @@ -19,10 +19,19 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 { // late resources in `util::link_section_uninit` // unless user specifies custom link section - let section = if attrs - .iter() - .any(|attr| attr.path().is_ident("link_section")) - { + let section = if attrs.iter().any(|attr| { + let is_link_section = attr.path().is_ident("link_section"); + let is_unsafe = attr.path().is_ident("unsafe"); + let is_embedded_link_section = match attr.parse_args() { + Ok(syn::Expr::Assign(assign)) => match &*assign.left { + syn::Expr::Path(path) => path.path.is_ident("link_section"), + _ => false, + }, + _ => false, + }; + + is_link_section || (is_unsafe && is_embedded_link_section) + }) { None } else { Some(util::link_section_uninit()) diff --git a/rtic/CHANGELOG.md b/rtic/CHANGELOG.md index b71b8d0dc026..b228e3d968b4 100644 --- a/rtic/CHANGELOG.md +++ b/rtic/CHANGELOG.md @@ -36,6 +36,7 @@ Example: - Placate clippy - Updated esp32c3 dependency to v0.27.0 - Allow software tasks to be diverging (return `!`) and give them `'static` context. +- Added more `unsafe` blocks and migrated to 2024 edition. ### Added diff --git a/rtic/Cargo.toml b/rtic/Cargo.toml index 932684ae604a..ebfdf1f155a7 100644 --- a/rtic/Cargo.toml +++ b/rtic/Cargo.toml @@ -9,7 +9,7 @@ authors = [ categories = ["concurrency", "embedded", "no-std", "asynchronous"] description = "Real-Time Interrupt-driven Concurrency (RTIC): a concurrency framework for building real-time systems" documentation = "https://rtic.rs/" -edition = "2021" +edition = "2024" keywords = ["embedded", "async", "runtime", "no-std", "rtos"] license = "MIT OR Apache-2.0" name = "rtic" diff --git a/rtic/src/export/cortex_basepri.rs b/rtic/src/export/cortex_basepri.rs index 8aaa2d411e36..87146a73ae4f 100644 --- a/rtic/src/export/cortex_basepri.rs +++ b/rtic/src/export/cortex_basepri.rs @@ -1,10 +1,10 @@ use super::cortex_logical2hw; use cortex_m::register::{basepri, basepri_max}; pub use cortex_m::{ + Peripherals, asm::wfi, interrupt, - peripheral::{scb::SystemHandler, DWT, SCB, SYST}, - Peripherals, + peripheral::{DWT, SCB, SYST, scb::SystemHandler}, }; #[cfg(not(any(feature = "thumbv7-backend", feature = "thumbv8main-backend")))] @@ -69,13 +69,15 @@ pub unsafe fn lock( nvic_prio_bits: u8, f: impl FnOnce(&mut T) -> R, ) -> R { - if ceiling == (1 << nvic_prio_bits) { - critical_section::with(|_| f(&mut *ptr)) - } else { - let current = basepri::read(); - basepri_max::write(cortex_logical2hw(ceiling, nvic_prio_bits)); - let r = f(&mut *ptr); - basepri::write(current); - r + unsafe { + if ceiling == (1 << nvic_prio_bits) { + critical_section::with(|_| f(&mut *ptr)) + } else { + let current = basepri::read(); + basepri_max::write(cortex_logical2hw(ceiling, nvic_prio_bits)); + let r = f(&mut *ptr); + basepri::write(current); + r + } } } diff --git a/rtic/src/export/cortex_source_mask.rs b/rtic/src/export/cortex_source_mask.rs index 6146b4c6a125..4fb62a403b14 100644 --- a/rtic/src/export/cortex_source_mask.rs +++ b/rtic/src/export/cortex_source_mask.rs @@ -1,8 +1,8 @@ pub use cortex_m::{ + Peripherals, asm::wfi, interrupt, - peripheral::{scb::SystemHandler, DWT, NVIC, SCB, SYST}, - Peripherals, + peripheral::{DWT, NVIC, SCB, SYST, scb::SystemHandler}, }; #[cfg(not(any(feature = "thumbv6-backend", feature = "thumbv8base-backend")))] @@ -57,7 +57,9 @@ impl Mask { let block = bit / 32; if block as usize >= M { - panic!("Generating masks for thumbv6/thumbv8m.base failed! Are you compiling for thumbv6 on an thumbv7 MCU or using an unsupported thumbv8m.base MCU?"); + panic!( + "Generating masks for thumbv6/thumbv8m.base failed! Are you compiling for thumbv6 on an thumbv7 MCU or using an unsupported thumbv8m.base MCU?" + ); } let offset = bit - (block * 32); @@ -125,25 +127,27 @@ pub unsafe fn lock( masks: &[Mask; 3], f: impl FnOnce(&mut T) -> R, ) -> R { - if ceiling >= 4 { - // safe to manipulate outside critical section - // execute closure under protection of raised system ceiling - - // safe to manipulate outside critical section - critical_section::with(|_| f(&mut *ptr)) - } else { - // safe to manipulate outside critical section - let mask = compute_mask(0, ceiling, masks); - let old_mask = read_mask(mask); - clear_enable_mask(mask); - - // execute closure under protection of raised system ceiling - let r = f(&mut *ptr); - - set_enable_mask(mask, old_mask); - - // safe to manipulate outside critical section - r + unsafe { + if ceiling >= 4 { + // safe to manipulate outside critical section + // execute closure under protection of raised system ceiling + + // safe to manipulate outside critical section + critical_section::with(|_| f(&mut *ptr)) + } else { + // safe to manipulate outside critical section + let mask = compute_mask(0, ceiling, masks); + let old_mask = read_mask(mask); + clear_enable_mask(mask); + + // execute closure under protection of raised system ceiling + let r = f(&mut *ptr); + + set_enable_mask(mask, old_mask); + + // safe to manipulate outside critical section + r + } } } @@ -185,7 +189,7 @@ unsafe fn read_mask(mask: Mask) -> Mask { for i in 0..M { // This check should involve compile time constants and be optimized out. if mask.0[i] != 0 { - out.0[i] = (*NVIC::PTR).iser[i].read(); + out.0[i] = unsafe { (*NVIC::PTR).iser[i].read() }; } } @@ -198,7 +202,9 @@ unsafe fn set_enable_mask(mask: Mask, old_mask: Mask) { for i in 0..M { // This check should involve compile time constants and be optimized out. if mask.0[i] != 0 { - (*NVIC::PTR).iser[i].write(old_mask.0[i]); + unsafe { + (*NVIC::PTR).iser[i].write(old_mask.0[i]); + } } } } @@ -209,7 +215,9 @@ unsafe fn clear_enable_mask(mask: Mask) { for i in 0..M { // This check should involve compile time constants and be optimized out. if mask.0[i] != 0 { - (*NVIC::PTR).icer[i].write(mask.0[i]); + unsafe { + (*NVIC::PTR).icer[i].write(mask.0[i]); + } } } } diff --git a/rtic/src/export/executor.rs b/rtic/src/export/executor.rs index 7bc758286d2a..cefcd1b4fd8b 100644 --- a/rtic/src/export/executor.rs +++ b/rtic/src/export/executor.rs @@ -17,7 +17,7 @@ unsafe fn waker_clone(p: *const ()) -> RawWaker { unsafe fn waker_wake(p: *const ()) { // The only thing we need from a waker is the function to call to pend the async // dispatcher. - let f: fn() = mem::transmute(p); + let f: fn() = unsafe { mem::transmute(p) }; f(); } @@ -81,7 +81,7 @@ macro_rules! from_ptr_n_args { ($name:ident, $($t:ident),*) => { #[inline(always)] pub unsafe fn $name<$($t,)* Fun: Fn($($t,)*) -> F>(_f: Fun, ptr: &AsyncTaskExecutorPtr) -> &Self { - &*(ptr.get() as *const _) + unsafe { &*(ptr.get() as *const _) } } }; } diff --git a/rtic/src/export/riscv_esp32c3.rs b/rtic/src/export/riscv_esp32c3.rs index 2af6fc9a6e90..3ae0316a6961 100644 --- a/rtic/src/export/riscv_esp32c3.rs +++ b/rtic/src/export/riscv_esp32c3.rs @@ -10,26 +10,24 @@ pub fn run(priority: u8, f: F) where F: FnOnce(), { - if priority == 1 { - //if priority is 1, priority thresh should be 1 - f(); - unsafe { + unsafe { + if priority == 1 { + //if priority is 1, priority thresh should be 1 + f(); + (*INTERRUPT_CORE0::ptr()) .cpu_int_thresh() .write(|w| w.cpu_int_thresh().bits(1)); - } - } else { - //read current thresh - let initial = unsafe { - (*INTERRUPT_CORE0::ptr()) + } else { + //read current thresh + let initial = (*INTERRUPT_CORE0::ptr()) .cpu_int_thresh() .read() .cpu_int_thresh() - .bits() - }; - f(); - //write back old thresh - unsafe { + .bits(); + f(); + //write back old thresh + (*INTERRUPT_CORE0::ptr()) .cpu_int_thresh() .write(|w| w.cpu_int_thresh().bits(initial)); @@ -55,30 +53,29 @@ where /// priority is current priority >= ceiling. #[inline(always)] pub unsafe fn lock(ptr: *mut T, ceiling: u8, f: impl FnOnce(&mut T) -> R) -> R { - if ceiling == (15) { - //turn off interrupts completely, were at max prio - critical_section::with(|_| f(&mut *ptr)) - } else { - let current = unsafe { - (*INTERRUPT_CORE0::ptr()) + unsafe { + if ceiling == (15) { + //turn off interrupts completely, were at max prio + critical_section::with(|_| f(&mut *ptr)) + } else { + let current = (*INTERRUPT_CORE0::ptr()) .cpu_int_thresh() .read() .cpu_int_thresh() - .bits() - }; + .bits(); - unsafe { (*INTERRUPT_CORE0::ptr()) .cpu_int_thresh() .write(|w| w.cpu_int_thresh().bits(ceiling + 1)); - } //esp32c3 lets interrupts with prio equal to threshold through so we up it by one - let r = f(&mut *ptr); - unsafe { + //esp32c3 lets interrupts with prio equal to threshold through so we up it by one + let r = f(&mut *ptr); + (*INTERRUPT_CORE0::ptr()) .cpu_int_thresh() .write(|w| w.cpu_int_thresh().bits(current)); + + r } - r } } diff --git a/rtic/src/export/riscv_esp32c6.rs b/rtic/src/export/riscv_esp32c6.rs index 7bd530384fa6..de50ff42703a 100644 --- a/rtic/src/export/riscv_esp32c6.rs +++ b/rtic/src/export/riscv_esp32c6.rs @@ -1,5 +1,5 @@ -pub use esp32c6::{Interrupt, Peripherals}; use esp32c6::{INTERRUPT_CORE0, PLIC_MX}; +pub use esp32c6::{Interrupt, Peripherals}; pub use riscv::interrupt; pub use riscv::register::mcause; @@ -11,26 +11,24 @@ pub fn run(priority: u8, f: F) where F: FnOnce(), { - if priority == 1 { - //if priority is 1, priority thresh should be 1 - f(); - unsafe { + unsafe { + if priority == 1 { + //if priority is 1, priority thresh should be 1 + f(); + (*PLIC_MX::ptr()) .mxint_thresh() .write(|w| w.cpu_mxint_thresh().bits(1)); - } - } else { - //read current thresh - let initial = unsafe { - (*PLIC_MX::ptr()) + } else { + //read current thresh + let initial = (*PLIC_MX::ptr()) .mxint_thresh() .read() .cpu_mxint_thresh() - .bits() - }; - f(); - //write back old thresh - unsafe { + .bits(); + f(); + //write back old thresh + (*PLIC_MX::ptr()) .mxint_thresh() .write(|w| w.cpu_mxint_thresh().bits(initial)); @@ -56,34 +54,30 @@ where /// priority is current priority >= ceiling. #[inline(always)] pub unsafe fn lock(ptr: *mut T, ceiling: u8, f: impl FnOnce(&mut T) -> R) -> R { - if ceiling == (15) { - // Turn off interrupts completely, we're at max prio - critical_section::with(|_| f(&mut *ptr)) - } else { - let current = unsafe { - (*PLIC_MX::ptr()) + unsafe { + if ceiling == (15) { + // Turn off interrupts completely, we're at max prio + critical_section::with(|_| f(&mut *ptr)) + } else { + let current = (*PLIC_MX::ptr()) .mxint_thresh() .read() .cpu_mxint_thresh() - .bits() - }; + .bits(); - // esp32c6 lets interrupts with prio equal to threshold through so we up it by one - unsafe { + // esp32c6 lets interrupts with prio equal to threshold through so we up it by one (*PLIC_MX::ptr()) .mxint_thresh() .write(|w| w.cpu_mxint_thresh().bits(ceiling + 1)); - } - let r = f(&mut *ptr); + let r = f(&mut *ptr); - unsafe { (*PLIC_MX::ptr()) .mxint_thresh() .write(|w| w.cpu_mxint_thresh().bits(current)); - } - r + r + } } } diff --git a/rtic/src/export/slic.rs b/rtic/src/export/slic.rs index 868535e05bd7..d7953056d6f9 100644 --- a/rtic/src/export/slic.rs +++ b/rtic/src/export/slic.rs @@ -1,4 +1,4 @@ -pub use riscv_slic::{lock, pend, run, InterruptNumber}; +pub use riscv_slic::{InterruptNumber, lock, pend, run}; #[cfg(all( feature = "riscv-slic", @@ -17,6 +17,6 @@ pub mod interrupt { #[inline] pub unsafe fn enable() { - riscv_slic::enable(); + unsafe { riscv_slic::enable() }; } } diff --git a/rtic/src/lib.rs b/rtic/src/lib.rs index 1fd0d43a4e7a..da1efdccbd89 100644 --- a/rtic/src/lib.rs +++ b/rtic/src/lib.rs @@ -33,13 +33,13 @@ #![allow(clippy::inline_always)] #![allow(unexpected_cfgs)] -pub use rtic_core::{prelude as mutex_prelude, Exclusive, Mutex}; +pub use rtic_core::{Exclusive, Mutex, prelude as mutex_prelude}; pub use rtic_macros::app; /// module `mutex::prelude` provides `Mutex` and multi-lock variants. Recommended over `mutex_prelude` pub mod mutex { - pub use rtic_core::prelude; pub use rtic_core::Mutex; + pub use rtic_core::prelude; } #[doc(hidden)] diff --git a/rtic/ui/custom_section.rs b/rtic/ui/custom_section.rs new file mode 100644 index 000000000000..cb1b81fa112a --- /dev/null +++ b/rtic/ui/custom_section.rs @@ -0,0 +1,20 @@ +#![no_main] + +compile_error!("This should be the only error in the file"); + +#[rtic::app(device = lm3s6965)] +mod app { + #[shared] + struct Shared { + #[unsafe(link_section = ".custom_section")] + foo: (), + } + + #[local] + struct Local {} + + #[init] + fn init(_cx: init::Context) -> (Shared, Local) { + (Shared { foo: () }, Local {}) + } +} diff --git a/rtic/ui/custom_section.stderr b/rtic/ui/custom_section.stderr new file mode 100644 index 000000000000..a8495dca4e63 --- /dev/null +++ b/rtic/ui/custom_section.stderr @@ -0,0 +1,5 @@ +error: This should be the only error in the file + --> ui/custom_section.rs:3:1 + | +3 | compile_error!("This should be the only error in the file"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^