Skip to content

Commit cbe9f8b

Browse files
joshlfjosephlr
andcommitted
Detect atomic support using target_has_atomic
Implements `TryFromBytes` and `FromZeros` for `AtomicPtr`; `FromBytes` and `IntoBytes` are blocked by #170. This is adapted from @josephlr's similar implementation in #1092. Fixes #1086 Co-authored-by: Joe Richey <[email protected]>
1 parent 739c3d1 commit cbe9f8b

34 files changed

+240
-137
lines changed

.github/workflows/ci.yml

+36-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,19 @@ jobs:
4646
matrix:
4747
# See `INTERNAL.md` for an explanation of these pinned toolchain
4848
# versions.
49-
toolchain: [ "msrv", "stable", "nightly", "zerocopy-generic-bounds-in-const-fn", "zerocopy-aarch64-simd", "zerocopy-panic-in-const", ]
49+
toolchain: [
50+
"msrv",
51+
"stable",
52+
"nightly",
53+
54+
# These are the names of specific Rust versions detected in
55+
# `build.rs`. Each of these represents the minimum Rust version for
56+
# which a particular feature is supported.
57+
"zerocopy-generic-bounds-in-const-fn",
58+
"zerocopy-target-has-atomics",
59+
"zerocopy-aarch64-simd",
60+
"zerocopy-panic-in-const"
61+
]
5062
target: [
5163
"i686-unknown-linux-gnu",
5264
"x86_64-unknown-linux-gnu",
@@ -57,6 +69,7 @@ jobs:
5769
"riscv64gc-unknown-linux-gnu",
5870
"s390x-unknown-linux-gnu",
5971
"x86_64-pc-windows-msvc",
72+
"thumbv6m-none-eabi",
6073
"wasm32-wasi"
6174
]
6275
features: [ "--no-default-features", "", "--features __internal_use_only_features_that_work_on_stable", "--all-features" ]
@@ -71,6 +84,8 @@ jobs:
7184
features: "--all-features"
7285
- toolchain: "zerocopy-generic-bounds-in-const-fn"
7386
features: "--all-features"
87+
- toolchain: "zerocopy-target-has-atomics"
88+
features: "--all-features"
7489
- toolchain: "zerocopy-aarch64-simd"
7590
features: "--all-features"
7691
- toolchain: "zerocopy-panic-in-const"
@@ -89,6 +104,8 @@ jobs:
89104
# zerocopy-derive doesn't behave different on these toolchains.
90105
- crate: "zerocopy-derive"
91106
toolchain: "zerocopy-generic-bounds-in-const-fn"
107+
- crate: "zerocopy-derive"
108+
toolchain: "zerocopy-target-has-atomics"
92109
- crate: "zerocopy-derive"
93110
toolchain: "zerocopy-aarch64-simd"
94111
- crate: "zerocopy-derive"
@@ -109,6 +126,8 @@ jobs:
109126
event_name: "pull_request"
110127
- target: "s390x-unknown-linux-gnu"
111128
event_name: "pull_request"
129+
- target: "thumbv6m-none-eabi"
130+
event_name: "pull_request"
112131
- target: "wasm32-wasi"
113132
event_name: "pull_request"
114133

@@ -120,6 +139,19 @@ jobs:
120139
- name: Populate cache
121140
uses: ./.github/actions/cache
122141

142+
# Ensure that Cargo resolves the minimum possible syn version so that if we
143+
# accidentally make a change which depends upon features added in more
144+
# recent versions of syn, we'll catch it in CI.
145+
#
146+
# TODO(#1595): Debug why this step is still necessary after #1564 and maybe
147+
# remove it.
148+
- name: Pin syn dependency
149+
run: |
150+
set -eo pipefail
151+
# Override the exising `syn` dependency with one which requires an exact
152+
# version.
153+
cargo add -p zerocopy-derive 'syn@=2.0.46'
154+
123155
- name: Configure environment variables
124156
run: |
125157
set -eo pipefail
@@ -488,6 +520,9 @@ jobs:
488520
# See comment on "Pin syn dependency" job for why we do this. It needs
489521
# to happen before the subsequent `cargo check`, so we don't
490522
# background it.
523+
#
524+
# TODO(#1595): Debug why this step is still necessary after #1564 and
525+
# maybe remove it.
491526
cargo add -p zerocopy-derive 'syn@=2.0.46' &> /dev/null
492527
493528
cargo check --workspace --tests &> /dev/null &

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ exclude = [".*"]
3535
# From 1.61.0, Rust supports generic types with trait bounds in `const fn`.
3636
zerocopy-generic-bounds-in-const-fn = "1.61.0"
3737

