Coverage Report

Created: 2026-04-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/portable-atomic-1.13.1/src/utils.rs
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3
#![cfg_attr(not(all(test, feature = "float")), allow(dead_code, unused_macros))]
4
5
#[allow(unused_imports)]
6
pub(crate) use self::generated::{RegISize, RegSize};
7
#[macro_use]
8
#[path = "gen/utils.rs"]
9
mod generated;
10
11
use core::sync::atomic::Ordering;
12
13
macro_rules! static_assert {
14
    ($cond:expr $(,)?) => {{
15
        let [()] = [(); (true /* type check */ & $cond) as usize];
16
    }};
17
}
18
19
macro_rules! static_assert_layout {
20
    ($atomic_type:ty, $value_type:ty) => {
21
        static_assert!(
22
            core::mem::align_of::<$atomic_type>() == core::mem::size_of::<$atomic_type>()
23
        );
24
        static_assert!(core::mem::size_of::<$atomic_type>() == core::mem::size_of::<$value_type>());
25
    };
26
}
27
28
// #[doc = concat!(...)] requires Rust 1.54
29
macro_rules! doc_comment {
30
    ($doc:expr, $($tt:tt)*) => {
31
        #[doc = $doc]
32
        $($tt)*
33
    };
34
}
35
36
// Adapted from https://github.com/BurntSushi/memchr/blob/2.4.1/src/memchr/x86/mod.rs#L9-L71.
37
/// # Safety
38
///
39
/// - the caller must uphold the safety contract for the function returned by $detect_body.
40
/// - the memory pointed by the function pointer returned by $detect_body must be visible from any threads.
41
///
42
/// The second requirement is always met if the function pointer is to the function definition.
43
/// (Currently, all uses of this macro in our code are in this case.)
44
#[allow(unused_macros)]
45
#[cfg(not(portable_atomic_no_outline_atomics))]
46
#[cfg(any(
47
    target_arch = "aarch64",
48
    target_arch = "arm",
49
    target_arch = "arm64ec",
50
    target_arch = "powerpc64",
51
    target_arch = "riscv32",
52
    target_arch = "riscv64",
53
    all(target_arch = "x86_64", not(any(target_env = "sgx", miri))),
