summaryrefslogtreecommitdiffstats
path: root/vendor/portable-atomic/src/lib.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /vendor/portable-atomic/src/lib.rs
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/portable-atomic/src/lib.rs')
-rw-r--r--vendor/portable-atomic/src/lib.rs246
1 files changed, 194 insertions, 52 deletions
diff --git a/vendor/portable-atomic/src/lib.rs b/vendor/portable-atomic/src/lib.rs
index 4be988e8b..21d743d71 100644
--- a/vendor/portable-atomic/src/lib.rs
+++ b/vendor/portable-atomic/src/lib.rs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
/*!
<!-- tidy:crate-doc:start -->
Portable atomic types including support for 128-bit atomics, atomic float, etc.
@@ -8,7 +10,7 @@ Portable atomic types including support for 128-bit atomics, atomic float, etc.
- Provide atomic load/store for targets where atomic is not available at all in the standard library. (RISC-V without A-extension, MSP430, AVR)
- Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, pre-v6 ARM, RISC-V without A-extension, MSP430, AVR, Xtensa, etc.) (always enabled for MSP430 and AVR, [optional](#optional-features-critical-section) otherwise)
- Provide stable equivalents of the standard library's atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108), [`AtomicBool::fetch_not`](https://github.com/rust-lang/rust/issues/98485).
-- Make features that require newer compilers, such as [`fetch_{max,min}`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_max), [`fetch_update`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_update), [`as_ptr`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.as_ptr), and [stronger CAS failure ordering](https://github.com/rust-lang/rust/pull/98383) available on Rust 1.34+.
+- Make features that require newer compilers, such as [`fetch_{max,min}`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_max), [`fetch_update`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_update), [`as_ptr`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.as_ptr), [`from_ptr`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.from_ptr) and [stronger CAS failure ordering](https://github.com/rust-lang/rust/pull/98383) available on Rust 1.34+.
- Provide workaround for bugs in the standard library's atomic-related APIs, such as [rust-lang/rust#100650], `fence`/`compiler_fence` on MSP430 that cause LLVM error, etc.
<!-- TODO:
@@ -162,7 +164,7 @@ RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
If dynamic dispatching by run-time CPU feature detection is enabled, it allows maintaining support for older CPUs while using features that are not supported on older CPUs, such as CMPXCHG16B (x86_64) and FEAT_LSE (aarch64).
Note:
- - Dynamic detection is currently only enabled in Rust 1.61+ for aarch64, in Rust 1.59+ (AVX) or 1.69+ (CMPXCHG16B) for x86_64, nightly only for powerpc64 (disabled by default), otherwise it works the same as when this cfg is set.
+ - Dynamic detection is currently only enabled in Rust 1.59+ for aarch64, in Rust 1.59+ (AVX) or 1.69+ (CMPXCHG16B) for x86_64, nightly only for powerpc64 (disabled by default), otherwise it works the same as when this cfg is set.
- If the required target features are enabled at compile-time, the atomic operations are inlined.
- This is compatible with no-std (as with all features except `std`).
- On some targets, run-time detection is disabled by default mainly for compatibility with older versions of operating systems or incomplete build environments, and can be enabled by `--cfg portable_atomic_outline_atomics`. (When both cfg are enabled, `*_no_*` cfg is preferred.)
@@ -194,33 +196,33 @@ RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
)
))]
#![warn(
- improper_ctypes,
- missing_debug_implementations,
- missing_docs,
rust_2018_idioms,
single_use_lifetimes,
- unreachable_pub
-)]
-#![cfg_attr(not(portable_atomic_no_unsafe_op_in_unsafe_fn), warn(unsafe_op_in_unsafe_fn))] // unsafe_op_in_unsafe_fn requires Rust 1.52
-#![cfg_attr(portable_atomic_no_unsafe_op_in_unsafe_fn, allow(unused_unsafe))]
-#![warn(
+ unreachable_pub,
clippy::pedantic,
- // lints for public library
+ // Lints that may help when writing public library.
+ missing_debug_implementations,
+ missing_docs,
clippy::alloc_instead_of_core,
clippy::exhaustive_enums,
clippy::exhaustive_structs,
+ clippy::impl_trait_in_params,
+ clippy::missing_inline_in_public_items,
clippy::std_instead_of_alloc,
clippy::std_instead_of_core,
- // lints that help writing unsafe code
+ // Lints that may help when writing unsafe code.
+ improper_ctypes,
+ // improper_ctypes_definitions, // requires Rust 1.46
+ // unsafe_op_in_unsafe_fn, // set conditionally since it requires Rust 1.52
clippy::as_ptr_cast_mut,
clippy::default_union_representation,
+ clippy::inline_asm_x86_att_syntax,
clippy::trailing_empty_array,
clippy::transmute_undefined_repr,
clippy::undocumented_unsafe_blocks,
- // misc
- clippy::inline_asm_x86_att_syntax,
- clippy::missing_inline_in_public_items,
)]
+#![cfg_attr(not(portable_atomic_no_unsafe_op_in_unsafe_fn), warn(unsafe_op_in_unsafe_fn))] // unsafe_op_in_unsafe_fn requires Rust 1.52
+#![cfg_attr(portable_atomic_no_unsafe_op_in_unsafe_fn, allow(unused_unsafe))]
#![allow(
clippy::cast_lossless,
clippy::doc_markdown,
@@ -246,8 +248,8 @@ RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
target_arch = "avr",
target_arch = "msp430",
all(target_arch = "xtensa", portable_atomic_unsafe_assume_single_core),
- all(portable_atomic_unstable_asm_experimental_arch, target_arch = "powerpc64"),
- all(portable_atomic_unstable_asm_experimental_arch, target_arch = "s390x"),
+ all(target_arch = "powerpc64", portable_atomic_unstable_asm_experimental_arch),
+ all(target_arch = "s390x", portable_atomic_unstable_asm_experimental_arch),
),
),
feature(asm_experimental_arch)
@@ -256,22 +258,13 @@ RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
// These features are already stabilized or have already been removed from compilers,
// and can safely be enabled for old nightly as long as version detection works.
// - cfg(target_has_atomic)
-// - #[target_feature(enable = "lse")] on AArch64
// - #[target_feature(enable = "cmpxchg16b")] on x86_64
// - asm! on ARM, AArch64, RISC-V, x86_64
// - llvm_asm! on AVR (tier 3) and MSP430 (tier 3)
-// - #[instruction_set] on non-Linux pre-v6 ARM (tier 3)
+// - #[instruction_set] on non-Linux/Android pre-v6 ARM (tier 3)
#![cfg_attr(portable_atomic_unstable_cfg_target_has_atomic, feature(cfg_target_has_atomic))]
#![cfg_attr(
all(
- target_arch = "aarch64",
- portable_atomic_unstable_aarch64_target_feature,
- not(portable_atomic_no_outline_atomics),
- ),
- feature(aarch64_target_feature)
-)]
-#![cfg_attr(
- all(
target_arch = "x86_64",
portable_atomic_unstable_cmpxchg16b_target_feature,
not(portable_atomic_no_outline_atomics),
@@ -284,13 +277,10 @@ RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
all(
portable_atomic_unstable_asm,
any(
- all(
- any(target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64"),
- not(target_has_atomic = "ptr"),
- ),
- all(target_arch = "arm", not(target_has_atomic = "64")),
target_arch = "aarch64",
- target_arch = "x86",
+ target_arch = "arm",
+ target_arch = "riscv32",
+ target_arch = "riscv64",
target_arch = "x86_64",
),
),
@@ -302,9 +292,9 @@ RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
)]
#![cfg_attr(
all(
+ target_arch = "arm",
portable_atomic_unstable_isa_attribute,
any(test, portable_atomic_unsafe_assume_single_core),
- target_arch = "arm",
not(any(target_feature = "v6", portable_atomic_target_feature = "v6")),
not(target_has_atomic = "ptr"),
),
@@ -320,19 +310,28 @@ RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
),
feature(core_intrinsics)
)]
-// This feature will be unnecessary once stdarch submodule in rust-lang/rust is
-// updated to include https://github.com/rust-lang/stdarch/pull/1358.
+// This feature is only enabled for old nightly because cmpxchg16b_intrinsic has been stabilized.
#![cfg_attr(
- all(target_arch = "x86_64", any(miri, portable_atomic_sanitize_thread)),
+ all(
+ target_arch = "x86_64",
+ portable_atomic_unstable_cmpxchg16b_intrinsic,
+ any(miri, portable_atomic_sanitize_thread),
+ ),
feature(stdsimd)
)]
// docs.rs only
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(
all(
- target_arch = "mips",
portable_atomic_no_atomic_load_store,
- not(feature = "critical-section"),
+ not(any(
+ target_arch = "avr",
+ target_arch = "bpf",
+ target_arch = "msp430",
+ target_arch = "riscv32",
+ target_arch = "riscv64",
+ feature = "critical-section",
+ )),
),
allow(unused_imports, unused_macros)
)]
@@ -407,6 +406,9 @@ compile_error!("cfg(portable_atomic_disable_fiq) does not compatible with this t
#[cfg(portable_atomic_s_mode)]
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
compile_error!("cfg(portable_atomic_s_mode) does not compatible with this target");
+#[cfg(portable_atomic_force_amo)]
+#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
+compile_error!("cfg(portable_atomic_force_amo) does not compatible with this target");
#[cfg(portable_atomic_disable_fiq)]
#[cfg(not(portable_atomic_unsafe_assume_single_core))]
@@ -418,6 +420,11 @@ compile_error!(
compile_error!(
"cfg(portable_atomic_s_mode) may only be used together with cfg(portable_atomic_unsafe_assume_single_core)"
);
+#[cfg(portable_atomic_force_amo)]
+#[cfg(not(portable_atomic_unsafe_assume_single_core))]
+compile_error!(
+ "cfg(portable_atomic_force_amo) may only be used together with cfg(portable_atomic_unsafe_assume_single_core)"
+);
#[cfg(all(portable_atomic_unsafe_assume_single_core, feature = "critical-section"))]
compile_error!(
@@ -526,7 +533,7 @@ cfg_has_atomic_8! {
cfg_has_atomic_cas! {
// See https://github.com/rust-lang/rust/pull/114034 for details.
// https://github.com/rust-lang/rust/blob/9339f446a5302cd5041d3f3b5e59761f36699167/library/core/src/sync/atomic.rs#L134
-// https://godbolt.org/z/EvPTfPh44
+// https://godbolt.org/z/5W85abT58
#[cfg(portable_atomic_no_cfg_target_has_atomic)]
const EMULATE_ATOMIC_BOOL: bool = cfg!(all(
not(portable_atomic_no_atomic_cas),
@@ -600,6 +607,39 @@ impl AtomicBool {
Self { v: core::cell::UnsafeCell::new(v as u8) }
}
+ /// Creates a new `AtomicBool` from a pointer.
+ ///
+ /// # Safety
+ ///
+ /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can
+ /// be bigger than `align_of::<bool>()`).
+ /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
+ /// * If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
+ /// behind `ptr` must have a happens-before relationship with atomic accesses via the returned
+ /// value (or vice-versa).
+ /// * In other words, time periods where the value is accessed atomically may not overlap
+ /// with periods where the value is accessed non-atomically.
+ /// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
+ /// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
+ /// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
+ /// from the same thread.
+ /// * If this atomic type is *not* lock-free:
+ /// * Any accesses to the value behind `ptr` must have a happens-before relationship
+ /// with accesses via the returned value (or vice-versa).
+ /// * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
+ /// be compatible with operations performed by this atomic type.
+ /// * This method must not be used to create overlapping or mixed-size atomic accesses, as
+ /// these are not supported by the memory model.
+ ///
+ /// [valid]: core::ptr#safety
+ #[inline]
+ #[must_use]
+ pub unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a Self {
+ #[allow(clippy::cast_ptr_alignment)]
+ // SAFETY: guaranteed by the caller
+ unsafe { &*(ptr as *mut Self) }
+ }
+
/// Returns `true` if operations on values of this type are lock-free.
///
/// If the compiler or the platform doesn't support the necessary
@@ -662,9 +702,8 @@ impl AtomicBool {
unsafe { &mut *(self.v.get() as *mut bool) }
}
- // TODO: Add from_mut/get_mut_slice/from_mut_slice/from_ptr once it is stable on std atomic types.
+ // TODO: Add from_mut/get_mut_slice/from_mut_slice once it is stable on std atomic types.
// https://github.com/rust-lang/rust/issues/76314
- // https://github.com/rust-lang/rust/issues/108652
/// Consumes the atomic and returns the contained value.
///
@@ -1425,6 +1464,39 @@ impl<T> AtomicPtr<T> {
Self { inner: imp::AtomicPtr::new(p) }
}
+ /// Creates a new `AtomicPtr` from a pointer.
+ ///
+ /// # Safety
+ ///
+ /// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this
+ /// can be bigger than `align_of::<*mut T>()`).
+ /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
+ /// * If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
+ /// behind `ptr` must have a happens-before relationship with atomic accesses via the returned
+ /// value (or vice-versa).
+ /// * In other words, time periods where the value is accessed atomically may not overlap
+ /// with periods where the value is accessed non-atomically.
+ /// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
+ /// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
+ /// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
+ /// from the same thread.
+ /// * If this atomic type is *not* lock-free:
+ /// * Any accesses to the value behind `ptr` must have a happens-before relationship
+ /// with accesses via the returned value (or vice-versa).
+ /// * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
+ /// be compatible with operations performed by this atomic type.
+ /// * This method must not be used to create overlapping or mixed-size atomic accesses, as
+ /// these are not supported by the memory model.
+ ///
+ /// [valid]: core::ptr#safety
+ #[inline]
+ #[must_use]
+ pub unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a Self {
+ #[allow(clippy::cast_ptr_alignment)]
+ // SAFETY: guaranteed by the caller
+ unsafe { &*(ptr as *mut Self) }
+ }
+
/// Returns `true` if operations on values of this type are lock-free.
///
/// If the compiler or the platform doesn't support the necessary
@@ -1487,9 +1559,8 @@ impl<T> AtomicPtr<T> {
self.inner.get_mut()
}
- // TODO: Add from_mut/get_mut_slice/from_mut_slice/from_ptr once it is stable on std atomic types.
+ // TODO: Add from_mut/get_mut_slice/from_mut_slice once it is stable on std atomic types.
// https://github.com/rust-lang/rust/issues/76314
- // https://github.com/rust-lang/rust/issues/108652
/// Consumes the atomic and returns the contained value.
///
@@ -2160,7 +2231,7 @@ impl<T> AtomicPtr<T> {
#[cfg(miri)]
{
let mask = 1_usize.wrapping_shl(bit);
- strict::addr(self.fetch_or(mask, order)) & mask != 0
+ self.fetch_or(mask, order) as usize & mask != 0
}
#[cfg(not(miri))]
{
@@ -2205,7 +2276,7 @@ impl<T> AtomicPtr<T> {
#[cfg(miri)]
{
let mask = 1_usize.wrapping_shl(bit);
- strict::addr(self.fetch_and(!mask, order)) & mask != 0
+ self.fetch_and(!mask, order) as usize & mask != 0
}
#[cfg(not(miri))]
{
@@ -2250,7 +2321,7 @@ impl<T> AtomicPtr<T> {
#[cfg(miri)]
{
let mask = 1_usize.wrapping_shl(bit);
- strict::addr(self.fetch_xor(mask, order)) & mask != 0
+ self.fetch_xor(mask, order) as usize & mask != 0
}
#[cfg(not(miri))]
{
@@ -2380,6 +2451,42 @@ let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
}
doc_comment! {
+ concat!("Creates a new reference to an atomic integer from a pointer.
+
+# Safety
+
+* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
+ can be bigger than `align_of::<", stringify!($int_type), ">()`).
+* `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
+* If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
+ behind `ptr` must have a happens-before relationship with atomic accesses via
+ the returned value (or vice-versa).
+ * In other words, time periods where the value is accessed atomically may not
+ overlap with periods where the value is accessed non-atomically.
+ * This requirement is trivially satisfied if `ptr` is never used non-atomically
+ for the duration of lifetime `'a`. Most use cases should be able to follow
+ this guideline.
+ * This requirement is also trivially satisfied if all accesses (atomic or not) are
+ done from the same thread.
+* If this atomic type is *not* lock-free:
+ * Any accesses to the value behind `ptr` must have a happens-before relationship
+ with accesses via the returned value (or vice-versa).
+ * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
+ be compatible with operations performed by this atomic type.
+* This method must not be used to create overlapping or mixed-size atomic
+ accesses, as these are not supported by the memory model.
+
+[valid]: core::ptr#safety"),
+ #[inline]
+ #[must_use]
+ pub unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a Self {
+ #[allow(clippy::cast_ptr_alignment)]
+ // SAFETY: guaranteed by the caller
+ unsafe { &*(ptr as *mut Self) }
+ }
+ }
+
+ doc_comment! {
concat!("Returns `true` if operations on values of this type are lock-free.
If the compiler or the platform doesn't support the necessary
@@ -2445,9 +2552,8 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5);
}
}
- // TODO: Add from_mut/get_mut_slice/from_mut_slice/from_ptr once it is stable on std atomic types.
+ // TODO: Add from_mut/get_mut_slice/from_mut_slice once it is stable on std atomic types.
// https://github.com/rust-lang/rust/issues/76314
- // https://github.com/rust-lang/rust/issues/108652
doc_comment! {
concat!("Consumes the atomic and returns the contained value.
@@ -3443,6 +3549,42 @@ This type has the same in-memory representation as the underlying floating point
Self { inner: imp::float::$atomic_type::new(v) }
}
+ doc_comment! {
+ concat!("Creates a new reference to an atomic float from a pointer.
+
+# Safety
+
+* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
+ can be bigger than `align_of::<", stringify!($float_type), ">()`).
+* `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
+* If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
+ behind `ptr` must have a happens-before relationship with atomic accesses via
+ the returned value (or vice-versa).
+ * In other words, time periods where the value is accessed atomically may not
+ overlap with periods where the value is accessed non-atomically.
+ * This requirement is trivially satisfied if `ptr` is never used non-atomically
+ for the duration of lifetime `'a`. Most use cases should be able to follow
+ this guideline.
+ * This requirement is also trivially satisfied if all accesses (atomic or not) are
+ done from the same thread.
+* If this atomic type is *not* lock-free:
+ * Any accesses to the value behind `ptr` must have a happens-before relationship
+ with accesses via the returned value (or vice-versa).
+ * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
+ be compatible with operations performed by this atomic type.
+* This method must not be used to create overlapping or mixed-size atomic
+ accesses, as these are not supported by the memory model.
+
+[valid]: core::ptr#safety"),
+ #[inline]
+ #[must_use]
+ pub unsafe fn from_ptr<'a>(ptr: *mut $float_type) -> &'a Self {
+ #[allow(clippy::cast_ptr_alignment)]
+ // SAFETY: guaranteed by the caller
+ unsafe { &*(ptr as *mut Self) }
+ }
+ }
+
/// Returns `true` if operations on values of this type are lock-free.
///
/// If the compiler or the platform doesn't support the necessary
@@ -3477,7 +3619,7 @@ This type has the same in-memory representation as the underlying floating point
self.inner.get_mut()
}
- // TODO: Add from_mut once it is stable on std atomic types.
+ // TODO: Add from_mut/get_mut_slice/from_mut_slice once it is stable on std atomic types.
// https://github.com/rust-lang/rust/issues/76314
/// Consumes the atomic and returns the contained value.
@@ -3752,7 +3894,7 @@ This type has the same in-memory representation as the underlying floating point
#[cfg(not(portable_atomic_no_const_raw_ptr_deref))]
doc_comment! {
- concat!("Raw transmutation to `", stringify!($atomic_int_type), "`.
+ concat!("Raw transmutation to `&", stringify!($atomic_int_type), "`.
See [`", stringify!($float_type) ,"::from_bits`] for some discussion of the
portability of this operation (there are almost no issues).
@@ -3765,7 +3907,7 @@ This is `const fn` on Rust 1.58+."),
}
#[cfg(portable_atomic_no_const_raw_ptr_deref)]
doc_comment! {
- concat!("Raw transmutation to `", stringify!($atomic_int_type), "`.
+ concat!("Raw transmutation to `&", stringify!($atomic_int_type), "`.
See [`", stringify!($float_type) ,"::from_bits`] for some discussion of the
portability of this operation (there are almost no issues).