38+
# From 1.60.0, Rust supports `cfg(target_has_atomics)`, which allows us to
39+
# detect whether a target supports particular sets of atomics.
40+
zerocopy-target-has-atomics = "1.60.0"
41+
3842
# When the "simd" feature is enabled, include SIMD types from the
3943
# `core::arch::aarch64` module, which was stabilized in 1.59.0. On earlier Rust
4044
# versions, these types require the "simd-nightly" feature.

src/impls.rs

+127-39
Original file line numberDiff line numberDiff line change
@@ -440,49 +440,137 @@ safety_comment! {
440440
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...));
441441
}
442442

443-
macro_rules! impl_traits_for_atomics {
444-
($($atomics:ident),* $(,)?) => {
445-
$(
446-
impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
447-
impl_for_transparent_wrapper!(=> FromZeros for $atomics);
448-
impl_for_transparent_wrapper!(=> FromBytes for $atomics);
449-
impl_for_transparent_wrapper!(=> IntoBytes for $atomics);
450-
)*
443+
#[cfg(zerocopy_target_has_atomics)]
444+
mod atomics {
445+
use core::sync::atomic::{
446+
AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16,
447+
AtomicU32, AtomicU64, AtomicU8, AtomicUsize,
451448
};
452-
}
453449

454-
#[rustfmt::skip]
455-
impl_traits_for_atomics!(
456-
AtomicI16, AtomicI32, AtomicI8, AtomicIsize,
457-
AtomicU16, AtomicU32, AtomicU8, AtomicUsize,
458-
);
450+
use super::*;
459451

460-
impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
461-
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
462-
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);
452+
macro_rules! impl_traits_for_atomics {
453+
($($atomics:ident),* $(,)?) => {
454+
$(
455+
impl_known_layout!($atomics);
456+
impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
457+
impl_for_transparent_wrapper!(=> FromZeros for $atomics);
458+
impl_for_transparent_wrapper!(=> FromBytes for $atomics);
459+
impl_for_transparent_wrapper!(=> IntoBytes for $atomics);
460+
)*
461+
};
462+
}
463463

464-
safety_comment! {
465-
/// SAFETY:
466-
/// Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the same size as
467-
/// `bool`, `u8`, and `i8` respectively. Since a type's alignment cannot be
468-
/// smaller than 1 [2], and since its alignment cannot be greater than its
469-
/// size [3], the only possible value for the alignment is 1. Thus, it is
470-
/// sound to implement `Unaligned`.
471-
///
472-
/// [1] TODO(#896), TODO(https://github.com/rust-lang/rust/pull/121943):
473-
/// Cite docs once they've landed.
474-
///
475-
/// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
476-
///
477-
/// Alignment is measured in bytes, and must be at least 1.
478-
///
479-
/// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
480-
///
481-
/// The size of a value is always a multiple of its alignment.
482-
unsafe_impl!(AtomicBool: Unaligned);
483-
unsafe_impl!(AtomicU8: Unaligned);
484-
unsafe_impl!(AtomicI8: Unaligned);
485-
assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
464+
#[cfg(target_has_atomic = "8")]
465+
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "8")))]
466+
mod atomic_8 {
467+
use super::*;
468+
469+
impl_traits_for_atomics!(AtomicU8, AtomicI8);
470+
471+
impl_known_layout!(AtomicBool);
472+
473+
impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
474+
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
475+
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);
476+
477+
safety_comment! {
478+
/// SAFETY:
479+
/// Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the same
480+
/// size as `bool`, `u8`, and `i8` respectively. Since a type's
481+
/// alignment cannot be smaller than 1 [2], and since its alignment
482+
/// cannot be greater than its size [3], the only possible value for
483+
/// the alignment is 1. Thus, it is sound to implement `Unaligned`.
484+
///
485+
/// [1] TODO(#896), TODO(https://github.com/rust-lang/rust/pull/121943):
486+
/// Cite docs once they've landed.
487+
///
488+
/// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
489+
///
490+
/// Alignment is measured in bytes, and must be at least 1.
491+
///
492+
/// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
493+
///
494+
/// The size of a value is always a multiple of its alignment.
495+
unsafe_impl!(AtomicBool: Unaligned);
496+
unsafe_impl!(AtomicU8: Unaligned);
497+
unsafe_impl!(AtomicI8: Unaligned);
498+
assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
499+
500+
/// SAFETY:
501+
/// All of these pass an atomic type and that type's native equivalent, as
502+
/// required by the macro safety preconditions.
503+
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
504+
}
505+
}
506+
507+
#[cfg(target_has_atomic = "16")]
508+
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "16")))]
509+
mod atomic_16 {
510+
use super::*;
511+
512+
impl_traits_for_atomics!(AtomicU16, AtomicI16);
513+
514+
safety_comment! {
515+
/// SAFETY:
516+
/// All of these pass an atomic type and that type's native equivalent, as
517+
/// required by the macro safety preconditions.
518+
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
519+
}
520+
}
521+
522+
#[cfg(target_has_atomic = "32")]
523+
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "32")))]
524+
mod atomic_32 {
525+
use super::*;
526+
527+
impl_traits_for_atomics!(AtomicU32, AtomicI32);
528+
529+
safety_comment! {
530+
/// SAFETY:
531+
/// All of these pass an atomic type and that type's native equivalent, as
532+
/// required by the macro safety preconditions.
533+
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
534+
}
535+
}
536+
537+
#[cfg(target_has_atomic = "64")]
538+
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "64")))]
539+
mod atomic_64 {
540+
use super::*;
541+
542+
impl_traits_for_atomics!(AtomicU64, AtomicI64);
543+
544+
safety_comment! {
545+
/// SAFETY:
546+
/// All of these pass an atomic type and that type's native equivalent, as
547+
/// required by the macro safety preconditions.
548+
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
549+
}
550+
}
551+
552+
#[cfg(target_has_atomic = "ptr")]
553+
#[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "ptr")))]
554+
mod atomic_ptr {
555+
use super::*;
556+
557+
impl_traits_for_atomics!(AtomicUsize, AtomicIsize);
558+
559+
impl_known_layout!(T => AtomicPtr<T>);
560+
561+
// TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement
562+
// those traits for `*mut T`.
563+
impl_for_transparent_wrapper!(T => TryFromBytes for AtomicPtr<T>);
564+
impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr<T>);
565+
566+
safety_comment! {
567+
/// SAFETY:
568+
/// This passes an atomic type and that type's native equivalent, as
569+
/// required by the macro safety preconditions.
570+
unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
571+
unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr<T> [*mut T]);
572+
}
573+
}
486574
}
487575

