Skip to content

Commit

Permalink
Make AtomicCell::is_lock_free always const fn
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Nov 17, 2020
1 parent 9c3a8a8 commit 3d2369e
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 11 deletions.
2 changes: 0 additions & 2 deletions crossbeam-utils/Cargo.toml
Expand Up @@ -31,12 +31,10 @@ nightly = []

[dependencies]
cfg-if = "1"
const_fn = "0.4"
lazy_static = { version = "1.4.0", optional = true }

[build-dependencies]
autocfg = "1.0.0"

[dev-dependencies]
rand = "0.7.3"
rustversion = "1.0"
20 changes: 14 additions & 6 deletions crossbeam-utils/src/atomic/atomic_cell.rs
Expand Up @@ -12,7 +12,6 @@ use core::sync::atomic::{self, AtomicBool, Ordering};
use std::panic::{RefUnwindSafe, UnwindSafe};

use super::seq_lock::SeqLock;
use const_fn::const_fn;

/// A thread-safe mutable memory location.
///
Expand Down Expand Up @@ -106,7 +105,6 @@ impl<T> AtomicCell<T> {
/// // operations on them will have to use global locks for synchronization.
/// assert_eq!(AtomicCell::<[u8; 1000]>::is_lock_free(), false);
/// ```
#[const_fn("1.46")]
pub const fn is_lock_free() -> bool {
atomic_is_lock_free::<T>()
}
Expand Down Expand Up @@ -611,10 +609,9 @@ impl<T: Copy + fmt::Debug> fmt::Debug for AtomicCell<T> {
}

/// Returns `true` if values of type `A` can be transmuted into values of type `B`.
#[const_fn("1.46")]
const fn can_transmute<A, B>() -> bool {
// Sizes must be equal, but alignment of `A` must be greater or equal than that of `B`.
mem::size_of::<A>() == mem::size_of::<B>() && mem::align_of::<A>() >= mem::align_of::<B>()
(mem::size_of::<A>() == mem::size_of::<B>()) & (mem::align_of::<A>() >= mem::align_of::<B>())
}

/// Returns a reference to the global lock associated with the `AtomicCell` at address `addr`.
Expand Down Expand Up @@ -817,9 +814,20 @@ macro_rules! atomic {
}

/// Returns `true` if operations on `AtomicCell<T>` are lock-free.
#[const_fn("1.46")]
const fn atomic_is_lock_free<T>() -> bool {
atomic! { T, _a, true, false }
// HACK(taiki-e): This is equivalent to `atomic! { T, _a, true, false }`, but can be used in const fn even in Rust 1.36.
let is_lock_free = can_transmute::<T, AtomicUnit>() | can_transmute::<T, atomic::AtomicUsize>();
#[cfg(has_atomic_u8)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU8>();
#[cfg(has_atomic_u16)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU16>();
#[cfg(has_atomic_u32)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU32>();
#[cfg(has_atomic_u64)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU64>();
#[cfg(has_atomic_u128)]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU128>();
is_lock_free
}

/// Atomically reads data from `src`.
Expand Down
5 changes: 2 additions & 3 deletions crossbeam-utils/tests/atomic_cell.rs
Expand Up @@ -22,11 +22,10 @@ fn is_lock_free() {
assert_eq!(AtomicCell::<u128>::is_lock_free(), cfg!(has_atomic_u128));
}

#[rustversion::since(1.46)]
#[test]
fn const_is_lock_free() {
const _: bool = AtomicCell::<usize>::is_lock_free();
const _: bool = AtomicCell::<isize>::is_lock_free();
const _U: bool = AtomicCell::<usize>::is_lock_free();
const _I: bool = AtomicCell::<isize>::is_lock_free();
}

#[test]
Expand Down

0 comments on commit 3d2369e

Please sign in to comment.