Upgrade atomic to 0.6.0 am: 839041b30b

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/atomic/+/2939603

Change-Id: Idf88a8335e8856f3a2933a3bfbcdf7c1e4db1af5
Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..8498c3a
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "79ace14a69d8d4a45cc7f6cd06ff0cbb5849b2fd"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..eb618e1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+language: rust
+sudo: false
+
+rust:
+- nightly
+- beta
+- stable
+- 1.45.0
+
+script:
+- cargo build
+- cargo test
+- cargo doc
+- if [ $TRAVIS_RUST_VERSION = nightly ]; then rustup target add aarch64-unknown-none; fi
+- if [ $TRAVIS_RUST_VERSION = nightly ]; then RUSTFLAGS="-Zcrate-attr=feature(integer_atomics)" cargo check --target=aarch64-unknown-none; fi
+
+notifications:
+  email: false
diff --git a/Android.bp b/Android.bp
index 6809e2e..9165de8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,23 +42,14 @@
     host_supported: true,
     crate_name: "atomic",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.5.1",
+    cargo_pkg_version: "0.6.0",
     srcs: ["src/lib.rs"],
     edition: "2018",
     features: [
         "fallback",
         "std",
     ],
-    cfgs: [
-        "has_atomic_i16",
-        "has_atomic_i32",
-        "has_atomic_i64",
-        "has_atomic_i8",
-        "has_atomic_u16",
-        "has_atomic_u32",
-        "has_atomic_u64",
-        "has_atomic_u8",
-    ],
+    rustlibs: ["libbytemuck"],
     apex_available: [
         "//apex_available:platform",
         "//apex_available:anyapex",
diff --git a/Cargo.toml b/Cargo.toml
index fedd21b..88db472 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,18 +12,26 @@
 [package]
 edition = "2018"
 name = "atomic"
-version = "0.5.1"
+version = "0.6.0"
 authors = ["Amanieu d'Antras <[email protected]>"]
 description = "Generic Atomic<T> wrapper type"
-documentation = "https://amanieu.github.io/atomic-rs/atomic/index.html"
 readme = "README.md"
-keywords = ["atomic", "no_std"]
+keywords = [
+    "atomic",
+    "no_std",
+]
 license = "Apache-2.0/MIT"
 repository = "https://github.com/Amanieu/atomic-rs"
-[build-dependencies.autocfg]
-version = "1"
+
+[dependencies.bytemuck]
+version = "1.13.1"
+
+[dev-dependencies.bytemuck]
+version = "1.13.1"
+features = ["derive"]
 
 [features]
 default = ["fallback"]
 fallback = []
+nightly = []
 std = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 80b613b..60faf7c 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,10 +1,9 @@
 [package]
 name = "atomic"
-version = "0.5.1"
+version = "0.6.0"
 edition = "2018"
 authors = ["Amanieu d'Antras <[email protected]>"]
 description = "Generic Atomic<T> wrapper type"
-documentation = "https://amanieu.github.io/atomic-rs/atomic/index.html"
 license = "Apache-2.0/MIT"
 repository = "https://github.com/Amanieu/atomic-rs"
 readme = "README.md"
@@ -14,6 +13,10 @@
 default = ["fallback"]
 std = []
 fallback = []
+nightly = []
 
-[build-dependencies]
-autocfg = "1"
+[dependencies]
+bytemuck = "1.13.1"
+
+[dev-dependencies]
+bytemuck = { version = "1.13.1", features = ["derive"] }
diff --git a/METADATA b/METADATA
index ada5837..917773f 100644
--- a/METADATA
+++ b/METADATA
@@ -1,20 +1,20 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/rust/crates/atomic
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
 name: "atomic"
 description: "Generic Atomic<T> wrapper type"
 third_party {
-  url {
-    type: HOMEPAGE
-    value: "https://crates.io/crates/atomic"
-  }
-  url {
-    type: ARCHIVE
-    value: "https://static.crates.io/crates/atomic/atomic-0.5.1.crate"
-  }
-  version: "0.5.1"
-  # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
+    year: 2024
     month: 1
-    day: 17
+    day: 31
+  }
+  homepage: "https://crates.io/crates/atomic"
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/atomic/atomic-0.6.0.crate"
+    version: "0.6.0"
   }
 }
