Skip to content

Commit

Permalink
Make from_ptr const fn on Rust 1.83+
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Oct 15, 2024
1 parent 710d179 commit 50532d8
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 65 deletions.
216 changes: 154 additions & 62 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,37 +586,42 @@ impl AtomicBool {
}

// TODO: update docs based on https://github.com/rust-lang/rust/pull/116762
/// Creates a new `AtomicBool` from a pointer.
///
/// # Safety
///
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can
/// be bigger than `align_of::<bool>()`).
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
/// behind `ptr` must have a happens-before relationship with atomic accesses via the returned
/// value (or vice-versa).
/// * In other words, time periods where the value is accessed atomically may not overlap
/// with periods where the value is accessed non-atomically.
/// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
/// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
/// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
/// from the same thread.
/// * If this atomic type is *not* lock-free:
/// * Any accesses to the value behind `ptr` must have a happens-before relationship
/// with accesses via the returned value (or vice-versa).
/// * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
/// be compatible with operations performed by this atomic type.
/// * This method must not be used to create overlapping or mixed-size atomic accesses, as
/// these are not supported by the memory model.
///
/// [valid]: core::ptr#safety
#[inline]
#[must_use]
pub unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a Self {
#[allow(clippy::cast_ptr_alignment)]
// SAFETY: guaranteed by the caller
unsafe { &*(ptr as *mut Self) }
const_fn! {
const_if: #[cfg(not(portable_atomic_no_const_mut_refs))];
/// Creates a new `AtomicBool` from a pointer.
///
/// This is `const fn` on Rust 1.83+.
///
/// # Safety
///
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can
/// be bigger than `align_of::<bool>()`).
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
/// behind `ptr` must have a happens-before relationship with atomic accesses via the returned
/// value (or vice-versa).
/// * In other words, time periods where the value is accessed atomically may not overlap
/// with periods where the value is accessed non-atomically.
/// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
/// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
/// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
/// from the same thread.
/// * If this atomic type is *not* lock-free:
/// * Any accesses to the value behind `ptr` must have a happens-before relationship
/// with accesses via the returned value (or vice-versa).
/// * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
/// be compatible with operations performed by this atomic type.
/// * This method must not be used to create overlapping or mixed-size atomic accesses, as
/// these are not supported by the memory model.
///
/// [valid]: core::ptr#safety
#[inline]
#[must_use]
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a Self {
#[allow(clippy::cast_ptr_alignment)]
// SAFETY: guaranteed by the caller
unsafe { &*(ptr as *mut Self) }
}
}

/// Returns `true` if operations on values of this type are lock-free.
Expand Down Expand Up @@ -1598,37 +1603,42 @@ impl<T> AtomicPtr<T> {
}

// TODO: update docs based on https://github.com/rust-lang/rust/pull/116762
/// Creates a new `AtomicPtr` from a pointer.
///
/// # Safety
///
/// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this
/// can be bigger than `align_of::<*mut T>()`).
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
/// behind `ptr` must have a happens-before relationship with atomic accesses via the returned
/// value (or vice-versa).
/// * In other words, time periods where the value is accessed atomically may not overlap
/// with periods where the value is accessed non-atomically.
/// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
/// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
/// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
/// from the same thread.
/// * If this atomic type is *not* lock-free:
/// * Any accesses to the value behind `ptr` must have a happens-before relationship
/// with accesses via the returned value (or vice-versa).
/// * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
/// be compatible with operations performed by this atomic type.
/// * This method must not be used to create overlapping or mixed-size atomic accesses, as
/// these are not supported by the memory model.
///
/// [valid]: core::ptr#safety
#[inline]
#[must_use]
pub unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a Self {
#[allow(clippy::cast_ptr_alignment)]
// SAFETY: guaranteed by the caller
unsafe { &*(ptr as *mut Self) }
const_fn! {
const_if: #[cfg(not(portable_atomic_no_const_mut_refs))];
/// Creates a new `AtomicPtr` from a pointer.
///
/// This is `const fn` on Rust 1.83+.
///
/// # Safety
///
/// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this
/// can be bigger than `align_of::<*mut T>()`).
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
/// behind `ptr` must have a happens-before relationship with atomic accesses via the returned
/// value (or vice-versa).
/// * In other words, time periods where the value is accessed atomically may not overlap
/// with periods where the value is accessed non-atomically.
/// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
/// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
/// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
/// from the same thread.
/// * If this atomic type is *not* lock-free:
/// * Any accesses to the value behind `ptr` must have a happens-before relationship
/// with accesses via the returned value (or vice-versa).
/// * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
/// be compatible with operations performed by this atomic type.
/// * This method must not be used to create overlapping or mixed-size atomic accesses, as
/// these are not supported by the memory model.
///
/// [valid]: core::ptr#safety
#[inline]
#[must_use]
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a Self {
#[allow(clippy::cast_ptr_alignment)]
// SAFETY: guaranteed by the caller
unsafe { &*(ptr as *mut Self) }
}
}

/// Returns `true` if operations on values of this type are lock-free.
Expand Down Expand Up @@ -2721,9 +2731,50 @@ let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
}

// TODO: update docs based on https://github.com/rust-lang/rust/pull/116762
#[cfg(not(portable_atomic_no_const_mut_refs))]
doc_comment! {
concat!("Creates a new reference to an atomic integer from a pointer.
This is `const fn` on Rust 1.83+.
# Safety
* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
can be bigger than `align_of::<", stringify!($int_type), ">()`).
* `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
* If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
behind `ptr` must have a happens-before relationship with atomic accesses via
the returned value (or vice-versa).
* In other words, time periods where the value is accessed atomically may not
overlap with periods where the value is accessed non-atomically.
* This requirement is trivially satisfied if `ptr` is never used non-atomically
for the duration of lifetime `'a`. Most use cases should be able to follow
this guideline.
* This requirement is also trivially satisfied if all accesses (atomic or not) are
done from the same thread.
* If this atomic type is *not* lock-free:
* Any accesses to the value behind `ptr` must have a happens-before relationship
with accesses via the returned value (or vice-versa).
* Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
be compatible with operations performed by this atomic type.
* This method must not be used to create overlapping or mixed-size atomic
accesses, as these are not supported by the memory model.
[valid]: core::ptr#safety"),
#[inline]
#[must_use]
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a Self {
#[allow(clippy::cast_ptr_alignment)]
// SAFETY: guaranteed by the caller
unsafe { &*(ptr as *mut Self) }
}
}
#[cfg(portable_atomic_no_const_mut_refs)]
doc_comment! {
concat!("Creates a new reference to an atomic integer from a pointer.
This is `const fn` on Rust 1.83+.
# Safety
* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
Expand Down Expand Up @@ -4107,9 +4158,50 @@ This type has the same in-memory representation as the underlying floating point
}

// TODO: update docs based on https://github.com/rust-lang/rust/pull/116762
#[cfg(not(portable_atomic_no_const_mut_refs))]
doc_comment! {
concat!("Creates a new reference to an atomic float from a pointer.
This is `const fn` on Rust 1.83+.
# Safety
* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
can be bigger than `align_of::<", stringify!($float_type), ">()`).
* `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
* If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
behind `ptr` must have a happens-before relationship with atomic accesses via
the returned value (or vice-versa).
* In other words, time periods where the value is accessed atomically may not
overlap with periods where the value is accessed non-atomically.
* This requirement is trivially satisfied if `ptr` is never used non-atomically
for the duration of lifetime `'a`. Most use cases should be able to follow
this guideline.
* This requirement is also trivially satisfied if all accesses (atomic or not) are
done from the same thread.
* If this atomic type is *not* lock-free:
* Any accesses to the value behind `ptr` must have a happens-before relationship
with accesses via the returned value (or vice-versa).
* Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
be compatible with operations performed by this atomic type.
* This method must not be used to create overlapping or mixed-size atomic
accesses, as these are not supported by the memory model.
[valid]: core::ptr#safety"),
#[inline]
#[must_use]
pub const unsafe fn from_ptr<'a>(ptr: *mut $float_type) -> &'a Self {
#[allow(clippy::cast_ptr_alignment)]
// SAFETY: guaranteed by the caller
unsafe { &*(ptr as *mut Self) }
}
}
#[cfg(portable_atomic_no_const_mut_refs)]
doc_comment! {
concat!("Creates a new reference to an atomic float from a pointer.
This is `const fn` on Rust 1.83+.
# Safety
* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
Expand Down
4 changes: 4 additions & 0 deletions src/tests/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,7 @@ macro_rules! __test_atomic_int_pub {
#[cfg(not(portable_atomic_no_const_mut_refs))]
const GET_MUT: $atomic_type = {
let mut a = <$atomic_type>::new(10);
let _ = unsafe { <$atomic_type>::from_ptr(a.as_ptr()) };
*a.get_mut() = 5;
a
};
Expand Down Expand Up @@ -1547,6 +1548,7 @@ macro_rules! __test_atomic_float_pub {
#[cfg(not(portable_atomic_no_const_mut_refs))]
const GET_MUT: $atomic_type = {
let mut a = <$atomic_type>::new(10.);
let _ = unsafe { <$atomic_type>::from_ptr(a.as_ptr()) };
*a.get_mut() = 5.;
a
};
Expand Down Expand Up @@ -1650,6 +1652,7 @@ macro_rules! __test_atomic_bool_pub {
#[cfg(not(portable_atomic_no_const_mut_refs))]
const GET_MUT: $atomic_type = {
let mut a = <$atomic_type>::new(true);
let _ = unsafe { <$atomic_type>::from_ptr(a.as_ptr()) };
*a.get_mut() = false;
a
};
Expand Down Expand Up @@ -1710,6 +1713,7 @@ macro_rules! __test_atomic_ptr_pub {
#[cfg(not(portable_atomic_no_const_mut_refs))]
const GET_MUT: $atomic_type = {
let mut a = <$atomic_type>::new(ptr::null_mut());
let _ = unsafe { <$atomic_type>::from_ptr(a.as_ptr()) };
*a.get_mut() = ptr::null_mut::<u8>().wrapping_add(1);
a
};
Expand Down
6 changes: 3 additions & 3 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,14 @@ macro_rules! const_fn {
(
const_if: #[cfg($($cfg:tt)+)];
$(#[$($attr:tt)*])*
$vis:vis const fn $($rest:tt)*
$vis:vis const $($rest:tt)*
) => {
#[cfg($($cfg)+)]
$(#[$($attr)*])*
$vis const fn $($rest)*
$vis const $($rest)*
#[cfg(not($($cfg)+))]
$(#[$($attr)*])*
$vis fn $($rest)*
$vis $($rest)*
};
}

Expand Down

0 comments on commit 50532d8

Please sign in to comment.