From 88078e7770a2beda072ac37f89e2a81e5a9cb243 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 15 Feb 2019 19:52:25 +0100 Subject: [PATCH 1/6] add "nightly" feature --- Cargo.toml | 1 + macros/Cargo.toml | 3 +- macros/src/codegen.rs | 265 +++++++++++++++++++++++++++++------------- src/export.rs | 65 ++++++++++- src/lib.rs | 1 + 5 files changed, 248 insertions(+), 87 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d741f6fa37..f09677239f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ features = ["exit"] version = "0.5.1" [features] +nightly = ["cortex-m-rtfm-macros/nightly", "heapless/const-fn"] timer-queue = ["cortex-m-rtfm-macros/timer-queue"] [target.x86_64-unknown-linux-gnu.dev-dependencies] diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 31fa8428ec..48e75f8977 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -27,4 +27,5 @@ default-features = false version = "0.5.5" [features] -timer-queue = [] \ No newline at end of file +timer-queue = [] +nightly = [] \ No newline at end of file diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index af09ad4286..83e5026670 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -283,7 +283,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2: if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) { if res.mutability.is_some() { let ptr = if res.expr.is_none() { - quote!(unsafe { #alias.get_mut() }) + quote!(unsafe { &mut *#alias.as_mut_ptr() }) } else { quote!(unsafe { &mut #alias }) }; @@ -494,8 +494,10 @@ fn post_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok // Enable and start the system timer if !analysis.timer_queue.tasks.is_empty() { let tq = &ctxt.timer_queue; - exprs.push(quote!(#tq.get_mut().syst.set_clock_source(rtfm::export::SystClkSource::Core))); - exprs.push(quote!(#tq.get_mut().syst.enable_counter())); + exprs.push( + quote!((*#tq.as_mut_ptr()).syst.set_clock_source(rtfm::export::SystClkSource::Core)), + ); + exprs.push(quote!((*#tq.as_mut_ptr()).syst.enable_counter())); } // Enable cycle counter @@ -903,21 +905,21 @@ fn prelude( )); } } else { - let method = if mut_.is_some() { - quote!(get_mut) + let expr = if mut_.is_some() { + quote!(&mut *#alias.as_mut_ptr()) } else { - quote!(get_ref) + quote!(&*#alias.as_ptr()) }; if exclusive { exprs.push(quote!( #(#cfgs)* - #name: rtfm::Exclusive(#alias.#method()) + #name: rtfm::Exclusive(#expr) )); } else { exprs.push(quote!( #(#cfgs)* - #name: #alias.#method() + #name: #expr )); } } @@ -1254,8 +1256,9 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok let ty = tuple_ty(inputs); - let capacity_lit = mk_capacity_literal(analysis.capacities[name]); - let capacity_ty = mk_typenum_capacity(analysis.capacities[name], true); + let capacity = analysis.capacities[name]; + let capacity_lit = mk_capacity_literal(capacity); + let capacity_ty = mk_typenum_capacity(capacity, true); let resource = mk_resource( ctxt, @@ -1263,7 +1266,11 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok &free_alias, quote!(rtfm::export::FreeQueue<#capacity_ty>), *analysis.free_queues.get(name).unwrap_or(&0), - quote!(#free_alias.get_mut()), + if cfg!(feature = "nightly") { + quote!(&mut #free_alias) + } else { + quote!(#free_alias.get_mut()) + }, app, None, ); @@ -1273,12 +1280,24 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok () => { let scheduleds_symbol = format!("{}::SCHEDULED_TIMES::{}", name, scheduleds_alias); - quote!( - #[doc = #scheduleds_symbol] - static mut #scheduleds_alias: - rtfm::export::MaybeUninit<[rtfm::Instant; #capacity_lit]> = - rtfm::export::MaybeUninit::uninitialized(); - ) + if cfg!(feature = "nightly") { + let inits = + (0..capacity).map(|_| quote!(rtfm::export::MaybeUninit::uninitialized())); + + quote!( + #[doc = #scheduleds_symbol] + static mut #scheduleds_alias: + [rtfm::export::MaybeUninit; #capacity_lit] = + [#(#inits),*]; + ) + } else { + quote!( + #[doc = #scheduleds_symbol] + static mut #scheduleds_alias: + rtfm::export::MaybeUninit<[rtfm::Instant; #capacity_lit]> = + rtfm::export::MaybeUninit::uninitialized(); + ) + } } #[cfg(not(feature = "timer-queue"))] () => quote!(), @@ -1286,20 +1305,36 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok let inputs_symbol = format!("{}::INPUTS::{}", name, inputs_alias); let free_symbol = format!("{}::FREE_QUEUE::{}", name, free_alias); - items.push(quote!( - // FIXME(MaybeUninit) MaybeUninit won't be necessary when core::mem::MaybeUninit - // stabilizes because heapless constructors will work in const context - #[doc = #free_symbol] - static mut #free_alias: rtfm::export::MaybeUninit< + if cfg!(feature = "nightly") { + let inits = (0..capacity).map(|_| quote!(rtfm::export::MaybeUninit::uninitialized())); + + items.push(quote!( + #[doc = #free_symbol] + static mut #free_alias: rtfm::export::FreeQueue<#capacity_ty> = unsafe { + rtfm::export::FreeQueue::new_sc() + }; + + #[doc = #inputs_symbol] + static mut #inputs_alias: [rtfm::export::MaybeUninit<#ty>; #capacity_lit] = + [#(#inits),*]; + )); + } else { + items.push(quote!( + #[doc = #free_symbol] + static mut #free_alias: rtfm::export::MaybeUninit< rtfm::export::FreeQueue<#capacity_ty> - > = rtfm::export::MaybeUninit::uninitialized(); + > = rtfm::export::MaybeUninit::uninitialized(); + #[doc = #inputs_symbol] + static mut #inputs_alias: rtfm::export::MaybeUninit<[#ty; #capacity_lit]> = + rtfm::export::MaybeUninit::uninitialized(); + + )); + } + + items.push(quote!( #resource - #[doc = #inputs_symbol] - static mut #inputs_alias: rtfm::export::MaybeUninit<[#ty; #capacity_lit]> = - rtfm::export::MaybeUninit::uninitialized(); - #scheduleds_static )); @@ -1428,18 +1463,31 @@ fn dispatchers( &ready_alias, ty.clone(), ceiling, - quote!(#ready_alias.get_mut()), + if cfg!(feature = "nightly") { + quote!(&mut #ready_alias) + } else { + quote!(#ready_alias.get_mut()) + }, app, None, ); + + if cfg!(feature = "nightly") { + data.push(quote!( + #[doc = #symbol] + static mut #ready_alias: #ty = unsafe { #e::ReadyQueue::new_sc() }; + )); + } else { + data.push(quote!( + #[doc = #symbol] + static mut #ready_alias: #e::MaybeUninit<#ty> = #e::MaybeUninit::uninitialized(); + )); + } data.push(quote!( #[allow(dead_code)] #[allow(non_camel_case_types)] enum #enum_alias { #(#variants,)* } - #[doc = #symbol] - static mut #ready_alias: #e::MaybeUninit<#ty> = #e::MaybeUninit::uninitialized(); - #resource )); @@ -1462,9 +1510,14 @@ fn dispatchers( #[cfg(feature = "timer-queue")] () => { let scheduleds = &task_.scheduleds; + let scheduled = if cfg!(feature = "nightly") { + quote!(#scheduleds.get_unchecked(usize::from(index)).as_ptr()) + } else { + quote!(#scheduleds.get_ref().get_unchecked(usize::from(index))) + }; + baseline_let = quote!( - let baseline = - ptr::read(#scheduleds.get_ref().get_unchecked(usize::from(index))); + let baseline = ptr::read(#scheduled); ); call = quote!(#alias(&baseline, #pats)); } @@ -1475,12 +1528,24 @@ fn dispatchers( } }; + let (free_, input) = if cfg!(feature = "nightly") { + ( + quote!(#free), + quote!(#inputs.get_unchecked(usize::from(index)).as_ptr()), + ) + } else { + ( + quote!(#free.get_mut()), + quote!(#inputs.get_ref().get_unchecked(usize::from(index))), + ) + }; + quote!( #(#cfgs)* #enum_alias::#task => { #baseline_let - let input = ptr::read(#inputs.get_ref().get_unchecked(usize::from(index))); - #free.get_mut().split().0.enqueue_unchecked(index); + let input = ptr::read(#input); + #free_.split().0.enqueue_unchecked(index); let (#pats) = input; #call } @@ -1492,6 +1557,11 @@ fn dispatchers( let interrupt = &dispatcher.interrupt; let symbol = interrupt.to_string(); let alias = ctxt.ident_gen.mk_ident(None, false); + let ready_alias_ = if cfg!(feature = "nightly") { + quote!(#ready_alias) + } else { + quote!(#ready_alias.get_mut()) + }; dispatchers.push(quote!( #(#attrs)* #[export_name = #symbol] @@ -1502,7 +1572,7 @@ fn dispatchers( let _ = #device::interrupt::#interrupt; rtfm::export::run(|| { - while let Some((task, index)) = #ready_alias.get_mut().split().1.dequeue() { + while let Some((task, index)) = #ready_alias_.split().1.dequeue() { match task { #(#arms)* } @@ -1550,12 +1620,21 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt #[cfg(feature = "timer-queue")] () => { let scheduleds = &ctxt.tasks[name].scheduleds; - quote!( - ptr::write( - #scheduleds.get_mut().get_unchecked_mut(usize::from(index)), - #baseline, - ); - ) + if cfg!(feature = "nightly") { + quote!( + ptr::write( + #scheduleds.get_unchecked_mut(usize::from(index)).as_mut_ptr(), + #baseline, + ); + ) + } else { + quote!( + ptr::write( + #scheduleds.get_mut().get_unchecked_mut(usize::from(index)), + #baseline, + ); + ) + } } #[cfg(not(feature = "timer-queue"))] () => quote!(), @@ -1568,6 +1647,11 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt () => quote!(), }; + let input = if cfg!(feature = "nightly") { + quote!(#inputs.get_unchecked_mut(usize::from(index)).as_mut_ptr()) + } else { + quote!(#inputs.get_mut().get_unchecked_mut(usize::from(index))) + }; items.push(quote!( #[inline(always)] #(#cfgs)* @@ -1581,7 +1665,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt use rtfm::Mutex; if let Some(index) = (#free { #priority }).lock(|f| f.split().1.dequeue()) { - ptr::write(#inputs.get_mut().get_unchecked_mut(usize::from(index)), (#pats)); + ptr::write(#input, (#pats)); #scheduleds_write #ready { #priority }.lock(|rq| { @@ -1667,6 +1751,17 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream { let ty = tuple_ty(args); let pats = tuple_pat(args); + let input = if cfg!(feature = "nightly") { + quote!(#inputs.get_unchecked_mut(usize::from(index)).as_mut_ptr()) + } else { + quote!(#inputs.get_mut().get_unchecked_mut(usize::from(index))) + }; + + let scheduled = if cfg!(feature = "nightly") { + quote!(#scheduleds.get_unchecked_mut(usize::from(index)).as_mut_ptr()) + } else { + quote!(#scheduleds.get_mut().get_unchecked_mut(usize::from(index))) + }; items.push(quote!( #[inline(always)] #(#cfgs)* @@ -1680,11 +1775,8 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream { use rtfm::Mutex; if let Some(index) = (#free { #priority }).lock(|f| f.split().1.dequeue()) { - ptr::write(#inputs.get_mut().get_unchecked_mut(usize::from(index)), (#pats)); - ptr::write( - #scheduleds.get_mut().get_unchecked_mut(usize::from(index)), - instant, - ); + ptr::write(#input, (#pats)); + ptr::write(#scheduled, instant); let nr = rtfm::export::NotReady { instant, @@ -1772,12 +1864,20 @@ fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro let cap = mk_typenum_capacity(analysis.timer_queue.capacity, false); let tq = &ctxt.timer_queue; let symbol = format!("TIMER_QUEUE::{}", tq); - items.push(quote!( - #[doc = #symbol] - static mut #tq: - rtfm::export::MaybeUninit> = + if cfg!(feature = "nightly") { + items.push(quote!( + #[doc = #symbol] + static mut #tq: rtfm::export::MaybeUninit> = rtfm::export::MaybeUninit::uninitialized(); - )); + )); + } else { + items.push(quote!( + #[doc = #symbol] + static mut #tq: + rtfm::export::MaybeUninit> = + rtfm::export::MaybeUninit::uninitialized(); + )); + } items.push(mk_resource( ctxt, @@ -1785,7 +1885,7 @@ fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro tq, quote!(rtfm::export::TimerQueue<#enum_, #cap>), analysis.timer_queue.ceiling, - quote!(#tq.get_mut()), + quote!(&mut *#tq.as_mut_ptr()), app, None, )); @@ -1842,36 +1942,32 @@ fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream { let mut exprs = vec![]; - // FIXME(MaybeUninit) Because we are using a fake MaybeUninit we need to set the Option tag to - // Some; otherwise the get_ref and get_mut could result in UB. Also heapless collections can't - // be constructed in const context; we have to initialize them at runtime (i.e. here). + if !cfg!(feature = "nightly") { + // these are `MaybeUninit` arrays + for task in ctxt.tasks.values() { + let inputs = &task.inputs; + exprs.push(quote!(#inputs.set(core::mem::uninitialized());)) + } - // these are `MaybeUninit` arrays - for task in ctxt.tasks.values() { - let inputs = &task.inputs; - exprs.push(quote!(#inputs.set(core::mem::uninitialized());)) + #[cfg(feature = "timer-queue")] + for task in ctxt.tasks.values() { + let scheduleds = &task.scheduleds; + exprs.push(quote!(#scheduleds.set(core::mem::uninitialized());)) + } + + // these are `MaybeUninit` `ReadyQueue`s + for dispatcher in ctxt.dispatchers.values() { + let rq = &dispatcher.ready_queue; + exprs.push(quote!(#rq.set(rtfm::export::ReadyQueue::new_sc());)) + } + + // these are `MaybeUninit` `FreeQueue`s + for task in ctxt.tasks.values() { + let fq = &task.free_queue; + exprs.push(quote!(#fq.set(rtfm::export::FreeQueue::new_sc());)) + } } - #[cfg(feature = "timer-queue")] - for task in ctxt.tasks.values() { - let scheduleds = &task.scheduleds; - exprs.push(quote!(#scheduleds.set(core::mem::uninitialized());)) - } - - // these are `MaybeUninit` `ReadyQueue`s - for dispatcher in ctxt.dispatchers.values() { - let rq = &dispatcher.ready_queue; - exprs.push(quote!(#rq.set(rtfm::export::ReadyQueue::new_sc());)) - } - - // these are `MaybeUninit` `FreeQueue`s - for task in ctxt.tasks.values() { - let fq = &task.free_queue; - exprs.push(quote!(#fq.set(rtfm::export::FreeQueue::new_sc());)) - } - - // end-of-FIXME - // Initialize the timer queue if !analysis.timer_queue.tasks.is_empty() { let tq = &ctxt.timer_queue; @@ -1881,10 +1977,15 @@ fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Toke // Populate the `FreeQueue`s for (name, task) in &ctxt.tasks { let fq = &task.free_queue; + let fq_ = if cfg!(feature = "nightly") { + quote!(#fq) + } else { + quote!(#fq.get_mut()) + }; let capacity = analysis.capacities[name]; exprs.push(quote!( for i in 0..#capacity { - #fq.get_mut().enqueue_unchecked(i); + #fq_.enqueue_unchecked(i); } )) } diff --git a/src/export.rs b/src/export.rs index 6eae65f280..f8fc8157cd 100644 --- a/src/export.rs +++ b/src/export.rs @@ -1,8 +1,10 @@ //! IMPLEMENTATION DETAILS. DO NOT USE ANYTHING IN THIS MODULE -#[cfg(not(debug_assertions))] +#[cfg(all(not(feature = "nightly"), not(debug_assertions)))] use core::hint; -use core::{cell::Cell, ptr, u8}; +#[cfg(not(feature = "nightly"))] +use core::ptr; +use core::{cell::Cell, u8}; #[cfg(armv7m)] use cortex_m::register::basepri; @@ -64,17 +66,72 @@ impl Priority { } } -// TODO(MaybeUninit) Until core::mem::MaybeUninit is stabilized we use our own (inefficient) -// implementation +#[cfg(feature = "nightly")] +pub struct MaybeUninit { + // we newtype so the end-user doesn't need `#![feature(maybe_uninit)]` in their code + inner: core::mem::MaybeUninit, +} + +#[cfg(feature = "nightly")] +impl MaybeUninit { + pub const fn uninitialized() -> Self { + MaybeUninit { + inner: core::mem::MaybeUninit::uninitialized(), + } + } + + pub fn as_ptr(&self) -> *const T { + self.inner.as_ptr() + } + + pub fn as_mut_ptr(&mut self) -> *mut T { + self.inner.as_mut_ptr() + } + + pub fn set(&mut self, value: T) -> &mut T { + self.inner.set(value) + } +} + +#[cfg(not(feature = "nightly"))] pub struct MaybeUninit { value: Option, } +#[cfg(not(feature = "nightly"))] impl MaybeUninit { pub const fn uninitialized() -> Self { MaybeUninit { value: None } } + pub fn as_ptr(&self) -> *const T { + if let Some(x) = self.value.as_ref() { + x + } else { + match () { + // Try to catch UB when compiling in release with debug assertions enabled + #[cfg(debug_assertions)] + () => unreachable!(), + #[cfg(not(debug_assertions))] + () => unsafe { hint::unreachable_unchecked() }, + } + } + } + + pub fn as_mut_ptr(&mut self) -> *mut T { + if let Some(x) = self.value.as_mut() { + x + } else { + match () { + // Try to catch UB when compiling in release with debug assertions enabled + #[cfg(debug_assertions)] + () => unreachable!(), + #[cfg(not(debug_assertions))] + () => unsafe { hint::unreachable_unchecked() }, + } + } + } + pub unsafe fn get_ref(&self) -> &T { if let Some(x) = self.value.as_ref() { x diff --git a/src/lib.rs b/src/lib.rs index 9914aaf430..6c79f6c785 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,7 @@ //! [`Instant`]: struct.Instant.html //! [`Duration`]: struct.Duration.html +#![cfg_attr(feature = "nightly", feature(maybe_uninit))] #![deny(missing_docs)] #![deny(warnings)] #![no_std] From c8df71adf0407050b2b0fd358c22fae6e2dc9ebf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 15 Feb 2019 20:16:45 +0100 Subject: [PATCH 2/6] ci: test the nightly feature --- ci/script.sh | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/ci/script.sh b/ci/script.sh index 4b9cd22d39..9bba8b35df 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -33,6 +33,11 @@ arm_example() { main() { local T=$TARGET + local nightly="" + + if [ $TRAVIS_RUST_VERSION = nightly ]; then + nightly="nightly" + fi mkdir -p ci/builds @@ -41,12 +46,12 @@ main() { case $TRAVIS_RUST_VERSION in nightly*) # TODO how to run a subset of these tests when timer-queue is disabled? - cargo test --features timer-queue --test compiletest --target $T + cargo test --features "$nightly,timer-queue" --test compiletest --target $T esac cargo check --target $T if [ $TARGET != thumbv6m-none-eabi ]; then - cargo check --features timer-queue --target $T + cargo check --features "$nightly,timer-queue" --target $T fi if [ $TRAVIS_RUST_VERSION != nightly ]; then @@ -76,9 +81,9 @@ main() { return fi - cargo check --target $T --examples + cargo check --features "$nightly" --target $T --examples if [ $TARGET != thumbv6m-none-eabi ]; then - cargo check --features timer-queue --target $T --examples + cargo check --features "$nightly,timer-queue" --target $T --examples fi # run-pass tests @@ -115,13 +120,13 @@ main() { fi if [ $ex != types ]; then - arm_example "run" $ex "debug" "" "1" - arm_example "run" $ex "release" "" "1" + arm_example "run" $ex "debug" "$nightly" "1" + arm_example "run" $ex "release" "$nightly" "1" fi if [ $TARGET != thumbv6m-none-eabi ]; then - arm_example "run" $ex "debug" "timer-queue" "1" - arm_example "run" $ex "release" "timer-queue" "1" + arm_example "run" $ex "debug" "$nightly,timer-queue" "1" + arm_example "run" $ex "release" "$nightly,timer-queue" "1" fi done @@ -139,16 +144,16 @@ main() { fi if [ $ex != types ]; then - arm_example "build" $ex "debug" "" "2" + arm_example "build" $ex "debug" "$nightly" "2" cmp ci/builds/${ex}_debug_1.hex ci/builds/${ex}_debug_2.hex - arm_example "build" $ex "release" "" "2" + arm_example "build" $ex "release" "$nightly" "2" cmp ci/builds/${ex}_release_1.hex ci/builds/${ex}_release_2.hex fi if [ $TARGET != thumbv6m-none-eabi ]; then - arm_example "build" $ex "debug" "timer-queue" "2" + arm_example "build" $ex "debug" "$nightly,timer-queue" "2" cmp ci/builds/${ex}_timer-queue_debug_1.hex ci/builds/${ex}_timer-queue_debug_2.hex - arm_example "build" $ex "release" "timer-queue" "2" + arm_example "build" $ex "release" "$nightly,timer-queue" "2" cmp ci/builds/${ex}_timer-queue_release_1.hex ci/builds/${ex}_timer-queue_release_2.hex fi done From 16821c8315fc5e0f9bfbc6ddd7ca79cc2b1d5d40 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 15 Feb 2019 20:20:38 +0100 Subject: [PATCH 3/6] document the nightly feature --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 6c79f6c785..4c2fd9e019 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,11 @@ //! //! [`Instant`]: struct.Instant.html //! [`Duration`]: struct.Duration.html +//! +//! - `nightly`. Enabling this opt-in feature makes RTFM internally use the unstable +//! `core::mem::MaybeUninit` API and unstable `const_fn` language feature to reduce static memory +//! usage, runtime overhead and initialization overhead. This feature requires a nightly compiler +//! and may stop working at any time! #![cfg_attr(feature = "nightly", feature(maybe_uninit))] #![deny(missing_docs)] From fe70817653db4f53c3069fb733b73f06ddedfbcf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 15 Feb 2019 20:37:06 +0100 Subject: [PATCH 4/6] ci: report the size of built examples --- ci/script.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci/script.sh b/ci/script.sh index 9bba8b35df..93b44615a5 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -130,6 +130,7 @@ main() { fi done + local built=() cargo clean for ex in ${exs[@]}; do if [ $ex = ramfunc ] && [ $T = thumbv6m-none-eabi ]; then @@ -148,6 +149,8 @@ main() { cmp ci/builds/${ex}_debug_1.hex ci/builds/${ex}_debug_2.hex arm_example "build" $ex "release" "$nightly" "2" cmp ci/builds/${ex}_release_1.hex ci/builds/${ex}_release_2.hex + + built+=( $ex ) fi if [ $TARGET != thumbv6m-none-eabi ]; then @@ -157,6 +160,8 @@ main() { cmp ci/builds/${ex}_timer-queue_release_1.hex ci/builds/${ex}_timer-queue_release_2.hex fi done + + ( cd target/$TARGET/release/examples/ && size ${built[@]} ) esac } From 28ee83dfdd76ffad0487bad83636fa600084c834 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 15 Feb 2019 20:23:32 +0100 Subject: [PATCH 5/6] turn all potential UB into panics --- src/export.rs | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/src/export.rs b/src/export.rs index f8fc8157cd..495468e16d 100644 --- a/src/export.rs +++ b/src/export.rs @@ -1,7 +1,5 @@ //! IMPLEMENTATION DETAILS. DO NOT USE ANYTHING IN THIS MODULE -#[cfg(all(not(feature = "nightly"), not(debug_assertions)))] -use core::hint; #[cfg(not(feature = "nightly"))] use core::ptr; use core::{cell::Cell, u8}; @@ -98,6 +96,10 @@ pub struct MaybeUninit { value: Option, } +#[cfg(not(feature = "nightly"))] +const MSG: &str = + "you have hit a bug (UB) in RTFM implementation; try enabling this crate 'nightly' feature"; + #[cfg(not(feature = "nightly"))] impl MaybeUninit { pub const fn uninitialized() -> Self { @@ -108,13 +110,7 @@ impl MaybeUninit { if let Some(x) = self.value.as_ref() { x } else { - match () { - // Try to catch UB when compiling in release with debug assertions enabled - #[cfg(debug_assertions)] - () => unreachable!(), - #[cfg(not(debug_assertions))] - () => unsafe { hint::unreachable_unchecked() }, - } + unreachable!(MSG) } } @@ -122,13 +118,7 @@ impl MaybeUninit { if let Some(x) = self.value.as_mut() { x } else { - match () { - // Try to catch UB when compiling in release with debug assertions enabled - #[cfg(debug_assertions)] - () => unreachable!(), - #[cfg(not(debug_assertions))] - () => unsafe { hint::unreachable_unchecked() }, - } + unreachable!(MSG) } } @@ -136,13 +126,7 @@ impl MaybeUninit { if let Some(x) = self.value.as_ref() { x } else { - match () { - // Try to catch UB when compiling in release with debug assertions enabled - #[cfg(debug_assertions)] - () => unreachable!(), - #[cfg(not(debug_assertions))] - () => hint::unreachable_unchecked(), - } + unreachable!(MSG) } } @@ -150,13 +134,7 @@ impl MaybeUninit { if let Some(x) = self.value.as_mut() { x } else { - match () { - // Try to catch UB when compiling in release with debug assertions enabled - #[cfg(debug_assertions)] - () => unreachable!(), - #[cfg(not(debug_assertions))] - () => hint::unreachable_unchecked(), - } + unreachable!(MSG) } } From c6f9b2c0aa62fa3ceed6ac58928af15d9e3a58a2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 23 Feb 2019 20:35:54 +0100 Subject: [PATCH 6/6] fix ci --- ci/script.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ci/script.sh b/ci/script.sh index 93b44615a5..5cc79fbbce 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -146,18 +146,22 @@ main() { if [ $ex != types ]; then arm_example "build" $ex "debug" "$nightly" "2" - cmp ci/builds/${ex}_debug_1.hex ci/builds/${ex}_debug_2.hex + cmp ci/builds/${ex}_${nightly/nightly/nightly_}debug_1.hex \ + ci/builds/${ex}_${nightly/nightly/nightly_}debug_2.hex arm_example "build" $ex "release" "$nightly" "2" - cmp ci/builds/${ex}_release_1.hex ci/builds/${ex}_release_2.hex + cmp ci/builds/${ex}_${nightly/nightly/nightly_}release_1.hex \ + ci/builds/${ex}_${nightly/nightly/nightly_}release_2.hex built+=( $ex ) fi if [ $TARGET != thumbv6m-none-eabi ]; then arm_example "build" $ex "debug" "$nightly,timer-queue" "2" - cmp ci/builds/${ex}_timer-queue_debug_1.hex ci/builds/${ex}_timer-queue_debug_2.hex + cmp ci/builds/${ex}_${nightly}_timer-queue_debug_1.hex \ + ci/builds/${ex}_${nightly}_timer-queue_debug_2.hex arm_example "build" $ex "release" "$nightly,timer-queue" "2" - cmp ci/builds/${ex}_timer-queue_release_1.hex ci/builds/${ex}_timer-queue_release_2.hex + cmp ci/builds/${ex}_${nightly}_timer-queue_release_1.hex \ + ci/builds/${ex}_${nightly}_timer-queue_release_2.hex fi done