diff options
author | 2018-01-25 20:35:56 +0000 | |
---|---|---|
committer | 2018-01-25 20:35:56 +0000 | |
commit | e7618ca3ee577ca7929f7296320d4ad7a8a57a97 (patch) | |
tree | 67afff58530513cbf82329a9e90c5bea8f89fa93 | |
parent | c921d43f58db6ac4050e53c6b372d530fce073b7 (diff) | |
parent | 032af4b2b914f42b5533358cd2f40bbc7a888256 (diff) | |
download | cortex-m-e7618ca3ee577ca7929f7296320d4ad7a8a57a97.tar.gz cortex-m-e7618ca3ee577ca7929f7296320d4ad7a8a57a97.tar.zst cortex-m-e7618ca3ee577ca7929f7296320d4ad7a8a57a97.zip |
Auto merge of #81 - japaric:singleton, r=japaric
[RFC] initialize singletons at runtime
This PR changes how the singletons are initialized. The advantage of initializing a singleton at
runtime is that the initial value is not constrained to only what works in const context. The
disadvantage is that this approach will use up more Flash. With the new approach, `singleton!(_:
[u8; 1024] = [0; 1024])` will invoke a memcpy at the caller site; with the old approach, the array
would have been initialized (zeroed) during startup.
The following code works with the new approach, but doesn't with the old one.
``` rust
let x = 0;
let y = singleton!(_: u32 = x);
```
cc @therealprof @hannobraun
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/macros.rs | 52 |
3 files changed, 51 insertions, 6 deletions
@@ -13,6 +13,7 @@ version = "0.4.2" aligned = "0.1.1" bare-metal = "0.1.0" volatile-register = "0.2.0" +untagged-option = "0.1.1" [features] -cm7-r0p1 = []
\ No newline at end of file +cm7-r0p1 = [] @@ -15,6 +15,7 @@ extern crate aligned; extern crate bare_metal; +extern crate untagged_option; extern crate volatile_register; #[macro_use] @@ -31,3 +32,4 @@ pub mod peripheral; pub mod register; pub use peripheral::Peripherals; +pub use untagged_option::UntaggedOption; diff --git a/src/macros.rs b/src/macros.rs index c9a32c2..7d2cf6a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -52,17 +52,59 @@ macro_rules! iprintln { #[macro_export] macro_rules! singleton { (: $ty:ty = $expr:expr) => { - $crate::interrupt::free(|_| unsafe { + $crate::interrupt::free(|_| { static mut USED: bool = false; - static mut VAR: $ty = $expr; + static mut VAR: $crate::UntaggedOption<$ty> = $crate::UntaggedOption { none: () }; - if USED { + + #[allow(unsafe_code)] + let used = unsafe { USED }; + if used { None } else { - USED = true; - let var: &'static mut _ = &mut VAR; + #[allow(unsafe_code)] + unsafe { USED = true } + + let expr = $expr; + + #[allow(unsafe_code)] + unsafe { VAR.some = expr } + + #[allow(unsafe_code)] + let var: &'static mut _ = unsafe { &mut VAR.some }; + Some(var) } }) } } + + +/// ``` compile_fail +/// #[macro_use(singleton)] +/// extern crate cortex_m; +/// +/// fn main() {} +/// +/// fn foo() { +/// // check that the call to `uninitialized` requires unsafe +/// singleton!(: u8 = std::mem::uninitialized()); +/// } +/// ``` +#[allow(dead_code)] +const CFAIL: () = (); + +/// ``` +/// #![deny(unsafe_code)] +/// #[macro_use(singleton)] +/// extern crate cortex_m; +/// +/// fn main() {} +/// +/// fn foo() { +/// // check that calls to `singleton!` don't trip the `unsafe_code` lint +/// singleton!(: u8 = 0); +/// } +/// ``` +#[allow(dead_code)] +const CPASS: () = (); |