54
))]
55
macro_rules! ifunc {
56
    (unsafe fn($($arg_pat:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)? { $($init_body:tt)* }) => {{
57
        type FnTy = unsafe fn($($arg_ty),*) $(-> $ret_ty)?;
58
        static FUNC: core::sync::atomic::AtomicPtr<()>
59
            = core::sync::atomic::AtomicPtr::new(init as *mut ());
60
        #[cold]
61
0
        unsafe fn init($($arg_pat: $arg_ty),*) $(-> $ret_ty)? {
62
0
            let func: FnTy = { $($init_body)* };
63
0
            FUNC.store(func as *mut (), core::sync::atomic::Ordering::Relaxed);
64
            // SAFETY: the caller must uphold the safety contract for the function returned by $init_body.
65
0
            unsafe { func($($arg_pat),*) }
66
0
        }
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_add::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_and::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_max::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_min::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_neg::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_not::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_sub::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_xor::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_load::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_nand::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_swap::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_umax::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_umin::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_store::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_store::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_compare_exchange::init
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_or::init
67
        // SAFETY: `FnTy` is a function pointer, which is always safe to transmute with a `*mut ()`.
68
        // (To force the caller to use unsafe block for this macro, do not use
69
        // unsafe block here.)
70
        let func = {
71
            core::mem::transmute::<*mut (), FnTy>(FUNC.load(core::sync::atomic::Ordering::Relaxed))
72
        };
73
        // SAFETY: the caller must uphold the safety contract for the function returned by $init_body.
74
        // (To force the caller to use unsafe block for this macro, do not use
75
        // unsafe block here.)
76
        func($($arg_pat),*)
77
    }};
78
}
79
80
#[allow(unused_macros)]
81
#[cfg(not(portable_atomic_no_outline_atomics))]
82
#[cfg(any(
83
    target_arch = "aarch64",
84
    target_arch = "arm",
85
    target_arch = "arm64ec",
86
    target_arch = "powerpc64",
87
    target_arch = "riscv32",
88
    target_arch = "riscv64",
89
    all(target_arch = "x86_64", not(any(target_env = "sgx", miri))),
90
))]
91
macro_rules! fn_alias {
92
    (
93
        $(#[$($fn_attr:tt)*])*
94
        $vis:vis unsafe fn($($arg_pat:ident: $arg_ty:ty),*) $(-> $ret_ty:ty)?;
95
        $(#[$($alias_attr:tt)*])*
96
        $new:ident = $from:ident($($last_args:tt)*);
97
        $($rest:tt)*
98
    ) => {
99
        $(#[$($fn_attr)*])*
100
        $(#[$($alias_attr)*])*
101
0
        $vis unsafe fn $new($($arg_pat: $arg_ty),*) $(-> $ret_ty)? {
102
            // SAFETY: the caller must uphold the safety contract.
103
0
            unsafe { $from($($arg_pat,)* $($last_args)*) }
104
0
        }
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_or_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_add_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_and_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_max_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_min_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_neg_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_not_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_sub_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_xor_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_load_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_nand_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_swap_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_umax_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_umin_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_store_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_store_non_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::fallback::atomic_compare_exchange_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_add::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_and::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_max::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_min::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_neg::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_not::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_sub::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_xor::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_nand::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_swap::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_umax::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_umin::cmpxchg16b_seqcst_fn
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_store::_atomic_store_vmovdqa_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_store::_atomic_store_vmovdqa_non_seqcst
Unexecuted instantiation: portable_atomic::imp::atomic128::x86_64::atomic_or::cmpxchg16b_seqcst_fn
105
        fn_alias! {
106
            $(#[$($fn_attr)*])*
107
            $vis unsafe fn($($arg_pat: $arg_ty),*) $(-> $ret_ty)?;
108
            $($rest)*
109
        }
110
    };
111
    (
112
        $(#[$($attr:tt)*])*
113
        $vis:vis unsafe fn($($arg_pat:ident: $arg_ty:ty),*) $(-> $ret_ty:ty)?;
114
    ) => {}
115
}
116
117
/// Make the given function const if the given condition is true.
118
macro_rules! const_fn {
119
    (
120
        const_if: #[cfg($($cfg:tt)+)];
121
        $(#[$($attr:tt)*])*
122
        $vis:vis const $($rest:tt)*
123
    ) => {
124
        #[cfg($($cfg)+)]
125
        $(#[$($attr)*])*
126
        $vis const $($rest)*
127
        #[cfg(not($($cfg)+))]
128
        $(#[$($attr)*])*
129
        $vis $($rest)*
130
    };
131
}
132
133
/// Implements `core::fmt::Debug` and `serde::{Serialize, Deserialize}` (when serde
134
/// feature is enabled) for atomic bool, integer, or float.
135
macro_rules! impl_debug_and_serde {
136
    // TODO(f16_and_f128): Implement serde traits for f16 & f128 once stabilized.
137
    (AtomicF16) => {
138
        impl_debug!(AtomicF16);
139
    };
140
    (AtomicF128) => {
141
        impl_debug!(AtomicF128);
142
    };
143
    ($atomic_type:ident) => {
144
        impl_debug!($atomic_type);
145
        #[cfg(feature = "serde")]
146
        #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
147
        impl serde::ser::Serialize for $atomic_type {
148
            #[allow(clippy::missing_inline_in_public_items)] // serde doesn't use inline on std atomic's Serialize/Deserialize impl
149
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
150
            where
151
                S: serde::ser::Serializer,
152
            {
153
                // https://github.com/serde-rs/serde/blob/v1.0.152/serde/src/ser/impls.rs#L958-L959
154
                self.load(Ordering::Relaxed).serialize(serializer)
155
            }
156
        }
157
        #[cfg(feature = "serde")]
158
        #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
159
        impl<'de> serde::de::Deserialize<'de> for $atomic_type {
160
            #[allow(clippy::missing_inline_in_public_items)] // serde doesn't use inline on std atomic's Serialize/Deserialize impl
161
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
162
            where
163
                D: serde::de::Deserializer<'de>,
164
            {
165
                serde::de::Deserialize::deserialize(deserializer).map(Self::new)
166
            }
167
        }
168
    };
169
}
170
macro_rules! impl_debug {
171
    ($atomic_type:ident) => {
172
        impl fmt::Debug for $atomic_type {
173
            #[inline] // fmt is not hot path, but #[inline] on fmt seems to still be useful: https://github.com/rust-lang/rust/pull/117727
174
0
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175
                // std atomic types use Relaxed in Debug::fmt: https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L2188
176
0
                fmt::Debug::fmt(&self.load(Ordering::Relaxed), f)
177
0
            }
Unexecuted instantiation: <portable_atomic::AtomicI128 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicU128 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicBool as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicU16 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicI32 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicU32 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicI64 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicU64 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicIsize as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicUsize as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicI8 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicU8 as core::fmt::Debug>::fmt
Unexecuted instantiation: <portable_atomic::AtomicI16 as core::fmt::Debug>::fmt
178
        }
179
    };
180
}
181
182
// We do not provide `nand` because it cannot be optimized on neither x86 nor MSP430.
183
// https://godbolt.org/z/ahWejchbT
184
macro_rules! impl_default_no_fetch_ops {
185
    ($atomic_type:ident, bool) => {
186
        impl $atomic_type {
187
            #[inline]
188
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
189
            pub(crate) fn and(&self, val: bool, order: Ordering) {
190
                self.fetch_and(val, order);
191
            }
192
            #[inline]
193
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
194
            pub(crate) fn or(&self, val: bool, order: Ordering) {
195
                self.fetch_or(val, order);
196
            }
197
            #[inline]
198
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
199
            pub(crate) fn xor(&self, val: bool, order: Ordering) {
200
                self.fetch_xor(val, order);
201
            }
202
        }
203
    };
204
    ($atomic_type:ident, $int_type:ty) => {
205
        impl $atomic_type {
206
            #[inline]
207
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
208
0
            pub(crate) fn add(&self, val: $int_type, order: Ordering) {
209
0
                self.fetch_add(val, order);
210
0
            }
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicI128>::add
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicU128>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicIsize>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicUsize>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI64>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU64>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI8>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU8>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI16>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU16>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI32>::add
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU32>::add
211
            #[inline]
212
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
213
0
            pub(crate) fn sub(&self, val: $int_type, order: Ordering) {
214
0
                self.fetch_sub(val, order);
215
0
            }
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicI128>::sub
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicU128>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicIsize>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicUsize>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI64>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU64>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI8>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU8>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI16>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU16>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI32>::sub
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU32>::sub
216
            #[inline]
217
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
218
0
            pub(crate) fn and(&self, val: $int_type, order: Ordering) {
219
0
                self.fetch_and(val, order);
220
0
            }
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicI128>::and
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicU128>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicIsize>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicUsize>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI64>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU64>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI8>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU8>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI16>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU16>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI32>::and
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU32>::and
221
            #[inline]
222
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
223
0
            pub(crate) fn or(&self, val: $int_type, order: Ordering) {
224
0
                self.fetch_or(val, order);
225
0
            }
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicI128>::or
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicU128>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicIsize>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicUsize>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI64>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU64>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI8>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU8>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI16>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU16>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI32>::or
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU32>::or
226
            #[inline]
227
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
228
0
            pub(crate) fn xor(&self, val: $int_type, order: Ordering) {
229
0
                self.fetch_xor(val, order);
230
0
            }
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicI128>::xor
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicU128>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicIsize>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicUsize>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI64>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU64>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI8>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU8>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI16>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU16>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI32>::xor
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU32>::xor
231
        }
232
    };
233
}
234
macro_rules! impl_default_bit_opts {
235
    (AtomicPtr, $int_type:ty) => {
236
        impl<T> AtomicPtr<T> {
237
            #[inline]
238
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
239
0
            pub(crate) fn bit_set(&self, bit: u32, order: Ordering) -> bool {
240
                #[cfg(portable_atomic_no_strict_provenance)]
241
                use crate::utils::ptr::PtrExt as _;
242
0
                let mask = <$int_type>::wrapping_shl(1, bit);
243
0
                self.fetch_or(mask, order).addr() & mask != 0
244
0
            }
245
            #[inline]
246
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
247
0
            pub(crate) fn bit_clear(&self, bit: u32, order: Ordering) -> bool {
248
                #[cfg(portable_atomic_no_strict_provenance)]
249
                use crate::utils::ptr::PtrExt as _;
250
0
                let mask = <$int_type>::wrapping_shl(1, bit);
251
0
                self.fetch_and(!mask, order).addr() & mask != 0
252
0
            }
253
            #[inline]
254
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
255
0
            pub(crate) fn bit_toggle(&self, bit: u32, order: Ordering) -> bool {
256
                #[cfg(portable_atomic_no_strict_provenance)]
257
                use crate::utils::ptr::PtrExt as _;
258
0
                let mask = <$int_type>::wrapping_shl(1, bit);
259
0
                self.fetch_xor(mask, order).addr() & mask != 0
260
0
            }
261
        }
262
    };
263
    ($atomic_type:ident, $int_type:ty) => {
264
        impl $atomic_type {
265
            #[inline]
266
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
267
0
            pub(crate) fn bit_set(&self, bit: u32, order: Ordering) -> bool {
268
0
                let mask = <$int_type>::wrapping_shl(1, bit);
269
0
                self.fetch_or(mask, order) & mask != 0
270
0
            }
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicI128>::bit_set
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicU128>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI8>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU8>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI16>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU16>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI32>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU32>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI64>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU64>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicIsize>::bit_set
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicUsize>::bit_set
271
            #[inline]
272
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
273
0
            pub(crate) fn bit_clear(&self, bit: u32, order: Ordering) -> bool {
274
0
                let mask = <$int_type>::wrapping_shl(1, bit);
275
0
                self.fetch_and(!mask, order) & mask != 0
276
0
            }
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicI128>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicU128>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI8>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU8>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI16>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU16>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI32>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU32>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI64>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU64>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicIsize>::bit_clear
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicUsize>::bit_clear
277
            #[inline]
278
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
279
0
            pub(crate) fn bit_toggle(&self, bit: u32, order: Ordering) -> bool {
280
0
                let mask = <$int_type>::wrapping_shl(1, bit);
281
0
                self.fetch_xor(mask, order) & mask != 0
282
0
            }
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicI128>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::atomic128::x86_64::AtomicU128>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI8>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU8>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI16>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU16>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI32>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU32>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicI64>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicU64>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicIsize>::bit_toggle
Unexecuted instantiation: <portable_atomic::imp::core_atomic::AtomicUsize>::bit_toggle
283
        }
284
    };
285
}
286
287
// This just outputs the input as is, but can be used like an item-level block by using it with cfg.
288
// Note: This macro is items!({ }), not items! { }.
289
// An extra brace is used in input to make contents rustfmt-able.
290
macro_rules! items {
291
    ({$($tt:tt)*}) => {
292
        $($tt)*
293
    };
294
}
295
296
// rustfmt-compatible cfg_select/cfg_if alternative
297
// Note: This macro is cfg_sel!({ }), not cfg_sel! { }.
298
// An extra brace is used in input to make contents rustfmt-able.
299
macro_rules! cfg_sel {
300
    ({#[cfg(else)] { $($output:tt)* }}) => {
301
        $($output)*
302
    };
303
    ({
304
        #[cfg($cfg:meta)]
305
        { $($output:tt)* }
306
        $($( $rest:tt )+)?
307
    }) => {
308
        #[cfg($cfg)]
309
        cfg_sel! {{#[cfg(else)] { $($output)* }}}
310
        $(
311
            #[cfg(not($cfg))]
312
            cfg_sel! {{ $($rest)+ }}
313
        )?
314
    };
315
    ({
316
        #[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg($cfg1:meta))]
317
        #[cfg_attr(not(portable_atomic_no_cfg_target_has_atomic), cfg($cfg2:meta))]
318
        { $($output:tt)* }
319
        $($( $rest:tt )+)?
320
    }) => {
321
        #[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg($cfg1))]
322
        #[cfg_attr(not(portable_atomic_no_cfg_target_has_atomic), cfg($cfg2))]
323
        cfg_sel! {{#[cfg(else)] { $($output)* }}}
324
        $(
325
            #[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg(not($cfg1)))]
326
            #[cfg_attr(not(portable_atomic_no_cfg_target_has_atomic), cfg(not($cfg2)))]
327
            cfg_sel! {{ $($rest)+ }}
328
        )?
329
    };
330
}
331
332
// Stable equivalent of core::hint::{likely, unlikely}.
333
#[allow(dead_code)]
334
#[inline(always)]
335
#[cold]
336
0
fn cold_path() {}
337
#[allow(dead_code)]
338
#[inline(always)]
339
0
pub(crate) fn likely(b: bool) -> bool {
340
0
    if b {
341
0
        true
342
    } else {
343
0
        cold_path();
344
0
        false
345
    }
346
0
}
347
#[allow(dead_code)]
348
#[inline(always)]
349
0
pub(crate) fn unlikely(b: bool) -> bool {
350
0
    if b {
351
0
        cold_path();
352
0
        true
353
    } else {
354
0
        false
355
    }
356
0
}
357
358
// Equivalent to core::hint::assert_unchecked, but compatible with pre-1.81 rustc.
359
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
360
#[allow(dead_code)]
361
#[inline(always)]
362
#[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
363
0
pub(crate) unsafe fn assert_unchecked(cond: bool) {
364
0
    if !cond {
365
        #[cfg(debug_assertions)]
366
        unreachable!();
367
        #[cfg(not(debug_assertions))]
368
        // SAFETY: the caller promised `cond` is true.
369
        unsafe {
370
0
            core::hint::unreachable_unchecked()
371
        }
372
0
    }
373
0
}
374
375
// https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L3338
376
#[inline]
377
#[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
378
0
pub(crate) fn assert_load_ordering(order: Ordering) {
379
0
    match order {
380
0
        Ordering::Acquire | Ordering::Relaxed | Ordering::SeqCst => {}
381
0
        Ordering::Release => panic!("there is no such thing as a release load"),
382
0
        Ordering::AcqRel => panic!("there is no such thing as an acquire-release load"),
383
0
        _ => unreachable!(),
384
    }
385
0
}
Unexecuted instantiation: portable_atomic::utils::assert_load_ordering
Unexecuted instantiation: portable_atomic::utils::assert_load_ordering
Unexecuted instantiation: portable_atomic::utils::assert_load_ordering
Unexecuted instantiation: portable_atomic::utils::assert_load_ordering
386
// https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L3323
387
#[inline]
388
#[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
389
0
pub(crate) fn assert_store_ordering(order: Ordering) {
390
0
    match order {
391
0
        Ordering::Release | Ordering::Relaxed | Ordering::SeqCst => {}
392
0
        Ordering::Acquire => panic!("there is no such thing as an acquire store"),
393
0
        Ordering::AcqRel => panic!("there is no such thing as an acquire-release store"),
394
0
        _ => unreachable!(),
395
    }
396
0
}
Unexecuted instantiation: portable_atomic::utils::assert_store_ordering
Unexecuted instantiation: portable_atomic::utils::assert_store_ordering
397
// https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L3404
398
#[inline]
399
#[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
400
0
pub(crate) fn assert_compare_exchange_ordering(success: Ordering, failure: Ordering) {
401
0
    match success {
402
        Ordering::AcqRel
403
        | Ordering::Acquire
404
        | Ordering::Relaxed
405
        | Ordering::Release
406
0
        | Ordering::SeqCst => {}
407
0
        _ => unreachable!(),
408
    }
409
0
    match failure {
410
0
        Ordering::Acquire | Ordering::Relaxed | Ordering::SeqCst => {}
411
0
        Ordering::Release => panic!("there is no such thing as a release failure ordering"),
412
0
        Ordering::AcqRel => panic!("there is no such thing as an acquire-release failure ordering"),
413
0
        _ => unreachable!(),
414
    }
415
0
}
Unexecuted instantiation: portable_atomic::utils::assert_compare_exchange_ordering
Unexecuted instantiation: portable_atomic::utils::assert_compare_exchange_ordering
Unexecuted instantiation: portable_atomic::utils::assert_compare_exchange_ordering
416
417
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0418r2.html
418
// https://github.com/rust-lang/rust/pull/98383
419
#[allow(dead_code)]
420
#[inline]
421
0
pub(crate) fn upgrade_success_ordering(success: Ordering, failure: Ordering) -> Ordering {
422
0
    match (success, failure) {
423
0
        (Ordering::Relaxed, Ordering::Acquire) => Ordering::Acquire,
424
0
        (Ordering::Release, Ordering::Acquire) => Ordering::AcqRel,
425
0
        (_, Ordering::SeqCst) => Ordering::SeqCst,
426
0
        _ => success,
427
    }
428
0
}
429
430
#[cfg(not(portable_atomic_no_asm_maybe_uninit))]
431
#[cfg(target_pointer_width = "32")]
432
// SAFETY: MaybeUninit returned by zero_extend64_ptr is always initialized.
433
const _: () = assert!(unsafe {
434
    zero_extend64_ptr(ptr::without_provenance_mut(!0)).assume_init() == !0_u32 as u64
435
});
436
/// Zero-extends the given 32-bit pointer to `MaybeUninit<u64>`.
437
/// This is used for 64-bit architecture's 32-bit ABI (e.g., AArch64 ILP32 ABI).
438
/// See ptr_reg! macro in src/gen/utils.rs for details.
439
#[cfg(not(portable_atomic_no_asm_maybe_uninit))]
440
#[cfg(target_pointer_width = "32")]
441
#[allow(dead_code)]
442
#[inline]
443
pub(crate) const fn zero_extend64_ptr(v: *mut ()) -> core::mem::MaybeUninit<u64> {
444
    #[repr(C)]
445
    struct ZeroExtended {
446
        #[cfg(target_endian = "big")]
447
        pad: *mut (),
448
        v: *mut (),
449
        #[cfg(target_endian = "little")]
450
        pad: *mut (),
451
    }
452
    // SAFETY: we can safely transmute any 64-bit value to MaybeUninit<u64>.
453
    unsafe { core::mem::transmute(ZeroExtended { v, pad: core::ptr::null_mut() }) }
454
}
455
456
#[allow(dead_code)]
457
#[cfg(any(
458
    target_arch = "aarch64",
459
    target_arch = "arm64ec",
460
    target_arch = "powerpc64",
461
    target_arch = "riscv64",
462
    target_arch = "s390x",
463
    target_arch = "x86_64",
464
))]
465
/// A 128-bit value represented as a pair of 64-bit values.
466
///
467
/// This type is `#[repr(C)]`, both fields have the same in-memory representation
468
/// and are plain old data types, so access to the fields is always safe.
469
#[derive(Clone, Copy)]
470
#[repr(C)]
471
pub(crate) union U128 {
472
    pub(crate) whole: u128,
473
    pub(crate) pair: Pair<u64>,
474
}
475
#[allow(dead_code)]
476
#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
477
/// A 64-bit value represented as a pair of 32-bit values.
478
///
479
/// This type is `#[repr(C)]`, both fields have the same in-memory representation
480
/// and are plain old data types, so access to the fields is always safe.
481
#[derive(Clone, Copy)]
482
#[repr(C)]
483
pub(crate) union U64 {
484
    pub(crate) whole: u64,
485
    pub(crate) pair: Pair<u32>,
486
}
487
#[allow(dead_code)]
488
#[derive(Clone, Copy)]
489
#[repr(C)]
490
pub(crate) struct Pair<T: Copy> {
491
    // little endian order
492
    #[cfg(any(
493
        target_endian = "little",
494
        target_arch = "aarch64",
495
        target_arch = "arm",
496
        target_arch = "arm64ec",
497
    ))]
498
    pub(crate) lo: T,
499
    pub(crate) hi: T,
500
    // big endian order
501
    #[cfg(not(any(
502
        target_endian = "little",
503
        target_arch = "aarch64",
504
        target_arch = "arm",
505
        target_arch = "arm64ec",
506
    )))]
507
    pub(crate) lo: T,
508
}
509
510
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
511
type MinWord = u32;
512
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
513
type RetInt = u32;
514
// Adapted from https://github.com/taiki-e/atomic-maybe-uninit/blob/v0.3.6/src/utils.rs#L255.
515
// Helper for implementing sub-word atomic operations using word-sized LL/SC loop or CAS loop.
516
//
517
// Refs: https://github.com/llvm/llvm-project/blob/llvmorg-22.1.0-rc1/llvm/lib/CodeGen/AtomicExpandPass.cpp#L811
518
// (aligned_ptr, shift, mask)
519
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
520
#[allow(dead_code)]
521
#[inline]
522
pub(crate) fn create_sub_word_mask_values<T>(ptr: *mut T) -> (*mut MinWord, RetInt, RetInt) {
523
    use core::mem;
524
525
    #[cfg(portable_atomic_no_strict_provenance)]
526
    use self::ptr::PtrExt as _;
527
528
    // RISC-V, MIPS, SPARC, LoongArch, Xtensa, BPF: shift amount of 32-bit shift instructions is 5 bits unsigned (0-31).
529
    // PowerPC, C-SKY: shift amount of 32-bit shift instructions is 6 bits unsigned (0-63) and shift amount 32-63 means "clear".
530
    // Arm: shift amount of 32-bit shift instructions is 8 bits unsigned (0-255).
531
    // Hexagon: shift amount of 32-bit shift instructions is 7 bits signed (-64-63) and negative shift amount means "reverse the direction of the shift".
532
    // (On s390x, we don't use the mask returned from this function.)
533
    // (See also https://devblogs.microsoft.com/oldnewthing/20230904-00/?p=108704 for others)
534
    const SHIFT_MASK: bool = !cfg!(any(
535
        target_arch = "bpf",
536
        target_arch = "loongarch32",
537
        target_arch = "loongarch64",
538
        target_arch = "mips",
539
        target_arch = "mips32r6",
540
        target_arch = "mips64",
541
        target_arch = "mips64r6",
542
        target_arch = "riscv32",
543
        target_arch = "riscv64",
544
        target_arch = "s390x",
545
        target_arch = "sparc",
546
        target_arch = "sparc64",
547
        target_arch = "xtensa",
548
    ));
549
    let ptr_mask = mem::size_of::<MinWord>() - 1;
550
    let aligned_ptr = ptr.with_addr(ptr.addr() & !ptr_mask) as *mut MinWord;
551
    let ptr_lsb = if SHIFT_MASK {
552
        ptr.addr() & ptr_mask
553
    } else {
554
        // We use 32-bit wrapping shift instructions in asm on these platforms.
555
        ptr.addr()
556
    };
557
    let shift = if cfg!(any(target_endian = "little", target_arch = "s390x")) {
558
        ptr_lsb.wrapping_mul(8)
559
    } else {
560
        (ptr_lsb ^ (mem::size_of::<MinWord>() - mem::size_of::<T>())).wrapping_mul(8)
561
    };
562
    let mut mask: RetInt = (1 << (mem::size_of::<T>() * 8)) - 1; // !(0 as T) as RetInt
563
    if SHIFT_MASK {
564
        mask <<= shift;
565
    }
566
    #[allow(clippy::cast_possible_truncation)]
567
    {
568
        (aligned_ptr, shift as RetInt, mask)
569
    }
570
}
571
572
// This module provides core::ptr strict_provenance/exposed_provenance polyfill for pre-1.84 rustc.
573
#[allow(dead_code)]
574
pub(crate) mod ptr {
575
    cfg_sel!({
576
        #[cfg(not(portable_atomic_no_strict_provenance))]
577
        {
578
            #[allow(unused_imports)]
579
            pub(crate) use core::ptr::{
580
                with_exposed_provenance, with_exposed_provenance_mut, without_provenance_mut,
581
            };
582
        }
583
        #[cfg(else)]
584
        {
585
            use core::mem;
586
587
            #[inline(always)]
588
            #[must_use]
589
            pub(crate) const fn without_provenance_mut<T>(addr: usize) -> *mut T {
590
                // An int-to-pointer transmute currently has exactly the intended semantics: it creates a
591
                // pointer without provenance. Note that this is *not* a stable guarantee about transmute
592
                // semantics, it relies on sysroot crates having special status.
593
                // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
594
                // pointer).
595
                #[cfg(miri)]
596
                unsafe {
597
                    mem::transmute(addr)
598
                }
599
                // const transmute requires Rust 1.56.
600
                #[cfg(not(miri))]
601
                {
602
                    addr as *mut T
603
                }
604
            }
605
            #[inline(always)]
606
            #[must_use]
607
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
608
            pub(crate) fn with_exposed_provenance<T>(addr: usize) -> *const T {
609
                addr as *const T
610
            }
611
            #[inline(always)]
612
            #[must_use]
613
            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
614
            pub(crate) fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T {
615
                addr as *mut T
616
            }
617
618
            pub(crate) trait PtrExt<T: ?Sized>: Copy {
619
                #[must_use]
620
                fn addr(self) -> usize;
621
                #[must_use]
622
                fn with_addr(self, addr: usize) -> Self
623
                where
624
                    T: Sized;
625
            }
626
            impl<T: ?Sized> PtrExt<T> for *mut T {
627
                #[inline(always)]
628
                #[must_use]
629
                fn addr(self) -> usize {
630
                    // A pointer-to-integer transmute currently has exactly the right semantics: it returns the
631
                    // address without exposing the provenance. Note that this is *not* a stable guarantee about
632
                    // transmute semantics, it relies on sysroot crates having special status.
633
                    // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
634
                    // provenance).
635
                    unsafe { mem::transmute(self as *mut ()) }
636
                }
637
                #[inline]
638
                #[must_use]
639
                fn with_addr(self, addr: usize) -> Self
640
                where
641
                    T: Sized,
642
                {
643
                    // This should probably be an intrinsic to avoid doing any sort of arithmetic, but
644
                    // meanwhile, we can implement it with `wrapping_offset`, which preserves the pointer's
645
                    // provenance.
646
                    let self_addr = self.addr() as isize;
647
                    let dest_addr = addr as isize;
648
                    let offset = dest_addr.wrapping_sub(self_addr);
649
                    (self as *mut u8).wrapping_offset(offset) as *mut T
650
                }
651
            }
652
        }
653
    });
654
}
655
656
// This module provides:
657
// - core::ffi polyfill (c_* type aliases and CStr) for pre-1.64 rustc compatibility.
658
//   (core::ffi::* (except c_void) requires Rust 1.64)
659
// - safe abstraction (c! macro) for creating static C strings without runtime checks.
660
//   (c"..." requires Rust 1.77)
661
// - helper macros for defining FFI bindings.
662
#[cfg(any(
663
    test,
664
    portable_atomic_test_no_std_static_assert_ffi,
665
    not(any(target_arch = "x86", target_arch = "x86_64"))
666
))]
667
#[cfg(any(not(portable_atomic_no_asm), portable_atomic_unstable_asm))]
668
#[allow(dead_code, non_camel_case_types, unused_macros)]
669
#[macro_use]
670
pub(crate) mod ffi {
671
    pub(crate) type c_void = core::ffi::c_void;
672
    // c_{,u}int is {i,u}16 on 16-bit targets, otherwise {i,u}32.
673
    // https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/ffi/mod.rs#L156
674
    #[cfg(target_pointer_width = "16")]
675
    pub(crate) type c_int = i16;
676
    #[cfg(target_pointer_width = "16")]
677
    pub(crate) type c_uint = u16;
678
    #[cfg(not(target_pointer_width = "16"))]
679
    pub(crate) type c_int = i32;
680
    #[cfg(not(target_pointer_width = "16"))]
681
    pub(crate) type c_uint = u32;
682
    // c_{,u}long is {i,u}64 on non-Windows 64-bit targets, otherwise {i,u}32.
683
    // https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/ffi/mod.rs#L168
684
    #[cfg(all(target_pointer_width = "64", not(windows)))]
685
    pub(crate) type c_long = i64;
686
    #[cfg(all(target_pointer_width = "64", not(windows)))]
687
    pub(crate) type c_ulong = u64;
688
    #[cfg(not(all(target_pointer_width = "64", not(windows))))]
689
    pub(crate) type c_long = i32;
690
    #[cfg(not(all(target_pointer_width = "64", not(windows))))]
691
    pub(crate) type c_ulong = u32;
692
    // c_size_t is currently always usize.
693
    // https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/ffi/mod.rs#L76
694
    pub(crate) type c_size_t = usize;
695
    // c_char is u8 by default on non-Apple/non-Windows/non-Vita Arm/C-SKY/Hexagon/MSP430/PowerPC/RISC-V/s390x/Xtensa targets, otherwise i8 by default.
696
    // See references in https://github.com/rust-lang/rust/issues/129945 for details.
697
    cfg_sel!({
698
        #[cfg(all(
699
            not(any(target_vendor = "apple", windows, target_os = "vita")),
700
            any(
701
                target_arch = "aarch64",
702
                target_arch = "arm",
703
                target_arch = "csky",
704
                target_arch = "hexagon",
705
                target_arch = "msp430",
706
                target_arch = "powerpc",
707
                target_arch = "powerpc64",
708
                target_arch = "riscv32",
709
                target_arch = "riscv64",
710
                target_arch = "s390x",
711
                target_arch = "xtensa",
712
            ),
713
        ))]