diff --git a/README.md b/README.md
index ea2c0cb..3dedec7 100644
--- a/README.md
+++ b/README.md
@@ -3,13 +3,15 @@
 
 [![Build Status](https://travis-ci.org/Amanieu/atomic-rs.svg?branch=master)](https://travis-ci.org/Amanieu/atomic-rs) [![Crates.io](https://img.shields.io/crates/v/atomic.svg)](https://crates.io/crates/atomic)
 
-A Rust library which provides a generic `Atomic<T>` type for all `T: Copy` types, unlike the standard library which only provides a few fixed atomic types (`AtomicBool`, `AtomicIsize`, `AtomicUsize`, `AtomicPtr`).
+A Rust library which provides a generic `Atomic<T>` type for all `T: NoUninit` types, unlike the standard library which only provides a few fixed atomic types (`AtomicBool`, `AtomicIsize`, `AtomicUsize`, `AtomicPtr`). The `NoUninit` bound is from the [bytemuck] crate, and indicates that a type has no internal padding bytes. You will need to derive or implement this trait for all types used with `Atomic<T>`.
 
 This library will use native atomic instructions if possible, and will otherwise fall back to a lock-based mechanism. You can use the `Atomic::<T>::is_lock_free()` function to check whether native atomic operations are supported for a given type. Note that a type must have a power-of-2 size and alignment in order to be used by native atomic instructions.
 
 This crate uses `#![no_std]` and only depends on libcore.
 
-[Documentation](https://amanieu.github.io/atomic-rs/atomic/index.html)
+[bytemuck]: https://docs.rs/bytemuck
+
+[Documentation](https://docs.rs/atomic)
 
 ## Usage
 
@@ -17,7 +19,7 @@
 
 ```toml
 [dependencies]
-atomic = "0.5"
+atomic = "0.6"
 ```
 
 and this to your crate root:
diff --git a/build.rs b/build.rs
deleted file mode 100644
index 4cf4274..0000000
--- a/build.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-fn main() {
-    let ac = autocfg::new();
-
-    for root in &["core", "std"] {
-        for size in &[8, 16, 32, 64, 128] {
-            ac.emit_expression_cfg(
-                &format!("{}::sync::atomic::AtomicU{}::compare_exchange", root, size),
-                &format!("has_atomic_u{}", size),
-            );
-            ac.emit_expression_cfg(
-                &format!("{}::sync::atomic::AtomicI{}::compare_exchange", root, size),
-                &format!("has_atomic_i{}", size),
-            );
-        }
-    }
-}
diff --git a/src/fallback.rs b/src/fallback.rs
index 8b7e861..949bbf3 100644
--- a/src/fallback.rs
+++ b/src/fallback.rs
@@ -6,12 +6,13 @@
 // copied, modified, or distributed except according to those terms.
 
 use core::cmp;
-use core::mem;
+use core::hint;
 use core::num::Wrapping;
 use core::ops;
 use core::ptr;
-use core::slice;
-use core::sync::atomic::{self, AtomicUsize, Ordering};
+use core::sync::atomic::{AtomicUsize, Ordering};
+
+use bytemuck::NoUninit;
 
 // We use an AtomicUsize instead of an AtomicBool because it performs better
 // on architectures that don't have byte-sized atomics.
@@ -28,7 +29,7 @@
             .is_err()
         {
             while self.0.load(Ordering::Relaxed) != 0 {
-                atomic::spin_loop_hint();
+                hint::spin_loop();
             }
         }
     }
@@ -116,15 +117,16 @@
 }
 
 #[inline]
-pub unsafe fn atomic_compare_exchange<T>(dst: *mut T, current: T, new: T) -> Result<T, T> {
+pub unsafe fn atomic_compare_exchange<T: NoUninit>(
+    dst: *mut T,
+    current: T,
+    new: T,
+) -> Result<T, T> {
     let _l = lock(dst as usize);
     let result = ptr::read(dst);
     // compare_exchange compares with memcmp instead of Eq
-    let a = slice::from_raw_parts(&result as *const _ as *const u8, mem::size_of_val(&result));
-    let b = slice::from_raw_parts(
-        &current as *const _ as *const u8,
-        mem::size_of_val(&current),
-    );
+    let a = bytemuck::bytes_of(&result);
+    let b = bytemuck::bytes_of(&current);
     if a == b {
         ptr::write(dst, new);
         Ok(result)
diff --git a/src/lib.rs b/src/lib.rs
index 09ad879..c4ff297 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,10 +11,14 @@
 //! threads, and are the building blocks of other concurrent types.
 //!
 //! This library defines a generic atomic wrapper type `Atomic<T>` for all
-//! `T: Copy` types.
+//! `T: NoUninit` types.
 //! Atomic types present operations that, when used correctly, synchronize
 //! updates between threads.
 //!
+//! The `NoUninit` bound is from the [bytemuck] crate, and indicates that a
+//! type has no internal padding bytes. You will need to derive or implement
+//! this trait for all types used with `Atomic<T>`.
+//!
 //! Each method takes an `Ordering` which represents the strength of
 //! the memory barrier for that operation. These orderings are the
 //! same as [LLVM atomic orderings][1].
@@ -29,15 +33,19 @@
 //! Most atomic types may be stored in static variables, initialized using
 //! the `const fn` constructors. Atomic statics are often used for lazy global
 //! initialization.
+//!
+//! [bytemuck]: https://docs.rs/bytemuck
 
 #![warn(missing_docs)]
 #![warn(rust_2018_idioms)]
 #![no_std]
+#![cfg_attr(feature = "nightly", feature(integer_atomics))]
 
 #[cfg(any(test, feature = "std"))]
 #[macro_use]
 extern crate std;
 
+use core::mem::MaybeUninit;
 // Re-export some useful definitions from libcore
 pub use core::sync::atomic::{fence, Ordering};
 
@@ -47,6 +55,8 @@
 #[cfg(feature = "std")]
 use std::panic::RefUnwindSafe;
 
+use bytemuck::NoUninit;
+
 #[cfg(feature = "fallback")]
 mod fallback;
 mod ops;
@@ -55,7 +65,8 @@
 /// between threads.
 #[repr(transparent)]
 pub struct Atomic<T> {
-    v: UnsafeCell<T>,
+    // The MaybeUninit is here to work around rust-lang/rust#87341.
+    v: UnsafeCell<MaybeUninit<T>>,
 }
 
 // Atomic<T> is only Sync if T is Send
@@ -68,16 +79,16 @@
 // `Atomic` API does not allow doing any panic-inducing operation after writing
 // to the target object.
 #[cfg(feature = "std")]
-impl<T: Copy + RefUnwindSafe> RefUnwindSafe for Atomic<T> {}
+impl<T: RefUnwindSafe> RefUnwindSafe for Atomic<T> {}
 
-impl<T: Copy + Default> Default for Atomic<T> {
+impl<T: Default> Default for Atomic<T> {
     #[inline]
     fn default() -> Self {
         Self::new(Default::default())
     }
 }
 
-impl<T: Copy + fmt::Debug> fmt::Debug for Atomic<T> {
+impl<T: NoUninit + fmt::Debug> fmt::Debug for Atomic<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple("Atomic")
             .field(&self.load(Ordering::SeqCst))
@@ -90,7 +101,7 @@
     #[inline]
     pub const fn new(v: T) -> Atomic<T> {
         Atomic {
-            v: UnsafeCell::new(v),
+            v: UnsafeCell::new(MaybeUninit::new(v)),
         }
     }
 
@@ -105,14 +116,19 @@
     }
 }
 
-impl<T: Copy> Atomic<T> {
+impl<T: NoUninit> Atomic<T> {
+    #[inline]
+    fn inner_ptr(&self) -> *mut T {
+        self.v.get() as *mut T
+    }
+
     /// Returns a mutable reference to the underlying type.
     ///
     /// This is safe because the mutable reference guarantees that no other threads are
     /// concurrently accessing the atomic data.
     #[inline]
     pub fn get_mut(&mut self) -> &mut T {
-        unsafe { &mut *self.v.get() }
+        unsafe { &mut *self.inner_ptr() }
     }
 
     /// Consumes the atomic and returns the contained value.
@@ -121,7 +137,7 @@
     /// concurrently accessing the atomic data.
     #[inline]
     pub fn into_inner(self) -> T {
-        self.v.into_inner()
+        unsafe { self.v.into_inner().assume_init() }
     }
 
     /// Loads a value from the `Atomic`.
@@ -134,7 +150,7 @@
     /// Panics if `order` is `Release` or `AcqRel`.
     #[inline]
     pub fn load(&self, order: Ordering) -> T {
-        unsafe { ops::atomic_load(self.v.get(), order) }
+        unsafe { ops::atomic_load(self.inner_ptr(), order) }
     }
 
     /// Stores a value into the `Atomic`.
@@ -148,7 +164,7 @@
     #[inline]
     pub fn store(&self, val: T, order: Ordering) {
         unsafe {
-            ops::atomic_store(self.v.get(), val, order);
+            ops::atomic_store(self.inner_ptr(), val, order);
         }
     }
 
@@ -158,7 +174,7 @@
     /// of this operation.
     #[inline]
     pub fn swap(&self, val: T, order: Ordering) -> T {
-        unsafe { ops::atomic_swap(self.v.get(), val, order) }
+        unsafe { ops::atomic_swap(self.inner_ptr(), val, order) }
     }
 
     /// Stores a value into the `Atomic` if the current value is the same as the
@@ -181,7 +197,7 @@
         success: Ordering,
         failure: Ordering,
     ) -> Result<T, T> {
-        unsafe { ops::atomic_compare_exchange(self.v.get(), current, new, success, failure) }
+        unsafe { ops::atomic_compare_exchange(self.inner_ptr(), current, new, success, failure) }
     }
 
     /// Stores a value into the `Atomic` if the current value is the same as the
@@ -206,7 +222,9 @@
         success: Ordering,
         failure: Ordering,
     ) -> Result<T, T> {
-        unsafe { ops::atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) }
+        unsafe {
+            ops::atomic_compare_exchange_weak(self.inner_ptr(), current, new, success, failure)
+        }
     }
 
     /// Fetches the value, and applies a function to it that returns an optional
@@ -275,7 +293,7 @@
     /// Returns the previous value.
     #[inline]
     pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
-        unsafe { ops::atomic_and(self.v.get(), val, order) }
+        unsafe { ops::atomic_and(self.inner_ptr(), val, order) }
     }
 
     /// Logical "or" with a boolean value.
@@ -286,7 +304,7 @@
     /// Returns the previous value.
     #[inline]
     pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
-        unsafe { ops::atomic_or(self.v.get(), val, order) }
+        unsafe { ops::atomic_or(self.inner_ptr(), val, order) }
     }
 
     /// Logical "xor" with a boolean value.
@@ -297,7 +315,7 @@
     /// Returns the previous value.
     #[inline]
     pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
-        unsafe { ops::atomic_xor(self.v.get(), val, order) }
+        unsafe { ops::atomic_xor(self.inner_ptr(), val, order) }
     }
 }
 
