diff --git a/.github/.cspell/project-dictionary.txt b/.github/.cspell/project-dictionary.txt index 0ccca448..46d454d2 100644 --- a/.github/.cspell/project-dictionary.txt +++ b/.github/.cspell/project-dictionary.txt @@ -169,6 +169,7 @@ uart umax umin unclonable +unsize usart uscat uwrite diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55db5fbf..90c6f4d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -349,6 +349,10 @@ jobs: if: matrix.rust == 'nightly-2024-02-13' - run: tools/test.sh -vv ${TARGET:-} ${DOCTEST_XCOMPILE:-} ${BUILD_STD:-} ${RELEASE:-} + - run: tools/test.sh -vv ${TARGET:-} ${BUILD_STD:-} ${RELEASE:-} + env: + RUSTFLAGS: ${{ env.RUSTFLAGS }} --cfg portable_atomic_unstable_coerce_unsized + if: startsWith(matrix.rust, 'nightly') # We test doctest only once with the default build conditions because doctest is slow. Both api-test # and src/tests have extended copies of doctest, so this will not reduce test coverage. # portable_atomic_no_outline_atomics only affects x86_64, AArch64, Arm, powerpc64, and RISC-V Linux. @@ -367,8 +371,9 @@ jobs: # __kuser_helper_version < 5, etc., and is not a public API. RUSTDOCFLAGS: ${{ env.RUSTDOCFLAGS }} --cfg portable_atomic_test_outline_atomics_detect_false RUSTFLAGS: ${{ env.RUSTFLAGS }} --cfg portable_atomic_test_outline_atomics_detect_false - # powerpc64 is skipped because tested below. - if: (matrix.target == '' && !contains(matrix.rust, 'i686') || startsWith(matrix.target, 'x86_64')) || startsWith(matrix.target, 'aarch64') && !(contains(matrix.target, '-musl') && matrix.flags == '') || startsWith(matrix.target, 'armv5te') || matrix.target == 'arm-linux-androideabi' + # PowerPC 64-bit is skipped because it is tested below. + # arm-linux-androideabi is removed due to an apparent issue between Rust nightly & QEmu in CI testing + if: (matrix.target == '' && !contains(matrix.rust, 'i686') || startsWith(matrix.target, 'x86_64')) || startsWith(matrix.target, 'aarch64') && !(contains(matrix.target, '-musl') && matrix.flags == '') || startsWith(matrix.target, 'armv5te') - run: tools/test.sh -vv --tests ${TARGET:-} ${BUILD_STD:-} ${RELEASE:-} env: QEMU_CPU: power7 # no quadword-atomics diff --git a/portable-atomic-util/README.md b/portable-atomic-util/README.md index 9ceecbb5..f9413e11 100644 --- a/portable-atomic-util/README.md +++ b/portable-atomic-util/README.md @@ -38,6 +38,28 @@ See [#1] for other primitives being considered for addition to this crate. [portable-atomic]: https://github.com/taiki-e/portable-atomic [#1]: https://github.com/taiki-e/portable-atomic/issues/1 +## Optional cfg + +One of the ways to enable cfg is to set [rustflags in the cargo config](https://doc.rust-lang.org/cargo/reference/config.html#targettriplerustflags): + +```toml +# .cargo/config.toml +[target.] +rustflags = ["--cfg", "portable_atomic_unstable_coerce_unsized"] +``` + +Or set environment variable: + +```sh +RUSTFLAGS="--cfg portable_atomic_unstable_coerce_unsized" cargo ... +``` + +- **`--cfg portable_atomic_unstable_coerce_unsized`**
support standard coercing of `Arc` to `Arc` and same for weak references + +This coercing requires Rust nightly to compile (with help from [unstable `CoerceUnsized` trait](https://doc.rust-lang.org/nightly/core/ops/trait.CoerceUnsized.html)). + +See [this issue comment](https://github.com/taiki-e/portable-atomic/issues/143#issuecomment-1866488569) for another known workaround. + ## License diff --git a/portable-atomic-util/build.rs b/portable-atomic-util/build.rs index a8b95f37..39ab4871 100644 --- a/portable-atomic-util/build.rs +++ b/portable-atomic-util/build.rs @@ -33,7 +33,7 @@ fn main() { // Custom cfgs set by build script. Not public API. // grep -F 'cargo:rustc-cfg=' build.rs | grep -Ev '^ *//' | sed -E 's/^.*cargo:rustc-cfg=//; s/(=\\)?".*$//' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/' println!( - "cargo:rustc-check-cfg=cfg(portable_atomic_no_alloc,portable_atomic_no_alloc_layout_extras,portable_atomic_no_core_unwind_safe,portable_atomic_no_error_in_core,portable_atomic_no_futures_api,portable_atomic_no_io_safety,portable_atomic_no_io_vec,portable_atomic_no_maybe_uninit,portable_atomic_no_min_const_generics,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_sanitize_thread)" + "cargo:rustc-check-cfg=cfg(portable_atomic_no_alloc,portable_atomic_no_alloc_layout_extras,portable_atomic_no_core_unwind_safe,portable_atomic_no_error_in_core,portable_atomic_no_futures_api,portable_atomic_no_io_safety,portable_atomic_no_io_vec,portable_atomic_no_maybe_uninit,portable_atomic_no_min_const_generics,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_sanitize_thread,portable_atomic_unstable_coerce_unsized)" ); } diff --git a/portable-atomic-util/src/arc.rs b/portable-atomic-util/src/arc.rs index 82ac674f..19e8aa1c 100644 --- a/portable-atomic-util/src/arc.rs +++ b/portable-atomic-util/src/arc.rs @@ -39,6 +39,8 @@ use core::{ ptr::{self, NonNull}, usize, }; +#[cfg(portable_atomic_unstable_coerce_unsized)] +use core::{marker::Unsize, ops::CoerceUnsized}; /// A soft limit on the amount of references that may be made to an `Arc`. /// @@ -77,11 +79,13 @@ macro_rules! acquire { /// This is an equivalent to [`std::sync::Arc`], but using [portable-atomic] for synchronization. /// See the documentation for [`std::sync::Arc`] for more details. /// -/// **Note:** Unlike `std::sync::Arc`, coercing `Arc` to `Arc` is not supported at all. +/// **Note:** Unlike `std::sync::Arc`, coercing `Arc` to `Arc` is only possible if +/// the optional cfg `portable_atomic_unstable_coerce_unsized` is enabled, as documented for this crate, +/// and this optional cfg item is only supported with Rust nightly version. /// This is because coercing the pointee requires the /// [unstable `CoerceUnsized` trait](https://doc.rust-lang.org/nightly/core/ops/trait.CoerceUnsized.html). /// See [this issue comment](https://github.com/taiki-e/portable-atomic/issues/143#issuecomment-1866488569) -/// for the known workaround. +/// for a workaround that works with stable and beta Rust channels. /// /// [portable-atomic]: https://crates.io/crates/portable-atomic /// @@ -115,6 +119,9 @@ impl core::panic::UnwindSafe for Arc #[cfg(all(portable_atomic_no_core_unwind_safe, feature = "std"))] impl std::panic::UnwindSafe for Arc {} +#[cfg(portable_atomic_unstable_coerce_unsized)] +impl, U: ?Sized> CoerceUnsized> for Arc {} + impl Arc { #[inline] fn into_inner_non_null(this: Self) -> NonNull> { @@ -174,6 +181,9 @@ pub struct Weak { unsafe impl Send for Weak {} unsafe impl Sync for Weak {} +#[cfg(portable_atomic_unstable_coerce_unsized)] +impl, U: ?Sized> CoerceUnsized> for Weak {} + impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("(Weak)") @@ -1508,11 +1518,11 @@ impl Arc { /// } /// /// let my_string = "Hello World".to_string(); - // TODO: CoerceUnsized is needed to cast Arc -> Arc directly. - // /// print_if_string(Arc::new(my_string)); - // /// print_if_string(Arc::new(0i8)); /// print_if_string(Arc::from(Box::new(my_string) as Box)); /// print_if_string(Arc::from(Box::new(0i8) as Box)); + /// // or with "--cfg portable_atomic_unstable_coerce_unsized" in RUSTFLAGS (requires Rust nightly): + /// // print_if_string(Arc::new(my_string)); + /// // print_if_string(Arc::new(0i8)); /// ``` #[inline] pub fn downcast(self) -> Result, Self> @@ -2234,7 +2244,7 @@ impl Default for Arc<[T]> { #[inline] fn default() -> Self { // TODO: we cannot use non-allocation optimization (https://github.com/rust-lang/rust/blob/1.80.0/library/alloc/src/sync.rs#L3449) - // for now due to casting Arc<[T; N]> -> Arc<[T]> requires unstable CoerceUnsized. + // for now since casting Arc<[T; N]> -> Arc<[T]> requires unstable CoerceUnsized from Rust nightly. let arr: [T; 0] = []; Arc::from(arr) } @@ -2292,7 +2302,8 @@ impl From<[T; N]> for Arc<[T]> { /// ``` #[inline] fn from(v: [T; N]) -> Self { - // Casting Arc<[T; N]> -> Arc<[T]> requires unstable CoerceUnsized, so we convert via Box. + // Casting Arc<[T; N]> -> Arc<[T]> requires unstable CoerceUnsized (with Rust nightly), + // so we convert via Box to support stable & beta Rust channels. // Since the compiler knows the actual size and metadata, the intermediate allocation is // optimized and generates the same code as when using CoerceUnsized and convert Arc<[T; N]> to Arc<[T]>. // https://github.com/taiki-e/portable-atomic/issues/143#issuecomment-1866488569 diff --git a/portable-atomic-util/src/lib.rs b/portable-atomic-util/src/lib.rs index 3d0292d4..2a576ba9 100644 --- a/portable-atomic-util/src/lib.rs +++ b/portable-atomic-util/src/lib.rs @@ -32,6 +32,28 @@ See [#1] for other primitives being considered for addition to this crate. [portable-atomic]: https://github.com/taiki-e/portable-atomic [#1]: https://github.com/taiki-e/portable-atomic/issues/1 +## Optional cfg + +One of the ways to enable cfg is to set [rustflags in the cargo config](https://doc.rust-lang.org/cargo/reference/config.html#targettriplerustflags): + +```toml +# .cargo/config.toml +[target.] +rustflags = ["--cfg", "portable_atomic_unstable_coerce_unsized"] +``` + +Or set environment variable: + +```sh +RUSTFLAGS="--cfg portable_atomic_unstable_coerce_unsized" cargo ... +``` + +- **`--cfg portable_atomic_unstable_coerce_unsized`**
support standard coercing of `Arc` to `Arc` and same for weak references + +This coercing requires Rust nightly to compile (with help from [unstable `CoerceUnsized` trait](https://doc.rust-lang.org/nightly/core/ops/trait.CoerceUnsized.html)). + +See [this issue comment](https://github.com/taiki-e/portable-atomic/issues/143#issuecomment-1866488569) for another known workaround. + */ @@ -60,6 +82,8 @@ See [#1] for other primitives being considered for addition to this crate. #![allow(clippy::inline_always)] // docs.rs only (cfg is enabled by docs.rs, not build script) #![cfg_attr(docsrs, feature(doc_cfg))] +// Enable custom unsized coercions if needed by cfg +#![cfg_attr(portable_atomic_unstable_coerce_unsized, feature(coerce_unsized, unsize))] #[cfg(all(feature = "alloc", not(portable_atomic_no_alloc)))] extern crate alloc;