714
        {
715
            pub(crate) type c_char = u8;
716
        }
717
        #[cfg(else)]
718
        {
719
            pub(crate) type c_char = i8;
720
        }
721
    });
722
723
    // Static assertions for C type definitions.
724
    #[cfg(test)]
725
    const _: fn() = || {
726
        let _: c_int = 0 as std::os::raw::c_int;
727
        let _: c_uint = 0 as std::os::raw::c_uint;
728
        let _: c_long = 0 as std::os::raw::c_long;
729
        let _: c_ulong = 0 as std::os::raw::c_ulong;
730
        #[cfg(unix)]
731
        let _: c_size_t = 0 as libc::size_t; // std::os::raw::c_size_t is unstable
732
        let _: c_char = 0 as std::os::raw::c_char;
733
    };
734
735
    #[repr(transparent)]
736
    pub(crate) struct CStr([c_char]);
737
    impl CStr {
738
        #[inline]
739
        #[must_use]
740
        pub(crate) const fn as_ptr(&self) -> *const c_char {
741
            self.0.as_ptr()
742
        }
743
        /// # Safety
744
        ///
745
        /// The provided slice **must** be nul-terminated and not contain any interior
746
        /// nul bytes.
747
        #[inline]
748
        #[must_use]
749
        pub(crate) unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
750
            // SAFETY: Casting to CStr is safe because *our* CStr is #[repr(transparent)]
751
            // and its internal representation is a [u8] too. (Note that std's CStr
752
            // is not #[repr(transparent)].)
753
            // Dereferencing the obtained pointer is safe because it comes from a
754
            // reference. Making a reference is then safe because its lifetime
755
            // is bound by the lifetime of the given `bytes`.
756
            unsafe { &*(bytes as *const [u8] as *const CStr) }
757
        }
