Skip to main content

atomic_maybe_uninit/
lib.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3/*!
4<!-- Note: Document from sync-markdown-to-rustdoc:start through sync-markdown-to-rustdoc:end
5     is synchronized from README.md. Any changes to that range are not preserved. -->
6<!-- tidy:sync-markdown-to-rustdoc:start -->
7
8Atomic operations on potentially uninitialized integers.
9
10## Motivation
11
12Copying types containing uninitialized bytes (e.g., padding), via the standard library's atomic types
13is [undefined behavior because the copy goes through integers][undefined-behavior].
14
15This crate provides a way to soundly perform such operations.
16
17## Platform Support
18
19Currently, all CPU architectures supported by Rust (x86, x86_64, Arm, AArch64, Arm64EC, RISC-V, LoongArch, s390x, PowerPC, MIPS, SPARC, AVR, MSP430, Hexagon, M68k, C-SKY, and Xtensa) are supported.
20(You can use `cfg_{has,no}_*` macros to write code based on which primitive sizes are available for the current target and Rust version.)
21
22| target_arch                                 | primitives                                          | load/store | swap/CAS |
23| ------------------------------------------- | --------------------------------------------------- |:----------:|:--------:|
24| x86                                         | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64           | ✓          | ✓        |
25| x86_64                                      | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64           | ✓          | ✓        |
26| x86_64 (+cmpxchg16b) \[2]                   | i128,u128                                           | ✓          | ✓        |
27| arm (v6+ or Linux/Android)                  | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓\[1]    |
28| arm (except for M-profile) \[3]             | i64,u64                                             | ✓          | ✓        |
29| aarch64                                     | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64,i128,u128 | ✓          | ✓        |
30| arm64ec \[10]                               | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64,i128,u128 | ✓          | ✓        |
31| riscv32                                     | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓\[1]    |
32| riscv32 (+zacas) \[4]                       | i64,u64                                             | ✓          | ✓        |
33| riscv64                                     | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64           | ✓          | ✓\[1]    |
34| riscv64 (+zacas) \[4]                       | i128,u128                                           | ✓          | ✓        |
35| loongarch64                                 | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64           | ✓          | ✓        |
36| loongarch64 (+scq) \[5]                     | i128,u128                                           | ✓          | ✓        |
37| loongarch32 \[11]                           | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓        |
38| s390x \[10]                                 | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64,i128,u128 | ✓          | ✓        |
39| powerpc \[12]                               | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓        |
40| powerpc64 \[12]                             | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64           | ✓          | ✓        |
41| powerpc64 (+quadword-atomics) \[6] \[12]    | i128,u128                                           | ✓          | ✓        |
42| mips / mips32r6 (experimental \[13])        | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓        |
43| mips64 / mips64r6 (experimental \[13])      | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64           | ✓          | ✓        |
44| sparc (experimental \[13])                  | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓\[1]    |
45| sparc (+v8plus) \[8] (experimental \[13])   | i64,u64                                             | ✓          | ✓        |
46| sparc64 (experimental \[13])                | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64           | ✓          | ✓        |
47| avr (experimental \[13])                    | isize,usize,i8,u8,i16,u16                           | ✓          | ✓        |
48| msp430 (experimental \[13])                 | isize,usize,i8,u8,i16,u16                           | ✓          | ✓        |
49| hexagon (experimental \[13])                | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64           | ✓          | ✓        |
50| m68k (experimental \[13])                   | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓\[1]    |
51| m68k (+isa-68020) \[9] (experimental \[13]) | i64,u64                                             | ✓          | ✓        |
52| csky (experimental \[13])                   | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓\[1]    |
53| xtensa (experimental \[13])                 | isize,usize,i8,u8,i16,u16,i32,u32                   | ✓          | ✓\[1]    |
54
55\[1] Arm's RMW operations are not available on Armv6-M (thumbv6m). RISC-V's RMW operations are not available on targets without the A (or G which means IMAFD) or Zalrsc or Zacas extension, such as riscv32i, riscv32imc, etc. 32-bit SPARC's RMW operations requires `v9` or `leoncasa` target feature (enabled by default on Linux). M68k's atomic RMW operations requires target-cpu M68020+ (enabled by default on Linux). C-SKY's atomic RMW operations requires target-cpu ck860\* or c860\* (enabled by default on the hard-float target). Xtensa's atomic RMW operations are not available on esp32s2.<br>
56\[2] Requires `cmpxchg16b` target feature (enabled by default on Apple, Windows (except Windows 7), and Fuchsia targets).<br>
57\[3] Armv6+ or Linux/Android, except for M-profile architecture such as thumbv6m, thumbv7m, etc.<br>
58\[4] Requires `zacas` target feature.<br>
59\[5] Requires `scq` target feature and Rust 1.97+.<br>
60\[6] Requires `quadword-atomics` target feature (enabled by default on powerpc64le).<br>
61\[8] Requires `v9` and `v8plus` target features (both enabled by default on Linux).<br>
62\[9] Requires target-cpu M68020 (Linux's default), M68030, M68040, or M68060 (Linux/NetBSD only).<br>
63\[10] Requires Rust 1.84+.<br>
64\[11] Requires Rust 1.91+.<br>
65\[12] Requires Rust 1.95+.<br>
66\[13] Requires nightly due to `#![feature(asm_experimental_arch)]`.<br>
67<!-- mips32r6/mips64r6: \[7] Requires Release 6 Paired LL/SC family of instructions.<br> -->
68
69See also [Atomic operation overview by architecture](https://github.com/taiki-e/atomic-maybe-uninit/blob/HEAD/src/arch/README.md)
70for more information about atomic operations in these architectures.
71
72Feel free to submit an issue if your target is not supported yet.
73
74## Limitations
75
76This crate uses inline assembly to implement atomic operations (this is currently the only sound way to perform atomic operations on uninitialized values), so it is currently not compatible with [Miri](https://github.com/rust-lang/miri/issues/11) and [most kinds of Sanitizers](https://github.com/google/sanitizers/issues/192).
77
78## Related Projects
79
80- [portable-atomic]: Portable atomic types including support for 128-bit atomics, atomic float, etc.
81- [atomic-memcpy]: Byte-wise atomic memcpy.
82- [asmtest]: A library for tracking generated assemblies.
83
84[asmtest]: https://github.com/taiki-e/asmtest
85[atomic-memcpy]: https://github.com/taiki-e/atomic-memcpy
86[portable-atomic]: https://github.com/taiki-e/portable-atomic
87[undefined-behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
88
89<!-- tidy:sync-markdown-to-rustdoc:end -->
90*/
91
92#![no_std]
93#![doc(test(
94    no_crate_inject,
95    attr(allow(
96        dead_code,
97        unused_variables,
98        clippy::undocumented_unsafe_blocks,
99        clippy::unused_trait_names,
100    ))
101))]
102#![warn(
103    // Lints that may help when writing public library.
104    missing_debug_implementations,
105    missing_docs,
106    clippy::alloc_instead_of_core,
107    clippy::exhaustive_enums,
108    clippy::exhaustive_structs,
109    clippy::impl_trait_in_params,
110    clippy::std_instead_of_alloc,
111    clippy::std_instead_of_core,
112    clippy::missing_inline_in_public_items,
113    // Code outside of cfg(test) shouldn't use float.
114    clippy::float_arithmetic,
115    // Code outside of cfg(test) shouldn't use code that can panic except for assertions. (overflow also cause panic if overflow check is enabled)
116    clippy::arithmetic_side_effects,
117)]
118#![cfg_attr(atomic_maybe_uninit_no_strict_provenance, allow(unstable_name_collisions))]
119#![allow(clippy::inline_always, clippy::unreadable_literal, clippy::used_underscore_items)]
120#![cfg_attr(
121    all(
122        atomic_maybe_uninit_unstable_asm_experimental_arch,
123        not(any(
124            // These cases currently don't use asm!
125            all(target_arch = "sparc", atomic_maybe_uninit_no_stbar),
126            all(target_arch = "mips", atomic_maybe_uninit_no_sync),
127        )),
128    ),
129    feature(asm_experimental_arch)
130)]
131
132// There are currently no 128-bit or higher builtin targets.
133// (Although some of our generic code is written with the future
134// addition of 128-bit targets in mind.)
135// Note that Rust (and C99) pointers must be at least 16-bit (i.e., 8-bit targets are impossible): https://github.com/rust-lang/rust/pull/49305
136#[cfg(not(any(
137    target_pointer_width = "16",
138    target_pointer_width = "32",
139    target_pointer_width = "64",
140)))]
141compile_error!(
142    "atomic-maybe-uninit currently only supports targets with {16,32,64}-bit pointer width; \
143     if you need support for others, \
144     please submit an issue at <https://github.com/taiki-e/atomic-maybe-uninit>"
145);
146
147#[cfg(test)]
148extern crate std;
149
150#[macro_use]
151mod utils;
152
153#[cfg(test)]
154#[macro_use]
155mod tests;
156
157pub mod raw;
158
159#[cfg(doc)]
160use core::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst};
161use core::{
162    cell::UnsafeCell,
163    fmt,
164    mem::{self, MaybeUninit},
165    sync::atomic::Ordering,
166};
167
168use self::raw::{AtomicCompareExchange, AtomicLoad, AtomicStore, AtomicSwap, Primitive};
169
170// -----------------------------------------------------------------------------
171// AtomicMaybeUninit
172
173/// A potentially uninitialized integer type which can be safely shared between threads.
174///
175/// This type has the same in-memory representation as the underlying
176/// value type, `MaybeUninit<T>`.
177/// However, the alignment of this type is always equal to its
178/// size, even on targets where `MaybeUninit<T>` has a
179/// lesser alignment.
180#[repr(C)]
181pub struct AtomicMaybeUninit<T: Primitive> {
182    v: UnsafeCell<MaybeUninit<T>>,
183    /// `[T::Align; 0]` ensures alignment is at least that of `T::Align`.
184    ///
185    /// This is needed because x86's u64 is 4-byte aligned and x86_64's u128 is
186    /// 8-byte aligned and atomic operations normally require alignment greater
187    /// than or equal to the size.
188    _align: [T::Align; 0],
189}
190
191impl<T: Primitive> From<MaybeUninit<T>> for AtomicMaybeUninit<T> {
192    /// Creates a new atomic value from a potentially uninitialized value.
193    #[inline]
194    fn from(v: MaybeUninit<T>) -> Self {
195        Self::new(v)
196    }
197}
198
199impl<T: Primitive> From<T> for AtomicMaybeUninit<T> {
200    /// Creates a new atomic value from an initialized value.
201    #[inline]
202    fn from(v: T) -> Self {
203        Self::new(MaybeUninit::new(v))
204    }
205}
206
207impl<T: Primitive> fmt::Debug for AtomicMaybeUninit<T> {
208    #[inline] // fmt is not hot path, but #[inline] on fmt seems to still be useful: https://github.com/rust-lang/rust/pull/117727
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        f.write_str(core::any::type_name::<Self>())
211    }
212}
213
214// Send is implicitly implemented.
215// SAFETY: `T` is `Send` and any data races are prevented by atomic intrinsics.
216unsafe impl<T: Primitive> Sync for AtomicMaybeUninit<T> {}
217
218// UnwindSafe is implicitly implemented.
219impl<T: Primitive> core::panic::RefUnwindSafe for AtomicMaybeUninit<T> {}
220
221impl<T: Primitive> AtomicMaybeUninit<T> {
222    /// Creates a new atomic value from a potentially uninitialized value.
223    ///
224    /// # Examples
225    ///
226    /// ```
227    /// use std::mem::MaybeUninit;
228    ///
229    /// use atomic_maybe_uninit::AtomicMaybeUninit;
230    ///
231    /// let v = AtomicMaybeUninit::new(MaybeUninit::new(5_i32));
232    ///
233    /// // Equivalent to:
234    /// let v = AtomicMaybeUninit::from(5_i32);
235    /// ```
236    #[inline]
237    #[must_use]
238    pub const fn new(v: MaybeUninit<T>) -> Self {
239        Self { v: UnsafeCell::new(v), _align: [] }
240    }
241
242    /// Creates a new reference to an atomic value from a pointer.
243    ///
244    /// # Safety
245    ///
246    /// * `ptr` must be aligned to `align_of::<AtomicMaybeUninit<T>>()` (note that on some platforms this
247    ///   can be bigger than `align_of::<MaybeUninit<T>>()`).
248    /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
249    /// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
250    ///   allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
251    ///   sizes, without synchronization.
252    ///
253    /// [valid]: core::ptr#safety
254    /// [Memory model for atomic accesses]: core::sync::atomic#memory-model-for-atomic-accesses
255    #[inline]
256    #[must_use]
257    pub const unsafe fn from_ptr<'a>(ptr: *mut MaybeUninit<T>) -> &'a Self {
258        // SAFETY: guaranteed by the caller
259        unsafe { &*ptr.cast::<Self>().cast_const() }
260    }
261
262    const_fn! {
263        const_if: #[cfg(not(atomic_maybe_uninit_no_const_mut_refs))];
264        /// Returns a mutable reference to the underlying value.
265        ///
266        /// This is safe because the mutable reference guarantees that no other threads are
267        /// concurrently accessing the atomic data.
268        ///
269        /// This is `const fn` on Rust 1.83+.
270        ///
271        /// # Examples
272        ///
273        /// ```
274        /// use std::mem::MaybeUninit;
275        ///
276        /// use atomic_maybe_uninit::AtomicMaybeUninit;
277        ///
278        /// let mut v = AtomicMaybeUninit::from(5_i32);
279        /// unsafe { assert_eq!((*v.get_mut()).assume_init(), 5) }
280        /// *v.get_mut() = MaybeUninit::new(10);
281        /// unsafe { assert_eq!((*v.get_mut()).assume_init(), 10) }
282        /// ```
283        #[inline]
284        pub const fn get_mut(&mut self) -> &mut MaybeUninit<T> {
285            // SAFETY: the mutable reference guarantees unique ownership.
286            // (core::cell::UnsafeCell::get_mut requires newer nightly)
287            unsafe { &mut *self.as_ptr() }
288        }
289    }
290
291    /// Consumes the atomic and returns the contained value.
292    ///
293    /// This is safe because passing `self` by value guarantees that no other threads are
294    /// concurrently accessing the atomic data.
295    ///
296    /// # Examples
297    ///
298    /// ```
299    /// use atomic_maybe_uninit::AtomicMaybeUninit;
300    ///
301    /// let v = AtomicMaybeUninit::from(5_i32);
302    /// unsafe { assert_eq!(v.into_inner().assume_init(), 5) }
303    /// ```
304    #[inline]
305    pub const fn into_inner(self) -> MaybeUninit<T> {
306        // SAFETY: AtomicMaybeUninit<T> and MaybeUninit<T> have the same size
307        // and in-memory representations, so they can be safely transmuted.
308        // (Equivalent to UnsafeCell::into_inner which is unstable in const context.)
309        unsafe { utils::transmute_copy_by_val::<Self, MaybeUninit<T>>(self) }
310    }
311
312    /// Loads a value from the atomic value.
313    ///
314    /// `load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
315    /// Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
316    ///
317    /// # Panics
318    ///
319    /// Panics if `order` is [`Release`] or [`AcqRel`].
320    ///
321    /// # Examples
322    ///
323    /// ```
324    /// use std::sync::atomic::Ordering;
325    ///
326    /// use atomic_maybe_uninit::AtomicMaybeUninit;
327    ///
328    /// let v = AtomicMaybeUninit::from(5_i32);
329    /// unsafe { assert_eq!(v.load(Ordering::Relaxed).assume_init(), 5) }
330    /// ```
331    #[inline]
332    #[cfg_attr(debug_assertions, track_caller)]
333    pub fn load(&self, order: Ordering) -> MaybeUninit<T>
334    where
335        T: AtomicLoad,
336    {
337        utils::assert_load_ordering(order);
338        // SAFETY: any data races are prevented by atomic intrinsics, the raw
339        // pointer passed in is valid because we got it from a reference,
340        // and we've checked the order is valid. Alignment is upheld because
341        // `PrimitivePriv`'s safety requirement ensures sufficient alignment
342        // of `T::Align`, and we got our `_align` field.
343        unsafe { T::atomic_load(self.v.get(), order) }
344    }
345
346    /// Stores a value into the atomic value.
347    ///
348    /// `store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
349    ///  Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
350    ///
351    /// # Panics
352    ///
353    /// Panics if `order` is [`Acquire`] or [`AcqRel`].
354    ///
355    /// # Examples
356    ///
357    /// ```
358    /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
359    ///
360    /// use atomic_maybe_uninit::AtomicMaybeUninit;
361    ///
362    /// let v = AtomicMaybeUninit::from(5_i32);
363    /// v.store(MaybeUninit::new(10), Ordering::Relaxed);
364    /// unsafe { assert_eq!(v.load(Ordering::Relaxed).assume_init(), 10) }
365    /// ```
366    #[inline]
367    #[cfg_attr(debug_assertions, track_caller)]
368    pub fn store(&self, val: MaybeUninit<T>, order: Ordering)
369    where
370        T: AtomicStore,
371    {
372        utils::assert_store_ordering(order);
373        // SAFETY: any data races are prevented by atomic intrinsics, the raw
374        // pointer passed in is valid because we got it from a reference,
375        // and we've checked the order is valid. Alignment is upheld because
376        // `PrimitivePriv`'s safety requirement ensures sufficient alignment
377        // of `T::Align`, and we got our `_align` field.
378        unsafe { T::atomic_store(self.v.get(), val, order) }
379    }
380
381    /// Stores a value into the atomic value, returning the previous value.
382    ///
383    /// `swap` takes an [`Ordering`] argument which describes the memory ordering
384    /// of this operation. All ordering modes are possible. Note that using
385    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
386    /// using [`Release`] makes the load part [`Relaxed`].
387    ///
388    /// # Examples
389    ///
390    /// ```
391    /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
392    ///
393    /// use atomic_maybe_uninit::AtomicMaybeUninit;
394    ///
395    /// let v = AtomicMaybeUninit::from(5_i32);
396    /// unsafe {
397    ///     assert_eq!(v.swap(MaybeUninit::new(10), Ordering::Relaxed).assume_init(), 5);
398    ///     assert_eq!(v.load(Ordering::Relaxed).assume_init(), 10);
399    /// }
400    /// ```
401    #[inline]
402    pub fn swap(&self, val: MaybeUninit<T>, order: Ordering) -> MaybeUninit<T>
403    where
404        T: AtomicSwap,
405    {
406        // SAFETY: any data races are prevented by atomic intrinsics and the raw
407        // pointer passed in is valid because we got it from a reference.
408        // Alignment is upheld because `PrimitivePriv`'s safety requirement
409        // ensures sufficient alignment of `T::Align`, and we got our `_align`
410        // field.
411        unsafe { T::atomic_swap(self.v.get(), val, order) }
412    }
413
414    /// Stores a value into the atomic value if the current value is the same as
415    /// the `current` value. Here, "the same" is determined using byte-wise
416    /// equality, not `PartialEq`.
417    ///
418    /// The return value is a result indicating whether the new value was written and
419    /// containing the previous value. On success this value is guaranteed to be equal to
420    /// `current`.
421    ///
422    /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
423    /// ordering of this operation. `success` describes the required ordering for the
424    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
425    /// `failure` describes the required ordering for the load operation that takes place when
426    /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
427    /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
428    /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
429    ///
430    /// # Panics
431    ///
432    /// Panics if `failure` is [`Release`], [`AcqRel`].
433    ///
434    /// # Notes
435    ///
436    /// Comparison of two values containing uninitialized bytes may fail even if
437    /// they are equivalent as Rust's type, because values can be byte-wise
438    /// inequal even when they are equal as Rust values.
439    ///
440    /// For example, the following example could be an infinite loop:
441    ///
442    /// ```no_run
443    /// use std::{
444    ///     mem::{self, MaybeUninit},
445    ///     sync::atomic::Ordering,
446    /// };
447    ///
448    /// use atomic_maybe_uninit::AtomicMaybeUninit;
449    ///
450    /// #[derive(Clone, Copy, PartialEq, Eq)]
451    /// #[repr(C, align(4))]
452    /// struct Test(u8, u16);
453    ///
454    /// unsafe {
455    ///     let x = mem::transmute::<Test, MaybeUninit<u32>>(Test(0, 0));
456    ///     let v = AtomicMaybeUninit::new(x);
457    ///     while v
458    ///         .compare_exchange(
459    ///             mem::transmute::<Test, MaybeUninit<u32>>(Test(0, 0)),
460    ///             mem::transmute::<Test, MaybeUninit<u32>>(Test(1, 0)),
461    ///             Ordering::AcqRel,
462    ///             Ordering::Acquire,
463    ///         )
464    ///         .is_err()
465    ///     {}
466    /// }
467    /// ```
468    ///
469    /// To work around this problem, you need to use a helper like the following.
470    ///
471    /// ```
472    /// # use std::{
473    /// #     mem::{self, MaybeUninit},
474    /// #     sync::atomic::Ordering,
475    /// # };
476    /// # use atomic_maybe_uninit::AtomicMaybeUninit;
477    /// # #[derive(Clone, Copy, PartialEq, Eq)]
478    /// # #[repr(C, align(4))]
479    /// # struct Test(u8, u16);
480    /// // Adapted from https://github.com/crossbeam-rs/crossbeam/blob/crossbeam-utils-0.8.10/crossbeam-utils/src/atomic/atomic_cell.rs#L1081-L1110
481    /// unsafe fn atomic_compare_exchange(
482    ///     v: &AtomicMaybeUninit<u32>,
483    ///     mut current: Test,
484    ///     new: Test,
485    /// ) -> Result<Test, Test> {
486    ///     let mut current_raw = unsafe { mem::transmute::<Test, MaybeUninit<u32>>(current) };
487    ///     let new_raw = unsafe { mem::transmute::<Test, MaybeUninit<u32>>(new) };
488    ///     loop {
489    ///         match v.compare_exchange_weak(current_raw, new_raw, Ordering::AcqRel, Ordering::Acquire)
490    ///         {
491    ///             Ok(_) => {
492    ///                 // The values are byte-wise equal; for `Test` we know this implies they are `PartialEq`-equal.
493    ///                 break Ok(current);
494    ///             }
495    ///             Err(previous_raw) => {
496    ///                 let previous = unsafe { mem::transmute::<MaybeUninit<u32>, Test>(previous_raw) };
497    ///
498    ///                 if !Test::eq(&previous, &current) {
499    ///                     break Err(previous);
500    ///                 }
501    ///
502    ///                 // The compare-exchange operation has failed and didn't store `new`. The
503    ///                 // failure is either spurious, or `previous` was semantically equal to
504    ///                 // `current` but not byte-equal. Let's retry with `previous` as the new
505    ///                 // `current`.
506    ///                 current = previous;
507    ///                 current_raw = previous_raw;
508    ///             }
509    ///         }
510    ///     }
511    /// }
512    /// # if cfg!(valgrind) { return; }
513    ///
514    /// unsafe {
515    ///     let x = mem::transmute::<Test, MaybeUninit<u32>>(Test(0, 0));
516    ///     let v = AtomicMaybeUninit::new(x);
517    ///     while atomic_compare_exchange(&v, Test(0, 0), Test(1, 0)).is_err() {}
518    /// }
519    /// ```
520    ///
521    /// Also, Valgrind reports "Conditional jump or move depends on uninitialized value(s)"
522    /// error if there is such a comparison -- which is correct, that's exactly
523    /// what the implementation does, but we are doing this inside inline
524    /// assembly so it should be fine. (Effectively we are adding partial
525    /// `freeze` capabilities to Rust via inline assembly. This pattern has not
526    /// been blessed by the language team, but is also not known to cause any
527    /// problems.)
528    ///
529    /// # Examples
530    ///
531    /// ```
532    /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
533    ///
534    /// use atomic_maybe_uninit::AtomicMaybeUninit;
535    ///
536    /// unsafe {
537    ///     let v = AtomicMaybeUninit::from(5_i32);
538    ///
539    ///     assert_eq!(
540    ///         v.compare_exchange(
541    ///             MaybeUninit::new(5),
542    ///             MaybeUninit::new(10),
543    ///             Ordering::Acquire,
544    ///             Ordering::Relaxed
545    ///         )
546    ///         .unwrap()
547    ///         .assume_init(),
548    ///         5
549    ///     );
550    ///     assert_eq!(v.load(Ordering::Relaxed).assume_init(), 10);
551    ///
552    ///     assert_eq!(
553    ///         v.compare_exchange(
554    ///             MaybeUninit::new(6),
555    ///             MaybeUninit::new(12),
556    ///             Ordering::SeqCst,
557    ///             Ordering::Acquire
558    ///         )
559    ///         .unwrap_err()
560    ///         .assume_init(),
561    ///         10
562    ///     );
563    ///     assert_eq!(v.load(Ordering::Relaxed).assume_init(), 10);
564    /// }
565    /// ```
566    #[doc(alias = "compare_and_swap")]
567    #[inline]
568    #[cfg_attr(debug_assertions, track_caller)]
569    pub fn compare_exchange(
570        &self,
571        current: MaybeUninit<T>,
572        new: MaybeUninit<T>,
573        success: Ordering,
574        failure: Ordering,
575    ) -> Result<MaybeUninit<T>, MaybeUninit<T>>
576    where
577        T: AtomicCompareExchange,
578    {
579        utils::assert_compare_exchange_ordering(success, failure);
580        // SAFETY: any data races are prevented by atomic intrinsics and the raw
581        // pointer passed in is valid because we got it from a reference.
582        // Alignment is upheld because `PrimitivePriv`'s safety requirement
583        // ensures sufficient alignment of `T::Align`, and we got our `_align`
584        // field.
585        let (out, ok) =
586            unsafe { T::atomic_compare_exchange(self.v.get(), current, new, success, failure) };
587        if ok { Ok(out) } else { Err(out) }
588    }
589
590    /// Stores a value into the atomic value if the current value is the same as
591    /// the `current` value. Here, "the same" is determined using byte-wise
592    /// equality, not `PartialEq`.
593    ///
594    /// This function is allowed to spuriously fail even when the comparison succeeds,
595    /// which can result in more efficient code on some platforms. The return value
596    /// is a result indicating whether the new value was written and containing
597    /// the previous value.
598    ///
599    /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
600    /// ordering of this operation. `success` describes the required ordering for the
601    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
602    /// `failure` describes the required ordering for the load operation that takes place when
603    /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
604    /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
605    /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
606    ///
607    /// # Panics
608    ///
609    /// Panics if `failure` is [`Release`], [`AcqRel`].
610    ///
611    /// # Notes
612    ///
613    /// Comparison of two values containing uninitialized bytes may fail even if
614    /// they are equivalent as Rust's type, because values can be byte-wise
615    /// inequal even when they are equal as Rust values.
616    ///
617    /// See [`compare_exchange`](Self::compare_exchange) for details.
618    ///
619    /// # Examples
620    ///
621    /// ```
622    /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
623    ///
624    /// use atomic_maybe_uninit::AtomicMaybeUninit;
625    ///
626    /// let v = AtomicMaybeUninit::from(5_i32);
627    ///
628    /// unsafe {
629    ///     let mut old = v.load(Ordering::Relaxed);
630    ///     loop {
631    ///         let new = old.assume_init() * 2;
632    ///         match v.compare_exchange_weak(
633    ///             old,
634    ///             MaybeUninit::new(new),
635    ///             Ordering::SeqCst,
636    ///             Ordering::Relaxed,
637    ///         ) {
638    ///             Ok(_) => break,
639    ///             Err(x) => old = x,
640    ///         }
641    ///     }
642    /// }
643    /// ```
644    #[doc(alias = "compare_and_swap")]
645    #[inline]
646    #[cfg_attr(debug_assertions, track_caller)]
647    pub fn compare_exchange_weak(
648        &self,
649        current: MaybeUninit<T>,
650        new: MaybeUninit<T>,
651        success: Ordering,
652        failure: Ordering,
653    ) -> Result<MaybeUninit<T>, MaybeUninit<T>>
654    where
655        T: AtomicCompareExchange,
656    {
657        utils::assert_compare_exchange_ordering(success, failure);
658        // SAFETY: any data races are prevented by atomic intrinsics and the raw
659        // pointer passed in is valid because we got it from a reference.
660        // Alignment is upheld because `PrimitivePriv`'s safety requirement
661        // ensures sufficient alignment of `T::Align`, and we got our `_align`
662        // field.
663        let (out, ok) = unsafe {
664            T::atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
665        };
666        if ok { Ok(out) } else { Err(out) }
667    }
668
669    /// An alias for [`try_update`](Self::try_update).
670    #[inline]
671    #[deprecated(note = "renamed to `try_update` for consistency")]
672    pub fn fetch_update<F>(
673        &self,
674        set_order: Ordering,
675        fetch_order: Ordering,
676        f: F,
677    ) -> Result<MaybeUninit<T>, MaybeUninit<T>>
678    where
679        F: FnMut(MaybeUninit<T>) -> Option<MaybeUninit<T>>,
680        T: AtomicCompareExchange,
681    {
682        self.try_update(set_order, fetch_order, f)
683    }
684
685    /// Fetches the value, and applies a function to it that returns an optional
686    /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
687    /// `Err(previous_value)`.
688    /// See also: [`update`](Self::update).
689    ///
690    /// Note: This may call the function multiple times if the value has been changed from other threads in
691    /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
692    /// only once to the stored value.
693    ///
694    /// `try_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
695    /// The first describes the required ordering for when the operation finally succeeds while the second
696    /// describes the required ordering for loads. These correspond to the success and failure orderings of
697    /// [`compare_exchange`](Self::compare_exchange) respectively.
698    ///
699    /// Using [`Acquire`] as success ordering makes the store part
700    /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
701    /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
702    ///
703    /// # Panics
704    ///
705    /// Panics if `fetch_order` is [`Release`], [`AcqRel`].
706    ///
707    /// # Considerations
708    ///
709    /// This method is not magic; it is not provided by the hardware, and does not act like a
710    /// critical section or mutex.
711    ///
712    /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
713    /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
714    /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
715    /// of the atomic is not in and of itself sufficient to ensure any required preconditions.
716    ///
717    /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
718    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
719    ///
720    /// # Examples
721    ///
722    /// ```
723    /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
724    ///
725    /// use atomic_maybe_uninit::AtomicMaybeUninit;
726    ///
727    /// unsafe {
728    ///     let v = AtomicMaybeUninit::from(5_i32);
729    ///     assert_eq!(
730    ///         v.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None).unwrap_err().assume_init(),
731    ///         5
732    ///     );
733    ///     assert_eq!(
734    ///         v.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(MaybeUninit::new(
735    ///             x.assume_init() + 1
736    ///         )))
737    ///         .unwrap()
738    ///         .assume_init(),
739    ///         5
740    ///     );
741    ///     assert_eq!(v.load(Ordering::SeqCst).assume_init(), 6);
742    /// }
743    /// ```
744    #[allow(clippy::impl_trait_in_params)] // Align to core::sync::atomic
745    #[inline]
746    pub fn try_update(
747        &self,
748        set_order: Ordering,
749        fetch_order: Ordering,
750        mut f: impl FnMut(MaybeUninit<T>) -> Option<MaybeUninit<T>>,
751    ) -> Result<MaybeUninit<T>, MaybeUninit<T>>
752    where
753        T: AtomicCompareExchange,
754    {
755        let mut prev = self.load(fetch_order);
756        while let Some(next) = f(prev) {
757            match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
758                x @ Ok(_) => return x,
759                Err(next_prev) => prev = next_prev,
760            }
761        }
762        Err(prev)
763    }
764
765    /// Fetches the value, applies a function to it that it return a new value.
766    /// The new value is stored and the old value is returned.
767    /// See also: [`try_update`](Self::try_update).
768    ///
769    /// Note: This may call the function multiple times if the value has been changed from other threads in
770    /// the meantime, but the function will have been applied only once to the stored value.
771    ///
772    /// `update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
773    /// The first describes the required ordering for when the operation finally succeeds while the second
774    /// describes the required ordering for loads. These correspond to the success and failure orderings of
775    /// [`compare_exchange`](Self::compare_exchange) respectively.
776    ///
777    /// Using [`Acquire`] as success ordering makes the store part
778    /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
779    /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
780    ///
781    /// # Panics
782    ///
783    /// Panics if `fetch_order` is [`Release`], [`AcqRel`].
784    ///
785    /// # Considerations
786    ///
787    /// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap
788    /// This method is not magic; it is not provided by the hardware, and does not act like a
789    /// critical section or mutex.
790    ///
791    /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
792    /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
793    /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
794    /// of the atomic is not in and of itself sufficient to ensure any required preconditions.
795    ///
796    /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
797    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
798    ///
799    /// # Examples
800    ///
801    /// ```
802    /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
803    ///
804    /// use atomic_maybe_uninit::AtomicMaybeUninit;
805    ///
806    /// unsafe {
807    ///     let v = AtomicMaybeUninit::from(5_i32);
808    ///     assert_eq!(
809    ///         v.update(Ordering::SeqCst, Ordering::SeqCst, |x| MaybeUninit::new(x.assume_init() + 1))
810    ///             .assume_init(),
811    ///         5
812    ///     );
813    ///     assert_eq!(
814    ///         v.update(Ordering::SeqCst, Ordering::SeqCst, |x| MaybeUninit::new(x.assume_init() + 1))
815    ///             .assume_init(),
816    ///         6
817    ///     );
818    ///     assert_eq!(v.load(Ordering::SeqCst).assume_init(), 7);
819    /// }
820    /// ```
821    #[allow(clippy::impl_trait_in_params)] // Align to core::sync::atomic
822    #[inline]
823    pub fn update(
824        &self,
825        set_order: Ordering,
826        fetch_order: Ordering,
827        mut f: impl FnMut(MaybeUninit<T>) -> MaybeUninit<T>,
828    ) -> MaybeUninit<T>
829    where
830        T: AtomicCompareExchange,
831    {
832        let mut prev = self.load(fetch_order);
833        loop {
834            match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
835                Ok(x) => break x,
836                Err(next_prev) => prev = next_prev,
837            }
838        }
839    }
840
841    /// Returns a mutable pointer to the underlying value.
842    ///
843    /// Doing non-atomic reads and writes on the resulting value can be a data race.
844    /// This method is mostly useful for FFI, where the function signature may use
845    /// `*mut T` instead of `&AtomicMaybeUninit<T>`.
846    ///
847    /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
848    /// atomic types work with interior mutability. All modifications of an atomic change the value
849    /// through a shared reference, and can do so safely as long as they use atomic operations. Any
850    /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the
851    /// requirements of the [memory model].
852    ///
853    /// [memory model]: core::sync::atomic#memory-model-for-atomic-accesses
854    #[inline]
855    pub const fn as_ptr(&self) -> *mut MaybeUninit<T> {
856        self.v.get()
857    }
858}
859
860macro_rules! int {
861    ($($ty:ident),* => $align:ident) => {$(
862        impl raw::Primitive for $ty {}
863        const _: () = {
864            assert!(mem::size_of::<AtomicMaybeUninit<$ty>>() == mem::size_of::<$ty>());
865            assert!(mem::align_of::<AtomicMaybeUninit<$ty>>() >= mem::size_of::<$ty>());
866        };
867        // SAFETY: the static assertion above ensures safety requirement.
868        unsafe impl private::PrimitivePriv for $ty {
869            type Align = private::$align;
870        }
871        impl AtomicMaybeUninit<$ty> {
872            /// Creates a new atomic value from a potentially uninitialized value.
873            #[inline]
874            #[must_use]
875            // TODO(semver): remove in the next breaking release.
876            #[deprecated(
877                since = "0.3.10",
878                note = "use `new` instead because it is now always `const fn`"
879            )]
880            pub const fn const_new(v: MaybeUninit<$ty>) -> Self {
881                Self { v: UnsafeCell::new(v), _align: [] }
882            }
883        }
884    )*};
885}
886int!(i8, u8 => Align1);
887int!(i16, u16 => Align2);
888int!(i32, u32 => Align4);
889int!(i64, u64 => Align8);
890int!(i128, u128 => Align16);
891int!(isize, usize => AlignPtr);
892
893#[cfg(target_pointer_width = "16")]
894pub use {cfg_has_atomic_16 as cfg_has_atomic_ptr, cfg_no_atomic_16 as cfg_no_atomic_ptr};
895#[cfg(target_pointer_width = "32")]
896pub use {cfg_has_atomic_32 as cfg_has_atomic_ptr, cfg_no_atomic_32 as cfg_no_atomic_ptr};
897#[cfg(target_pointer_width = "64")]
898pub use {cfg_has_atomic_64 as cfg_has_atomic_ptr, cfg_no_atomic_64 as cfg_no_atomic_ptr};
899#[cfg(target_pointer_width = "128")]
900pub use {cfg_has_atomic_128 as cfg_has_atomic_ptr, cfg_no_atomic_128 as cfg_no_atomic_ptr};
901
902// -----------------------------------------------------------------------------
903// Internals
904
905#[cfg_attr(
906    any(target_arch = "aarch64", all(target_arch = "arm64ec", not(atomic_maybe_uninit_no_asm))),
907    path = "arch/aarch64.rs"
908)]
909#[cfg_attr(
910    all(
911        target_arch = "arm",
912        // Pre-v6 Arm has no Data Memory Barrier (DMB) operation, so we cannot implement non-relaxed atomics.
913        // However, Linux kernel provides helpers for it, so we can provide it on Linux/Android.
914        any(
915            target_feature = "v6",
916            atomic_maybe_uninit_target_feature = "v6",
917            target_os = "linux",
918            target_os = "android",
919        ),
920        // Use armv8.rs for Armv8+.
921        not(any(
922            target_feature = "v8",
923            target_feature = "acquire-release",
924            atomic_maybe_uninit_target_feature = "acquire-release",
925        )),
926    ),
927    path = "arch/arm.rs"
928)]
929#[cfg_attr(
930    all(
931        target_arch = "arm",
932        // Use arm.rs for pre-v8 Arm.
933        any(
934            target_feature = "v8",
935            target_feature = "acquire-release",
936            atomic_maybe_uninit_target_feature = "acquire-release",
937        ),
938    ),
939    path = "arch/armv8.rs"
940)]
941#[cfg_attr(
942    all(target_arch = "avr", atomic_maybe_uninit_unstable_asm_experimental_arch),
943    path = "arch/avr.rs"
944)]
945#[cfg_attr(
946    all(target_arch = "csky", atomic_maybe_uninit_unstable_asm_experimental_arch),
947    path = "arch/csky.rs"
948)]
949#[cfg_attr(
950    all(target_arch = "hexagon", atomic_maybe_uninit_unstable_asm_experimental_arch),
951    path = "arch/hexagon.rs"
952)]
953#[cfg_attr(
954    any(
955        all(target_arch = "loongarch32", not(atomic_maybe_uninit_no_asm)),
956        target_arch = "loongarch64",
957    ),
958    path = "arch/loongarch.rs"
959)]
960#[cfg_attr(
961    all(target_arch = "m68k", atomic_maybe_uninit_unstable_asm_experimental_arch),
962    path = "arch/m68k.rs"
963)]
964#[cfg_attr(
965    all(
966        any(
967            // MIPS-I has no SYNC, so we cannot implement non-relaxed atomics.
968            all(target_arch = "mips", not(atomic_maybe_uninit_no_sync)),
969            target_arch = "mips32r6",
970            target_arch = "mips64",
971            target_arch = "mips64r6",
972        ),
973        atomic_maybe_uninit_unstable_asm_experimental_arch,
974    ),
975    path = "arch/mips.rs"
976)]
977#[cfg_attr(
978    all(target_arch = "msp430", atomic_maybe_uninit_unstable_asm_experimental_arch),
979    path = "arch/msp430.rs"
980)]
981#[cfg_attr(
982    all(any(target_arch = "powerpc", target_arch = "powerpc64"), not(atomic_maybe_uninit_no_asm)),
983    path = "arch/powerpc.rs"
984)]
985#[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), path = "arch/riscv.rs")]
986#[cfg_attr(all(target_arch = "s390x", not(atomic_maybe_uninit_no_asm)), path = "arch/s390x.rs")]
987#[cfg_attr(
988    all(
989        any(
990            // SPARC-V7 has no STBAR, so we cannot implement non-relaxed atomics.
991            all(target_arch = "sparc", not(atomic_maybe_uninit_no_stbar)),
992            target_arch = "sparc64",
993        ),
994        atomic_maybe_uninit_unstable_asm_experimental_arch,
995    ),
996    path = "arch/sparc.rs"
997)]
998#[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), path = "arch/x86.rs")]
999#[cfg_attr(
1000    all(target_arch = "xtensa", atomic_maybe_uninit_unstable_asm_experimental_arch),
1001    path = "arch/xtensa.rs"
1002)]
1003#[allow(missing_docs)] // For cfg_* macros.
1004mod arch;
1005
1006mod private {
1007    #![allow(missing_debug_implementations)]
1008
1009    use core::panic::{RefUnwindSafe, UnwindSafe};
1010
1011    /// This trait is private and cannot be implemented for types outside of `atomic-maybe-uninit`.
1012    ///
1013    /// # Safety
1014    ///
1015    /// The implementer must guarantee that `align_of::<Self::Align>() == size_of::<Self>()`.
1016    // Auto traits are needed to better docs.
1017    #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1018    pub unsafe trait PrimitivePriv:
1019        Copy + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe
1020    {
1021        // See _align field of AtomicMaybeUninit.
1022        type Align: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe;
1023    }
1024
1025    #[repr(align(1))]
1026    #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1027    pub struct Align1(#[allow(dead_code)] u8);
1028    #[repr(align(2))]
1029    #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1030    pub struct Align2(#[allow(dead_code)] u16);
1031    #[repr(align(4))]
1032    #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1033    pub struct Align4(#[allow(dead_code)] u32);
1034    #[repr(align(8))]
1035    #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1036    pub struct Align8(#[allow(dead_code)] u64);
1037    #[repr(align(16))]
1038    #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1039    pub struct Align16(#[allow(dead_code)] u128);
1040    #[cfg(target_pointer_width = "16")]
1041    pub(crate) type AlignPtr = Align2;
1042    #[cfg(target_pointer_width = "32")]
1043    pub(crate) type AlignPtr = Align4;
1044    #[cfg(target_pointer_width = "64")]
1045    pub(crate) type AlignPtr = Align8;
1046    #[cfg(target_pointer_width = "128")]
1047    pub(crate) type AlignPtr = Align16;
1048
1049    // Check that all cfg_ macros work.
1050    use crate::{
1051        AtomicMaybeUninit, cfg_has_atomic_8, cfg_has_atomic_16, cfg_has_atomic_32,
1052        cfg_has_atomic_64, cfg_has_atomic_128, cfg_has_atomic_cas, cfg_has_atomic_ptr,
1053        cfg_no_atomic_8, cfg_no_atomic_16, cfg_no_atomic_32, cfg_no_atomic_64, cfg_no_atomic_128,
1054        cfg_no_atomic_cas, cfg_no_atomic_ptr,
1055    };
1056    // TODO: make these type aliases public?
1057    cfg_has_atomic_8! {
1058        type _AtomicMaybeUninitI8 = AtomicMaybeUninit<i8>;
1059        type _AtomicMaybeUninitU8 = AtomicMaybeUninit<u8>;
1060    }
1061    cfg_no_atomic_8! {
1062        type _AtomicMaybeUninitI8 = AtomicMaybeUninit<i8>;
1063        type _AtomicMaybeUninitU8 = AtomicMaybeUninit<u8>;
1064    }
1065    cfg_has_atomic_16! {
1066        type _AtomicMaybeUninitI16 = AtomicMaybeUninit<i16>;
1067        type _AtomicMaybeUninitU16 = AtomicMaybeUninit<u16>;
1068    }
1069    cfg_no_atomic_16! {
1070        type _AtomicMaybeUninitI16 = AtomicMaybeUninit<i16>;
1071        type _AtomicMaybeUninitU16 = AtomicMaybeUninit<u16>;
1072    }
1073    cfg_has_atomic_32! {
1074        type _AtomicMaybeUninitI32 = AtomicMaybeUninit<i32>;
1075        type _AtomicMaybeUninitU32 = AtomicMaybeUninit<u32>;
1076    }
1077    cfg_no_atomic_32! {
1078        type _AtomicMaybeUninitI32 = AtomicMaybeUninit<i32>;
1079        type _AtomicMaybeUninitU32 = AtomicMaybeUninit<u32>;
1080    }
1081    cfg_has_atomic_64! {
1082        type _AtomicMaybeUninitI64 = AtomicMaybeUninit<i64>;
1083        type _AtomicMaybeUninitU64 = AtomicMaybeUninit<u64>;
1084    }
1085    cfg_no_atomic_64! {
1086        type _AtomicMaybeUninitI64 = AtomicMaybeUninit<i64>;
1087        type _AtomicMaybeUninitU64 = AtomicMaybeUninit<u64>;
1088    }
1089    cfg_has_atomic_128! {
1090        type _AtomicMaybeUninitI128 = AtomicMaybeUninit<i128>;
1091        type _AtomicMaybeUninitU128 = AtomicMaybeUninit<u128>;
1092    }
1093    cfg_no_atomic_128! {
1094        type _AtomicMaybeUninitI128 = AtomicMaybeUninit<i128>;
1095        type _AtomicMaybeUninitU128 = AtomicMaybeUninit<u128>;
1096    }
1097    cfg_has_atomic_ptr! {
1098        type _AtomicMaybeUninitIsize = AtomicMaybeUninit<isize>;
1099        type _AtomicMaybeUninitUsize = AtomicMaybeUninit<usize>;
1100    }
1101    cfg_no_atomic_ptr! {
1102        type _AtomicMaybeUninitIsize = AtomicMaybeUninit<isize>;
1103        type _AtomicMaybeUninitUsize = AtomicMaybeUninit<usize>;
1104    }
1105    cfg_has_atomic_cas! {
1106        type __AtomicMaybeUninitIsize = AtomicMaybeUninit<isize>;
1107        type __AtomicMaybeUninitUsize = AtomicMaybeUninit<usize>;
1108    }
1109    cfg_no_atomic_cas! {
1110        type __AtomicMaybeUninitIsize = AtomicMaybeUninit<isize>;
1111        type __AtomicMaybeUninitUsize = AtomicMaybeUninit<usize>;
1112    }
1113}