Skip to content

Commit

Permalink
Start preparing for static_mut_refs lint.
Browse files Browse the repository at this point in the history
This lint's inclusion in Rust 2024 is discussed in:
rust-lang/rust#114447

I'm assuming I'm doing the right thing because, frustratingly, that
issue doesn't actually suggest the right thing to do -- and in fact
denigrates the specific thing I'm doing here as an example of leading a
horse to water but not being able to make them drink.
  • Loading branch information
cbiffle committed Mar 2, 2024
1 parent d867e8b commit f39b28f
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 11 deletions.
19 changes: 11 additions & 8 deletions os/src/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,15 +474,18 @@ macro_rules! create_static_mutex {

assert_eq!(INIT.swap_polyfill(true, Ordering::SeqCst), false);

// Static mutex storage.
static mut M: MaybeUninit<$crate::mutex::Mutex<$t>> = MaybeUninit::uninit();
// Safety: we can produce a non-aliased reference to this thanks to the
// INIT check above. We can be confident we don't touch it again below
// thanks to the block scope.
let __m = unsafe {
static mut M: MaybeUninit<$crate::mutex::Mutex<$t>> = MaybeUninit::uninit();
&mut *core::ptr::addr_of_mut!(M)
};

// Safety: there are two things going on here:
// - Discharging the obligations of Mutex::new (which we'll do in a sec)
// - Write to a static mut, which is safe because of our INIT check
// above.
// Safety: this requires that we discharge the obligations of Mutex::new
// (which we'll do in a sec)
unsafe {
M = MaybeUninit::new(
__m.write(
ManuallyDrop::into_inner($crate::mutex::Mutex::new($contents))
);
}
Expand All @@ -491,7 +494,7 @@ macro_rules! create_static_mutex {
// in the program, so we can pin it as long as we don't touch M again
// below (which we do not).
let mut m: Pin<&'static mut _> = unsafe {
Pin::new_unchecked(&mut *M.as_mut_ptr())
Pin::new_unchecked(__m.assume_init_mut())
};

// Safety: the value has not been operated on since `new` except for
Expand Down
18 changes: 15 additions & 3 deletions testsuite/src/spsc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::mem::MaybeUninit;
use core::ptr::addr_of_mut;
use core::sync::atomic::{AtomicBool, Ordering};

use lilos::atomic::AtomicExt;
Expand All @@ -13,24 +14,35 @@ pub async fn test_stack() {

/// Queue on stack, storage in a static, because maybe the storage is big and
/// you want to account for it at link time.
///
/// NOTE: this will only complete successfully once! The second attempt will
/// panic. This is a consequence of how I'm managing aliasing of the static
/// buffer below.
pub async fn test_static_storage() {
static ONCE: AtomicBool = AtomicBool::new(false);
assert!(!ONCE.swap_polyfill(true, Ordering::SeqCst));

static mut STORAGE: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
let mut q = Queue::new(unsafe { &mut STORAGE });
let mut q = Queue::new(unsafe { &mut *addr_of_mut!(STORAGE) });
test_wherever(&mut q).await
}

/// Queue *and* storage in a static, because this makes the resulting Push and
/// Pop have `'static` life, so they can be shared with an ISR.
///
/// NOTE: this will only complete successfully once! The second attempt will
/// panic. This is a consequence of how I'm managing aliasing of the static
/// buffer below.
pub async fn test_static_everything() {
static ONCE: AtomicBool = AtomicBool::new(false);
assert!(!ONCE.swap_polyfill(true, Ordering::SeqCst));

static mut STORAGE: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
static mut Q: MaybeUninit<Queue<u8>> = MaybeUninit::uninit();
let q = unsafe {
Q.as_mut_ptr().write(Queue::new(&mut STORAGE));
&mut *Q.as_mut_ptr()
let q = &mut *addr_of_mut!(Q);
q.as_mut_ptr().write(Queue::new(&mut *addr_of_mut!(STORAGE)));
&mut *q.as_mut_ptr()
};
test_wherever(q).await
}
Expand Down

0 comments on commit f39b28f

Please sign in to comment.