758
        #[cfg(test)]
759
        #[inline]
760
        #[must_use]
761
        pub(crate) fn to_bytes_with_nul(&self) -> &[u8] {
762
            #[allow(clippy::unnecessary_cast)] // triggered for targets that c_char is u8
763
            // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
764
            // is safe on all supported targets.
765
            unsafe {
766
                &*(&self.0 as *const [c_char] as *const [u8])
767
            }
768
        }
769
    }
770
771
    macro_rules! c {
772
        ($s:expr) => {{
773
            const BYTES: &[u8] = concat!($s, "\0").as_bytes();
774
            const _: () = static_assert!(crate::utils::ffi::_const_is_c_str(BYTES));
775
            #[allow(unused_unsafe)]
776
            // SAFETY: we've checked `BYTES` is a valid C string
777
            unsafe {
778
                crate::utils::ffi::CStr::from_bytes_with_nul_unchecked(BYTES)
779
            }
780
        }};
781
    }
782
783
    #[must_use]
784
    pub(crate) const fn _const_is_c_str(bytes: &[u8]) -> bool {
785
        #[cfg(portable_atomic_no_track_caller)]
786
        {
787
            // const_if_match/const_loop was stabilized (nightly-2020-06-30) 2 days before
788
            // track_caller was stabilized (nightly-2020-07-02), so we reuse the cfg for
789
            // track_caller here instead of emitting a cfg for const_if_match/const_loop.
790
            // https://github.com/rust-lang/rust/pull/72437
791
            // track_caller was stabilized 11 days after the oldest nightly version
792
            // that uses this module, and is included in the same 1.46 stable release.
793
            // The check here is insufficient in this case, but this is fine because this function
794
            // is internal code that is not used to process input from the user and our CI checks
795
            // all builtin targets and some custom targets with some versions of newer compilers.
796
            !bytes.is_empty()
797
        }
798
        #[cfg(not(portable_atomic_no_track_caller))]
799
        {
800
            // Based on https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/ffi/c_str.rs#L417
801
            // - bytes must be nul-terminated.
802
            // - bytes must not contain any interior nul bytes.
803
            if bytes.is_empty() {
804
                return false;
805
            }
806
            let mut i = bytes.len() - 1;
807
            if bytes[i] != 0 {
808
                return false;
809
            }
810
            // Ending null byte exists, skip to the rest.
811
            while i != 0 {
812
                i -= 1;
813
                if bytes[i] == 0 {
814
                    return false;
815
                }
816
            }
817
            true
818
        }
819
    }