@@ -307,31 +325,31 @@
             /// Add to the current value, returning the previous value.
             #[inline]
             pub fn fetch_add(&self, val: $t, order: Ordering) -> $t {
-                unsafe { ops::atomic_add(self.v.get(), val, order) }
+                unsafe { ops::atomic_add(self.inner_ptr(), val, order) }
             }
 
             /// Subtract from the current value, returning the previous value.
             #[inline]
             pub fn fetch_sub(&self, val: $t, order: Ordering) -> $t {
-                unsafe { ops::atomic_sub(self.v.get(), val, order) }
+                unsafe { ops::atomic_sub(self.inner_ptr(), val, order) }
             }
 
             /// Bitwise and with the current value, returning the previous value.
             #[inline]
             pub fn fetch_and(&self, val: $t, order: Ordering) -> $t {
-                unsafe { ops::atomic_and(self.v.get(), val, order) }
+                unsafe { ops::atomic_and(self.inner_ptr(), val, order) }
             }
 
             /// Bitwise or with the current value, returning the previous value.
             #[inline]
             pub fn fetch_or(&self, val: $t, order: Ordering) -> $t {
-                unsafe { ops::atomic_or(self.v.get(), val, order) }
+                unsafe { ops::atomic_or(self.inner_ptr(), val, order) }
             }
 
             /// Bitwise xor with the current value, returning the previous value.
             #[inline]
             pub fn fetch_xor(&self, val: $t, order: Ordering) -> $t {
-                unsafe { ops::atomic_xor(self.v.get(), val, order) }
+                unsafe { ops::atomic_xor(self.inner_ptr(), val, order) }
             }
         }
     )*);
