diff options
| author | bors <bors@rust-lang.org> | 2025-04-28 05:12:59 +0000 | 
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-04-28 05:12:59 +0000 | 
| commit | 0134651fb81314870903e21b1bcbdd993d75b61a (patch) | |
| tree | b912264968f9c6956b72422437f29c9dae64b14d /library/core/src | |
| parent | 21079f53a359d9fc82668d4175d49dafdb600563 (diff) | |
| parent | df3dd876c95f4dcf83a80c33fe9b5a59df78de45 (diff) | |
| download | rust-0134651fb81314870903e21b1bcbdd993d75b61a.tar.gz rust-0134651fb81314870903e21b1bcbdd993d75b61a.zip  | |
Auto merge of #136316 - GrigorenkoPV:generic_atomic, r=Mark-Simulacrum
Create `Atomic<T>` type alias (rebase) Rebase of #130543. Additional changes: - Switch from `allow` to `expect` for `private_bounds` on `AtomicPrimitive` - Unhide `AtomicPrimitive::AtomicInner` from docs, because rustdoc shows the definition `pub type Atomic<T> = <T as AtomicPrimitive>::AtomicInner;` and generated links for it. - `NonZero` did not have this issue, because they kept the new alias private before the direction was changed. - Use `Atomic<_>` in more places, including inside `Once`'s `Futex`. This is possible thanks to https://github.com/rust-lang/rust-clippy/pull/14125 The rest will either get moved back to #130543 or #130543 will be closed in favor of this instead. --- * ACP: https://github.com/rust-lang/libs-team/issues/443#event-14293381061 * Tracking issue: #130539
Diffstat (limited to 'library/core/src')
| -rw-r--r-- | library/core/src/sync/atomic.rs | 94 | 
1 files changed, 94 insertions, 0 deletions
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 9b1b13e7129..84c7f1aafe1 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -247,6 +247,100 @@ use crate::cell::UnsafeCell; use crate::hint::spin_loop; use crate::{fmt, intrinsics}; +trait Sealed {} + +/// A marker trait for primitive types which can be modified atomically. +/// +/// This is an implementation detail for <code>[Atomic]\<T></code> which may disappear or be replaced at any time. +/// +/// # Safety +/// +/// Types implementing this trait must be primitives that can be modified atomically. +/// +/// The associated `Self::AtomicInner` type must have the same size and bit validity as `Self`, +/// but may have a higher alignment requirement, so the following `transmute`s are sound: +/// +/// - `&mut Self::AtomicInner` as `&mut Self` +/// - `Self` as `Self::AtomicInner` or the reverse +#[unstable( + feature = "atomic_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +#[expect(private_bounds)] +pub unsafe trait AtomicPrimitive: Sized + Copy + Sealed { + /// Temporary implementation detail. + type AtomicInner: Sized; +} + +macro impl_atomic_primitive( + $Atom:ident $(<$T:ident>)? ($Primitive:ty), + size($size:literal), + align($align:literal) $(,)? +) { + impl $(<$T>)? Sealed for $Primitive {} + + #[unstable( + feature = "atomic_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + #[cfg(target_has_atomic_load_store = $size)] + unsafe impl $(<$T>)? AtomicPrimitive for $Primitive { + type AtomicInner = $Atom $(<$T>)?; + } +} + +impl_atomic_primitive!(AtomicBool(bool), size("8"), align(1)); +impl_atomic_primitive!(AtomicI8(i8), size("8"), align(1)); +impl_atomic_primitive!(AtomicU8(u8), size("8"), align(1)); +impl_atomic_primitive!(AtomicI16(i16), size("16"), align(2)); +impl_atomic_primitive!(AtomicU16(u16), size("16"), align(2)); +impl_atomic_primitive!(AtomicI32(i32), size("32"), align(4)); +impl_atomic_primitive!(AtomicU32(u32), size("32"), align(4)); +impl_atomic_primitive!(AtomicI64(i64), size("64"), align(8)); +impl_atomic_primitive!(AtomicU64(u64), size("64"), align(8)); +impl_atomic_primitive!(AtomicI128(i128), size("128"), align(16)); +impl_atomic_primitive!(AtomicU128(u128), size("128"), align(16)); + +#[cfg(target_pointer_width = "16")] +impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(2)); +#[cfg(target_pointer_width = "32")] +impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(4)); +#[cfg(target_pointer_width = "64")] +impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(8)); + +#[cfg(target_pointer_width = "16")] +impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(2)); +#[cfg(target_pointer_width = "32")] +impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(4)); +#[cfg(target_pointer_width = "64")] +impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(8)); + +#[cfg(target_pointer_width = "16")] +impl_atomic_primitive!(AtomicPtr<T>(*mut T), size("ptr"), align(2)); +#[cfg(target_pointer_width = "32")] +impl_atomic_primitive!(AtomicPtr<T>(*mut T), size("ptr"), align(4)); +#[cfg(target_pointer_width = "64")] +impl_atomic_primitive!(AtomicPtr<T>(*mut T), size("ptr"), align(8)); + +/// A memory location which can be safely modified from multiple threads. +/// +/// This has the same size and bit validity as the underlying type `T`. However, +/// the alignment of this type is always equal to its size, even on targets where +/// `T` has alignment less than its size. +/// +/// For more about the differences between atomic types and non-atomic types as +/// well as information about the portability of this type, please see the +/// [module-level documentation]. +/// +/// **Note:** This type is only available on platforms that support atomic loads +/// and stores of `T`. +/// +/// [module-level documentation]: crate::sync::atomic +#[unstable(feature = "generic_atomic", issue = "130539")] +pub type Atomic<T> = <T as AtomicPrimitive>::AtomicInner; + // Some architectures don't have byte-sized atomics, which results in LLVM // emulating them using a LL/SC loop. However for AtomicBool we can take // advantage of the fact that it only ever contains 0 or 1 and use atomic OR/AND  | 