820
821
    /// Defines types with #[cfg(test)] static assertions which checks
822
    /// types are the same as the platform's latest header files' ones.
823
    // Note: This macro is sys_ty!({ }), not sys_ty! { }.
824
    // An extra brace is used in input to make contents rustfmt-able.
825
    macro_rules! sys_type {
826
        ({$(
827
            $(#[$attr:meta])*
828
            $vis:vis type $([$($windows_path:ident)::+])? $name:ident = $ty:ty;
829
        )*}) => {
830
            $(
831
                $(#[$attr])*
832
                $vis type $name = $ty;
833
            )*
834
            #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
835
            test_helper::static_assert_sys_type!($(
836
                $(#[$attr])*
837
                type $([$($windows_path)::+])? $name;
838
            )*);
839
        };
840
    }
841
    /// Defines #[repr(C)] structs with #[cfg(test)] static assertions which checks
842
    /// fields are the same as the platform's latest header files' ones.
843
    // Note: This macro is sys_struct!({ }), not sys_struct! { }.
844
    // An extra brace is used in input to make contents rustfmt-able.
845
    macro_rules! sys_struct {
846
        ({$(
847
            $(#[$attr:meta])*
848
            $vis:vis struct $([$($windows_path:ident)::+])? $name:ident {$(
849
                $(#[$field_attr:meta])*
850
                $field_vis:vis $field_name:ident: $field_ty:ty,
851
            )*}
852
        )*}) => {
853
            $(
854
                $(#[$attr])*
855
                #[derive(Clone, Copy)]
856
                #[cfg_attr(
857
                    any(test, portable_atomic_test_no_std_static_assert_ffi),
858
                    derive(Debug, PartialEq)
859
                )]
860
                #[repr(C)]
861
                $vis struct $name {$(
862
                    $(#[$field_attr])*
863
                    $field_vis $field_name: $field_ty,
864
                )*}
865
            )*
866
            #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
867
            test_helper::static_assert_sys_struct!($(
868
                $(#[$attr])*
869
                struct $([$($windows_path)::+])? $name {$(
870
                    $(#[$field_attr])*
871
                    $field_name: $field_ty,
872
                )*}
873
            )*);
874
        };
875
    }
876
    /// Defines constants with #[cfg(test)] static assertions which checks
877
    /// values are the same as the platform's latest header files' ones.
878
    // Note: This macro is sys_const!({ }), not sys_const! { }.
879
    // An extra brace is used in input to make contents rustfmt-able.
880
    macro_rules! sys_const {
881
        ({$(
882
            $(#[$attr:meta])*
883
            $vis:vis const $([$($windows_path:ident)::+])? $name:ident: $ty:ty = $val:expr;
884
        )*}) => {
885
            $(
886
                $(#[$attr])*
887
                $vis const $name: $ty = $val;
888
            )*
889
            #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
890
            test_helper::static_assert_sys_const!($(
891
                $(#[$attr])*
892
                const $([$($windows_path)::+])? $name: $ty;
893
            )*);
894
        };
895
    }
896
    /// Defines functions with #[cfg(test)] static assertions which checks
897
    /// signatures are the same as the platform's latest header files' ones.
898
    // Note: This macro is sys_fn!({ }), not sys_fn! { }.
899
    // An extra brace is used in input to make contents rustfmt-able.
900
    macro_rules! sys_fn {
901
        ({
902
            $(#[$extern_attr:meta])*
903
            extern $abi:literal {$(
904
                $(#[$fn_attr:meta])*
905
                $vis:vis fn $([$($windows_path:ident)::+])? $name:ident(
906
                    $($args:tt)*
907
                ) $(-> $ret_ty:ty)?;
908
            )*}
909
        }) => {
910
            $(#[$extern_attr])*
911
            extern $abi {$(
912
                $(#[$fn_attr])*
913
                $vis fn $name($($args)*) $(-> $ret_ty)?;
914
            )*}
915
            #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
916
            test_helper::static_assert_sys_fn!(
917
                $(#[$extern_attr])*
918
                extern $abi {$(
919
                    $(#[$fn_attr])*
920
                    fn $([$($windows_path)::+])? $name($($args)*) $(-> $ret_ty)?;
921
                )*}
922
            );
923
        };
924
    }
925
926
    #[allow(
927
        clippy::alloc_instead_of_core,
928
        clippy::std_instead_of_alloc,
929
        clippy::std_instead_of_core,
930
        clippy::undocumented_unsafe_blocks,
931
        clippy::wildcard_imports
932
    )]
933
    #[cfg(test)]
934
    mod tests {
935
        #[test]
936
        fn test_c_macro() {
937
            #[track_caller]
938
            fn t(s: &crate::utils::ffi::CStr, raw: &[u8]) {
939
                assert_eq!(s.to_bytes_with_nul(), raw);
940
            }
941
            t(c!(""), b"\0");
942
            t(c!("a"), b"a\0");
943
            t(c!("abc"), b"abc\0");
944
            t(c!(concat!("abc", "d")), b"abcd\0");
945
        }
946
947
        #[test]
948
        fn test_is_c_str() {
949
            #[track_caller]
950
            fn t(bytes: &[u8]) {
951
                assert_eq!(
952
                    super::_const_is_c_str(bytes),
953
                    std::ffi::CStr::from_bytes_with_nul(bytes).is_ok()
954
                );
955
            }
956
            t(b"\0");
957
            t(b"a\0");
958
            t(b"abc\0");
959
            t(b"");
960
            t(b"a");
961
            t(b"abc");
962
            t(b"\0a");
963
            t(b"\0a\0");
964
            t(b"ab\0c\0");
965
            t(b"\0\0");
966
        }
967
    }
968
}