@@ -344,13 +362,13 @@
                 /// Minimum with the current value.
                 #[inline]
                 pub fn fetch_min(&self, val: $t, order: Ordering) -> $t {
-                    unsafe { ops::atomic_min(self.v.get(), val, order) }
+                    unsafe { ops::atomic_min(self.inner_ptr(), val, order) }
                 }
 
                 /// Maximum with the current value.
                 #[inline]
                 pub fn fetch_max(&self, val: $t, order: Ordering) -> $t {
-                    unsafe { ops::atomic_max(self.v.get(), val, order) }
+                    unsafe { ops::atomic_max(self.inner_ptr(), val, order) }
                 }
             }
         )*
@@ -364,13 +382,13 @@
                 /// Minimum with the current value.
                 #[inline]
                 pub fn fetch_min(&self, val: $t, order: Ordering) -> $t {
-                    unsafe { ops::atomic_umin(self.v.get(), val, order) }
+                    unsafe { ops::atomic_umin(self.inner_ptr(), val, order) }
                 }
 
                 /// Maximum with the current value.
                 #[inline]
                 pub fn fetch_max(&self, val: $t, order: Ordering) -> $t {
-                    unsafe { ops::atomic_umax(self.v.get(), val, order) }
+                    unsafe { ops::atomic_umax(self.inner_ptr(), val, order) }
                 }
             }
         )*
