aboutsummaryrefslogtreecommitdiff
path: root/cortex-m-rt/macros/src/lib.rs
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <jorge@japaric.io> 2018-09-03 20:41:41 +0200
committerGravatar Jorge Aparicio <jorge@japaric.io> 2018-09-03 23:21:53 +0200
commitfc592e4960d99ca8f33c6414ca9903bf0cb6df73 (patch)
treeee8fc7bcf09b601da6826ac6005a2eadf455a486 /cortex-m-rt/macros/src/lib.rs
parent48c1af844ef99772446850eb0288bef61d663afb (diff)
downloadcortex-m-fc592e4960d99ca8f33c6414ca9903bf0cb6df73.tar.gz
cortex-m-fc592e4960d99ca8f33c6414ca9903bf0cb6df73.tar.zst
cortex-m-fc592e4960d99ca8f33c6414ca9903bf0cb6df73.zip
make `static mut` variables safe to access in the entry point
extend / update documentation
Diffstat (limited to 'cortex-m-rt/macros/src/lib.rs')
-rw-r--r--cortex-m-rt/macros/src/lib.rs146
1 files changed, 110 insertions, 36 deletions
diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs
index 82457f1..5d6a603 100644
--- a/cortex-m-rt/macros/src/lib.rs
+++ b/cortex-m-rt/macros/src/lib.rs
@@ -9,7 +9,7 @@ extern crate syn;
use proc_macro2::Span;
use rand::Rng;
-use syn::{FnArg, Ident, Item, ItemFn, ReturnType, Stmt, Type, Visibility};
+use syn::{FnArg, Ident, Item, ItemFn, ItemStatic, ReturnType, Stmt, Type, Visibility};
use proc_macro::TokenStream;
@@ -24,13 +24,45 @@ use proc_macro::TokenStream;
///
/// The type of the specified function must be `fn() -> !` (never ending function)
///
+/// # Properties
+///
+/// The entry point will be called by the reset handler. The program can't reference to the entry
+/// point, much less invoke it.
+///
+/// `static mut` variables declared within the entry point are safe to access. The compiler can't
+/// prove this is safe so the attribute will help by making a transformation to the source code: for
+/// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note
+/// that `&'static mut` references have move semantics.
+///
/// # Examples
///
+/// - Simple entry point
+///
+/// ``` no_run
+/// # #![no_main]
+/// # use cortex_m_rt_macros::entry;
+/// #[entry]
+/// fn main() -> ! {
+/// loop {
+/// /* .. */
+/// }
+/// }
+/// ```
+///
+/// - `static mut` variables local to the entry point are safe to modify.
+///
/// ``` no_run
/// # #![no_main]
/// # use cortex_m_rt_macros::entry;
/// #[entry]
/// fn main() -> ! {
+/// static mut FOO: u32 = 0;
+///
+/// let foo: &'static mut u32 = FOO;
+/// assert_eq!(*foo, 0);
+/// *foo = 1;
+/// assert_eq!(*foo, 1);
+///
/// loop {
/// /* .. */
/// }
@@ -69,12 +101,36 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
// XXX should we blacklist other attributes?
let attrs = f.attrs;
let ident = f.ident;
- let block = f.block;
+ let (statics, stmts) = extract_static_muts(f.block.stmts);
+
+ let vars = statics
+ .into_iter()
+ .map(|var| {
+ let ident = var.ident;
+ // `let` can't shadow a `static mut` so we must give the `static` a different
+ // name. We'll create a new name by appending an underscore to the original name
+ // of the `static`.
+ let mut ident_ = ident.to_string();
+ ident_.push('_');
+ let ident_ = Ident::new(&ident_, Span::call_site());
+ let ty = var.ty;
+ let expr = var.expr;
+
+ quote!(
+ static mut #ident_: #ty = #expr;
+ #[allow(non_snake_case, unsafe_code)]
+ let #ident: &'static mut #ty = unsafe { &mut #ident_ };
+ )
+ }).collect::<Vec<_>>();
quote!(
#[export_name = "main"]
#(#attrs)*
- pub fn #ident() -> ! #block
+ pub fn #ident() -> ! {
+ #(#vars)*
+
+ #(#stmts)*
+ }
).into()
}
@@ -130,8 +186,15 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
/// mut` variables at the beginning of the body of the function. These variables will be safe to
/// access from the function body.
///
+/// # Properties
+///
/// Exception handlers can only be called by the hardware. Other parts of the program can't refer to
-/// the exception handler much less invoke them as if they were functions.
+/// the exception handlers, much less invoke them as if they were functions.
+///
+/// `static mut` variables declared within an exception handler are safe to access and can be used
+/// to preserve state across invocations of the handler. The compiler can't prove this is safe so
+/// the attribute will help by making a transformation to the source code: for this reason a
+/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`.
///
/// # Examples
///
@@ -215,17 +278,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
let block = f.block;
let stmts = block.stmts;
- let mut rng = rand::thread_rng();
- let hash = (0..16)
- .map(|i| {
- if i == 0 || rng.gen() {
- ('a' as u8 + rng.gen::<u8>() % 25) as char
- } else {
- ('0' as u8 + rng.gen::<u8>() % 10) as char
- }
- }).collect::<String>();
- let hash = Ident::new(&hash, Span::call_site());
-
+ let hash = random_ident();
match exn {
Exception::DefaultHandler => {
assert!(
@@ -336,27 +389,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
have signature `fn()`"
);
- // Collect all the `static mut` at the beginning of the function body. We'll make them
- // safe
- let mut istmts = stmts.into_iter();
-
- let mut statics = vec![];
- let mut stmts = vec![];
- while let Some(stmt) = istmts.next() {
- match stmt {
- Stmt::Item(Item::Static(var)) => if var.mutability.is_some() {
- statics.push(var);
- } else {
- stmts.push(Stmt::Item(Item::Static(var)));
- },
- _ => {
- stmts.push(stmt);
- break;
- }
- }
- }
-
- stmts.extend(istmts);
+ let (statics, stmts) = extract_static_muts(stmts);
let vars = statics
.into_iter()
@@ -455,3 +488,44 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
pub unsafe fn #ident() #block
).into()
}
+
+// Creates a random identifier
+fn random_ident() -> Ident {
+ let mut rng = rand::thread_rng();
+ Ident::new(
+ &(0..16)
+ .map(|i| {
+ if i == 0 || rng.gen() {
+ ('a' as u8 + rng.gen::<u8>() % 25) as char
+ } else {
+ ('0' as u8 + rng.gen::<u8>() % 10) as char
+ }
+ }).collect::<String>(),
+ Span::call_site(),
+ )
+}
+
+/// Extracts `static mut` vars from the beginning of the given statements
+fn extract_static_muts(stmts: Vec<Stmt>) -> (Vec<ItemStatic>, Vec<Stmt>) {
+ let mut istmts = stmts.into_iter();
+
+ let mut statics = vec![];
+ let mut stmts = vec![];
+ while let Some(stmt) = istmts.next() {
+ match stmt {
+ Stmt::Item(Item::Static(var)) => if var.mutability.is_some() {
+ statics.push(var);
+ } else {
+ stmts.push(Stmt::Item(Item::Static(var)));
+ },
+ _ => {
+ stmts.push(stmt);
+ break;
+ }
+ }
+ }
+
+ stmts.extend(istmts);
+
+ (statics, stmts)
+}
-highlight'> 2023-10-16Fix formattingGravatar Ashcon Partovi 1-3/+1 2023-10-16fix(test): when tests run with --only the nested describe blocks `.on… (#5616)Gravatar Igor Shapiro 2-13/+45 2023-10-16perf(node:events): optimize `emit(...)` function (#5485)Gravatar Yannik Schröder 3-11/+132 2023-10-16fix: don't remove content-encoding header from header table (#5743)Gravatar Liz 2-2/+25 Closes #5668 2023-10-16fix(sqlite) Insert .all() does not return an array #5872 (#5946)Gravatar Hugo Galan 2-7/+11 * fixing #5872 * removing useless comment 2023-10-16Fix formattingGravatar Ashcon Partovi 2-5/+4 2023-10-16Fix `Response.statusText` (#6151)Gravatar Chris Toshok 10-238/+269 2023-10-16fix-subprocess-argument-missing (#6407)Gravatar Nicolae-Rares Ailincai 4-2/+40 * fix-subprocess-argument-missing * fix-tests * nitpick, these should === not just be undefined --------- Co-authored-by: dave caruso <me@paperdave.net> 2023-10-16Add type parameter to `expect` (#6128)Gravatar Voldemat 1-3/+3 2023-10-16fix(node:worker_threads): ensure threadId property is exposed on ↵Gravatar Jérôme Benoit 6-15/+75 worker_threads instance (#6521) * fix: ensure threadId property is exposed on worker_threads instance Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com> * fix: rename lazy worker_threads module properties Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com> * fix: add getter for threadId Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com> * test: improve worker_threads UTs Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com> * test: fix lazy loading Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com> * test: fix worker_threads test Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org> * fix: return the worker threadId Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com> * test: refine worker_threads expectation on threadId Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org> --------- Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com> Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org> 2023-10-16Fix use before define bug in sqliteGravatar Ashcon Partovi 2-5/+5 Fixes #6481 2023-10-16fix(jest): fix toStrictEqual on same URLs (#6528)Gravatar João Alisson 2-13/+16 Fixes #6492 2023-10-16Fix `toHaveBeenCalled` having wrong error signatureGravatar Ashcon Partovi 1-2/+2 Fixes #6527 2023-10-16Fix formattingGravatar Ashcon Partovi 1-2/+1 2023-10-16Add `reusePort` to `Bun.serve` typesGravatar Ashcon Partovi 1-0/+9 2023-10-16Fix `request.url` having incorrect portGravatar Ashcon Partovi 4-1/+92 Fixes #6443 2023-10-16Remove uWebSockets header from Bun.serve responsesGravatar Ashcon Partovi 1-6/+6 2023-10-16Rename some testsGravatar Ashcon Partovi 3-0/+0 2023-10-16Fix #6467Gravatar Ashcon Partovi 2-3/+10 2023-10-16Update InternalModuleRegistryConstants.hGravatar Dylan Conway 1-3/+3 2023-10-16Development -> Contributing (#6538)Gravatar Colin McDonnell 2-1/+1 Co-authored-by: Colin McDonnell <colin@KennyM1.local> 2023-10-14fix(net/tls) fix pg hang on end + hanging on query (#6487)Gravatar Ciro Spaciari 3-8/+36 * fix pg hang on end + hanging on query * remove dummy function * fix node-stream * add test * fix test * return error in test * fix test use once instead of on * fix OOM * generated * 💅 * 💅 2023-10-13fix installing dependencies that match workspace versions (#6494)Gravatar Dylan Conway 4-2/+64 * check if dependency matches workspace version * test * Update lockfile.zig * set resolution to workspace package id 2023-10-13fix lockfile struct padding (#6495)Gravatar Dylan Conway 3-3/+18 * integrity padding * error message for bytes at end of struct