Skip to content

Commit

Permalink
Detect atomic support using target_has_atomic
Browse files Browse the repository at this point in the history
This is adapted from @josephlr's similar implementation in #1091.

Fixes #1086

Co-authored-by: Joe Richey <joerichey@google.com>
  • Loading branch information
joshlf and josephlr committed Aug 9, 2024
1 parent f0a52b5 commit 4fc0b38
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 45 deletions.
17 changes: 16 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,19 @@ jobs:
matrix:
# See `INTERNAL.md` for an explanation of these pinned toolchain
# versions.
toolchain: [ "msrv", "stable", "nightly", "zerocopy-generic-bounds-in-const-fn", "zerocopy-aarch64-simd", "zerocopy-panic-in-const", ]
toolchain: [
"msrv",
"stable",
"nightly",

# These are the names of specific Rust versions detected in
# `build.rs`. Each of these represents the minimum Rust version for
# which a particular feature is supported.
"zerocopy-generic-bounds-in-const-fn",
"zerocopy-target-has-atomics",
"zerocopy-aarch64-simd",
"zerocopy-panic-in-const"
]
target: [
"i686-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
Expand All @@ -57,6 +69,7 @@ jobs:
"riscv64gc-unknown-linux-gnu",
"s390x-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
"thumbv6m-none-eabi",
"wasm32-wasi"
]
features: [ "--no-default-features", "", "--features __internal_use_only_features_that_work_on_stable", "--all-features" ]
Expand Down Expand Up @@ -109,6 +122,8 @@ jobs:
event_name: "pull_request"
- target: "s390x-unknown-linux-gnu"
event_name: "pull_request"
- target: "thumbv6m-none-eabi"
event_name: "pull_request"
- target: "wasm32-wasi"
event_name: "pull_request"

Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ exclude = [".*"]
# From 1.61.0, Rust supports generic types with trait bounds in `const fn`.
zerocopy-generic-bounds-in-const-fn = "1.61.0"

# From 1.60.0, Rust supports `cfg(target_has_atomics)`, which allows us to
# detect whether a target supports particular sets of atomics.
zerocopy-target-has-atomics = "1.60.0"

# When the "simd" feature is enabled, include SIMD types from the
# `core::arch::aarch64` module, which was stabilized in 1.59.0. On earlier Rust
# versions, these types require the "simd-nightly" feature.
Expand Down
101 changes: 61 additions & 40 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,49 +440,70 @@ safety_comment! {
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...));
}

macro_rules! impl_traits_for_atomics {
($($atomics:ident),* $(,)?) => {
$(
impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
impl_for_transparent_wrapper!(=> FromZeros for $atomics);
impl_for_transparent_wrapper!(=> FromBytes for $atomics);
impl_for_transparent_wrapper!(=> IntoBytes for $atomics);
)*
};
}
#[cfg(zerocopy_target_has_atomics)]
mod atomics {
macro_rules! impl_traits_for_atomics {
($($atomics:ident),* $(,)?) => {
$(
impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
impl_for_transparent_wrapper!(=> FromZeros for $atomics);
impl_for_transparent_wrapper!(=> FromBytes for $atomics);
impl_for_transparent_wrapper!(=> IntoBytes for $atomics);
)*
};
}

#[rustfmt::skip]
impl_traits_for_atomics!(
AtomicI16, AtomicI32, AtomicI8, AtomicIsize,
AtomicU16, AtomicU32, AtomicU8, AtomicUsize,
);
#[cfg(target_has_atomic = "8")]
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "8")))]
mod atomic_8 {
use super::*;

impl_traits_for_atomics!(AtomicU8, AtomicI8);

impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);

safety_comment! {
/// SAFETY:
/// Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the same
/// size as `bool`, `u8`, and `i8` respectively. Since a type's
/// alignment cannot be smaller than 1 [2], and since its alignment
/// cannot be greater than its size [3], the only possible value for
/// the alignment is 1. Thus, it is sound to implement `Unaligned`.
///
/// [1] TODO(#896), TODO(https://github.com/rust-lang/rust/pull/121943):
/// Cite docs once they've landed.
///
/// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
///
/// Alignment is measured in bytes, and must be at least 1.
///
/// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
///
/// The size of a value is always a multiple of its alignment.
unsafe_impl!(AtomicBool: Unaligned);
unsafe_impl!(AtomicU8: Unaligned);
unsafe_impl!(AtomicI8: Unaligned);
assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
}
}

impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);
#[cfg(target_has_atomic = "16")]
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "16")))]
impl_traits_for_atomics!(AtomicU16, AtomicI16);

safety_comment! {
/// SAFETY:
/// Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the same size as
/// `bool`, `u8`, and `i8` respectively. Since a type's alignment cannot be
/// smaller than 1 [2], and since its alignment cannot be greater than its
/// size [3], the only possible value for the alignment is 1. Thus, it is
/// sound to implement `Unaligned`.
///
/// [1] TODO(#896), TODO(https://github.com/rust-lang/rust/pull/121943):
/// Cite docs once they've landed.
///
/// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
///
/// Alignment is measured in bytes, and must be at least 1.
///
/// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
///
/// The size of a value is always a multiple of its alignment.
unsafe_impl!(AtomicBool: Unaligned);
unsafe_impl!(AtomicU8: Unaligned);
unsafe_impl!(AtomicI8: Unaligned);
assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
#[cfg(target_has_atomic = "32")]
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "32")))]
impl_traits_for_atomics!(AtomicU32, AtomicI32);

#[cfg(target_has_atomic = "64")]
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "64")))]
impl_traits_for_atomics!(AtomicU64, AtomicI64);

#[cfg(target_has_atomic = "ptr")]
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "ptr")))]
impl_traits_for_atomics!(AtomicUsize, AtomicIsize);
}

safety_comment! {
Expand Down
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,8 @@ use core::{
ptr::{self, NonNull},
slice,
sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU32,
AtomicU8, AtomicUsize,
AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16,
AtomicU32, AtomicU64, AtomicU8, AtomicUsize,
},
};

Expand Down Expand Up @@ -820,8 +820,9 @@ impl_known_layout!(
bool, char,
NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32,
NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize,
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
AtomicU8, AtomicUsize
AtomicBool,
AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize,
AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize
);
#[rustfmt::skip]
impl_known_layout!(
Expand Down

0 comments on commit 4fc0b38

Please sign in to comment.