@@ -382,19 +400,26 @@
 #[cfg(test)]
 mod tests {
     use super::{Atomic, Ordering::*};
+    use bytemuck::NoUninit;
     use core::mem;
 
-    #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
+    #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)]
+    #[repr(C)]
     struct Foo(u8, u8);
-    #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
+    #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)]
+    #[repr(C)]
     struct Bar(u64, u64);
-    #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
+    #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)]
+    #[repr(C)]
     struct Quux(u32);
 
     #[test]
     fn atomic_bool() {
         let a = Atomic::new(false);
-        assert_eq!(Atomic::<bool>::is_lock_free(), cfg!(has_atomic_u8),);
+        assert_eq!(
+            Atomic::<bool>::is_lock_free(),
+            cfg!(target_has_atomic = "8"),
+        );
         assert_eq!(format!("{:?}", a), "Atomic(false)");
         assert_eq!(a.load(SeqCst), false);
         a.store(true, SeqCst);
@@ -410,7 +435,7 @@
     #[test]
     fn atomic_i8() {
         let a = Atomic::new(0i8);
-        assert_eq!(Atomic::<i8>::is_lock_free(), cfg!(has_atomic_u8));
+        assert_eq!(Atomic::<i8>::is_lock_free(), cfg!(target_has_atomic = "8"));
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
         a.store(1, SeqCst);
@@ -431,7 +456,10 @@
     #[test]
     fn atomic_i16() {
         let a = Atomic::new(0i16);
-        assert_eq!(Atomic::<i16>::is_lock_free(), cfg!(has_atomic_u16));
+        assert_eq!(
+            Atomic::<i16>::is_lock_free(),
+            cfg!(target_has_atomic = "16")
+        );
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
         a.store(1, SeqCst);
@@ -451,7 +479,10 @@
     #[test]
     fn atomic_i32() {
         let a = Atomic::new(0i32);
-        assert_eq!(Atomic::<i32>::is_lock_free(), cfg!(has_atomic_u32));
+        assert_eq!(
+            Atomic::<i32>::is_lock_free(),
+            cfg!(target_has_atomic = "32")
+        );
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
         a.store(1, SeqCst);
@@ -473,7 +504,7 @@
         let a = Atomic::new(0i64);
         assert_eq!(
             Atomic::<i64>::is_lock_free(),
-            cfg!(has_atomic_u64) && mem::align_of::<i64>() == 8
+            cfg!(target_has_atomic = "64") && mem::align_of::<i64>() == 8
         );
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
@@ -494,7 +525,10 @@
     #[test]
     fn atomic_i128() {
         let a = Atomic::new(0i128);
-        assert_eq!(Atomic::<i128>::is_lock_free(), cfg!(has_atomic_u128));
+        assert_eq!(
+            Atomic::<i128>::is_lock_free(),
+            cfg!(feature = "nightly") & cfg!(target_has_atomic = "128")
+        );
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
         a.store(1, SeqCst);
@@ -533,7 +567,7 @@
     #[test]
     fn atomic_u8() {
         let a = Atomic::new(0u8);
-        assert_eq!(Atomic::<u8>::is_lock_free(), cfg!(has_atomic_u8));
+        assert_eq!(Atomic::<u8>::is_lock_free(), cfg!(target_has_atomic = "8"));
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
         a.store(1, SeqCst);
@@ -553,7 +587,10 @@
     #[test]
     fn atomic_u16() {
         let a = Atomic::new(0u16);
-        assert_eq!(Atomic::<u16>::is_lock_free(), cfg!(has_atomic_u16));
+        assert_eq!(
+            Atomic::<u16>::is_lock_free(),
+            cfg!(target_has_atomic = "16")
+        );
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
         a.store(1, SeqCst);
@@ -573,7 +610,10 @@
     #[test]
     fn atomic_u32() {
         let a = Atomic::new(0u32);
-        assert_eq!(Atomic::<u32>::is_lock_free(), cfg!(has_atomic_u32));
+        assert_eq!(
+            Atomic::<u32>::is_lock_free(),
+            cfg!(target_has_atomic = "32")
+        );
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
         a.store(1, SeqCst);
@@ -595,7 +635,7 @@
         let a = Atomic::new(0u64);
         assert_eq!(
             Atomic::<u64>::is_lock_free(),
-            cfg!(has_atomic_u64) && mem::align_of::<u64>() == 8
+            cfg!(target_has_atomic = "64") && mem::align_of::<u64>() == 8
         );
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
@@ -616,7 +656,10 @@
     #[test]
     fn atomic_u128() {
         let a = Atomic::new(0u128);
-        assert_eq!(Atomic::<u128>::is_lock_free(), cfg!(has_atomic_u128));
+        assert_eq!(
+            Atomic::<u128>::is_lock_free(),
+            cfg!(feature = "nightly") & cfg!(target_has_atomic = "128")
+        );
         assert_eq!(format!("{:?}", a), "Atomic(0)");
         assert_eq!(a.load(SeqCst), 0);
         a.store(1, SeqCst);
@@ -693,7 +736,10 @@
     #[test]
     fn atomic_quxx() {
         let a = Atomic::default();
-        assert_eq!(Atomic::<Quux>::is_lock_free(), cfg!(has_atomic_u32));
+        assert_eq!(
+            Atomic::<Quux>::is_lock_free(),
+            cfg!(target_has_atomic = "32")
+        );
         assert_eq!(format!("{:?}", a), "Atomic(Quux(0))");
         assert_eq!(a.load(SeqCst), Quux(0));
         a.store(Quux(1), SeqCst);
diff --git a/src/ops.rs b/src/ops.rs
index 808335c..1f54fa5 100644
--- a/src/ops.rs
+++ b/src/ops.rs
@@ -5,6 +5,8 @@
 // http://opensource.org/licenses/MIT>, at your option. This file may not be
 // copied, modified, or distributed except according to those terms.
 
+use bytemuck::NoUninit;
+
 #[cfg(feature = "fallback")]
 use crate::fallback;
 use core::cmp;
@@ -16,31 +18,31 @@
 macro_rules! match_atomic {
     ($type:ident, $atomic:ident, $impl:expr, $fallback_impl:expr) => {
         match mem::size_of::<$type>() {
-            #[cfg(has_atomic_u8)]
+            #[cfg(target_has_atomic = "8")]
             1 if mem::align_of::<$type>() >= 1 => {
                 type $atomic = core::sync::atomic::AtomicU8;
 
                 $impl
             }
-            #[cfg(has_atomic_u16)]
+            #[cfg(target_has_atomic = "16")]
             2 if mem::align_of::<$type>() >= 2 => {
                 type $atomic = core::sync::atomic::AtomicU16;
 
                 $impl
             }
-            #[cfg(has_atomic_u32)]
+            #[cfg(target_has_atomic = "32")]
             4 if mem::align_of::<$type>() >= 4 => {
                 type $atomic = core::sync::atomic::AtomicU32;
 
                 $impl
             }
-            #[cfg(has_atomic_u64)]
+            #[cfg(target_has_atomic = "64")]
             8 if mem::align_of::<$type>() >= 8 => {
                 type $atomic = core::sync::atomic::AtomicU64;
 
                 $impl
             }
-            #[cfg(has_atomic_u128)]
+            #[cfg(all(feature = "nightly", target_has_atomic = "128"))]
             16 if mem::align_of::<$type>() >= 16 => {
                 type $atomic = core::sync::atomic::AtomicU128;
 
@@ -57,31 +59,31 @@
 macro_rules! match_signed_atomic {
     ($type:ident, $atomic:ident, $impl:expr, $fallback_impl:expr) => {
         match mem::size_of::<$type>() {
-            #[cfg(has_atomic_i8)]
+            #[cfg(target_has_atomic = "8")]
             1 if mem::align_of::<$type>() >= 1 => {
                 type $atomic = core::sync::atomic::AtomicI8;
 
                 $impl
             }
-            #[cfg(has_atomic_i16)]
+            #[cfg(target_has_atomic = "16")]
             2 if mem::align_of::<$type>() >= 2 => {
                 type $atomic = core::sync::atomic::AtomicI16;
 
                 $impl
             }
-            #[cfg(has_atomic_i32)]
+            #[cfg(target_has_atomic = "32")]
             4 if mem::align_of::<$type>() >= 4 => {
                 type $atomic = core::sync::atomic::AtomicI32;
 
                 $impl
             }
-            #[cfg(has_atomic_i64)]
+            #[cfg(target_has_atomic = "64")]
             8 if mem::align_of::<$type>() >= 8 => {
                 type $atomic = core::sync::atomic::AtomicI64;
 
                 $impl
             }
-            #[cfg(has_atomic_u128)]
+            #[cfg(all(feature = "nightly", target_has_atomic = "128"))]
             16 if mem::align_of::<$type>() >= 16 => {
                 type $atomic = core::sync::atomic::AtomicI128;
 
@@ -100,15 +102,18 @@
     let size = mem::size_of::<T>();
     let align = mem::align_of::<T>();
 
-    (cfg!(has_atomic_u8) & (size == 1) & (align >= 1))
-        | (cfg!(has_atomic_u16) & (size == 2) & (align >= 2))
-        | (cfg!(has_atomic_u32) & (size == 4) & (align >= 4))
-        | (cfg!(has_atomic_u64) & (size == 8) & (align >= 8))
-        | (cfg!(has_atomic_u128) & (size == 16) & (align >= 16))
+    (cfg!(target_has_atomic = "8") & (size == 1) & (align >= 1))
+        | (cfg!(target_has_atomic = "16") & (size == 2) & (align >= 2))
+        | (cfg!(target_has_atomic = "32") & (size == 4) & (align >= 4))
+        | (cfg!(target_has_atomic = "64") & (size == 8) & (align >= 8))
+        | (cfg!(feature = "nightly")
+            & cfg!(target_has_atomic = "128")
+            & (size == 16)
+            & (align >= 16))
 }
 
 #[inline]
-pub unsafe fn atomic_load<T>(dst: *mut T, order: Ordering) -> T {
+pub unsafe fn atomic_load<T: NoUninit>(dst: *mut T, order: Ordering) -> T {
     match_atomic!(
         T,
         A,
@@ -118,7 +123,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_store<T>(dst: *mut T, val: T, order: Ordering) {
+pub unsafe fn atomic_store<T: NoUninit>(dst: *mut T, val: T, order: Ordering) {
     match_atomic!(
         T,
         A,
@@ -128,7 +133,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_swap<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T {
     match_atomic!(
         T,
         A,
@@ -146,7 +151,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_compare_exchange<T>(
+pub unsafe fn atomic_compare_exchange<T: NoUninit>(
     dst: *mut T,
     current: T,
     new: T,
@@ -167,7 +172,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_compare_exchange_weak<T>(
+pub unsafe fn atomic_compare_exchange_weak<T: NoUninit>(
     dst: *mut T,
     current: T,
     new: T,
@@ -188,7 +193,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T
+pub unsafe fn atomic_add<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T
 where
     Wrapping<T>: ops::Add<Output = Wrapping<T>>,
 {
@@ -201,7 +206,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T
+pub unsafe fn atomic_sub<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T
 where
     Wrapping<T>: ops::Sub<Output = Wrapping<T>>,
 {
@@ -214,7 +219,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_and<T: Copy + ops::BitAnd<Output = T>>(
+pub unsafe fn atomic_and<T: NoUninit + ops::BitAnd<Output = T>>(
     dst: *mut T,
     val: T,
     order: Ordering,
@@ -228,7 +233,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_or<T: Copy + ops::BitOr<Output = T>>(
+pub unsafe fn atomic_or<T: NoUninit + ops::BitOr<Output = T>>(
     dst: *mut T,
     val: T,
     order: Ordering,
@@ -242,7 +247,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_xor<T: Copy + ops::BitXor<Output = T>>(
+pub unsafe fn atomic_xor<T: NoUninit + ops::BitXor<Output = T>>(
     dst: *mut T,
     val: T,
     order: Ordering,
@@ -256,7 +261,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_min<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_min<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
     match_signed_atomic!(
         T,
         A,
@@ -266,7 +271,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_max<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_max<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
     match_signed_atomic!(
         T,
         A,
@@ -276,7 +281,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_umin<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_umin<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
     match_atomic!(
         T,
         A,
@@ -286,7 +291,7 @@
 }
 
 #[inline]
-pub unsafe fn atomic_umax<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_umax<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
     match_atomic!(
         T,
         A,