488576
safety_comment! {

src/lib.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ extern crate self as zerocopy;
296296

297297
#[macro_use]
298298
mod macros;
299+
#[macro_use]
300+
mod util;
299301

300302
pub mod byte_slice;
301303
pub mod byteorder;
@@ -313,7 +315,6 @@ pub mod macro_util;
313315
#[doc(hidden)]
314316
pub mod pointer;
315317
mod r#ref;
316-
mod util;
317318
// TODO(#252): If we make this pub, come up with a better name.
318319
mod wrappers;
319320

@@ -337,10 +338,6 @@ use core::{
337338
ops::{Deref, DerefMut},
338339
ptr::{self, NonNull},
339340
slice,
340-
sync::atomic::{
341-
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU32,
342-
AtomicU8, AtomicUsize,
343-
},
344341
};
345342

346343
use crate::pointer::{invariant, BecauseExclusive, BecauseImmutable};
@@ -819,9 +816,7 @@ impl_known_layout!(
819816
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64,
820817
bool, char,
821818
NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32,
822-
NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize,
823-
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
824-
AtomicU8, AtomicUsize
819+
NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize
825820
);
826821
#[rustfmt::skip]
827822
impl_known_layout!(
@@ -830,8 +825,7 @@ impl_known_layout!(
830825
T => Wrapping<T>,
831826
T => MaybeUninit<T>,
832827
T: ?Sized => *const T,
833-
T: ?Sized => *mut T,
834-
T => AtomicPtr<T>
828+
T: ?Sized => *mut T
835829
);
836830
impl_known_layout!(const N: usize, T => [T; N]);
837831

0 commit comments

Comments
 (0)