diff --git a/.github/.cspell/project-dictionary.txt b/.github/.cspell/project-dictionary.txt index ffc0d691..5d458ad8 100644 --- a/.github/.cspell/project-dictionary.txt +++ b/.github/.cspell/project-dictionary.txt @@ -170,6 +170,7 @@ uart umax umin unclonable +unsize usart uscat uwrite diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55db5fbf..81a32273 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 --tests ${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. @@ -368,7 +372,8 @@ jobs: 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' + # TODO: arm-linux-androideabi is removed due to an issue between Rust nightly & QEMU in CI testing - needs investigation + 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/Cargo.toml b/Cargo.toml index 92a15f6a..b0b1931c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -134,6 +134,8 @@ unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(portable_atomic_test_outline_atomics_detect_false,qemu,valgrind)', # Public APIs, considered unstable unless documented in readme. 'cfg(portable_atomic_no_outline_atomics,portable_atomic_outline_atomics)', + # Public unstable API(s) - portable-atomic-util + 'cfg(portable_atomic_unstable_coerce_unsized)', ] } unreachable_pub = "warn" # unsafe_op_in_unsafe_fn = "warn" # Set at crate-level instead since https://github.com/rust-lang/rust/pull/100081 is not available on MSRV diff --git a/portable-atomic-util/CHANGELOG.md b/portable-atomic-util/CHANGELOG.md index 5c3ba17d..c835f2fb 100644 --- a/portable-atomic-util/CHANGELOG.md +++ b/portable-atomic-util/CHANGELOG.md @@ -12,6 +12,8 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com ## [Unreleased] +- Add `portable_atomic_unstable_coerce_unsized` cfg option (requires Rust nightly) + ## [0.2.3] - 2024-10-17 - Add `new_uninit`/`new_uninit_slice`/`assume_init` to `Arc` at Rust 1.36+. (align to the [std `Arc` change in Rust 1.82](https://github.com/rust-lang/rust/pull/129401)) ([362dc9a](https://github.com/taiki-e/portable-atomic/commit/362dc9af2779c81aa346e89c4d3f3eef71cf29ed)) diff --git a/portable-atomic-util/README.md b/portable-atomic-util/README.md index 9ceecbb5..47607c89 100644 --- a/portable-atomic-util/README.md +++ b/portable-atomic-util/README.md @@ -38,6 +38,30 @@ 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` + + + +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/src/arc.rs b/portable-atomic-util/src/arc.rs index 82ac674f..56f4c4b7 100644 --- a/portable-atomic-util/src/arc.rs +++ b/portable-atomic-util/src/arc.rs @@ -2,7 +2,7 @@ // This module is based on alloc::sync::Arc. // -// The code has been adjusted to work with stable Rust. +// The code has been adjusted to work with stable Rust (and optionally support some unstable features). // // Source: https://github.com/rust-lang/rust/blob/a0c2aba29aa9ea50a7c45c3391dd446f856bef7b/library/alloc/src/sync.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 at the crate-level documentation, +/// 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 without depending on unstable features. /// /// [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> { @@ -142,6 +149,10 @@ impl Arc { /// This is an equivalent to [`std::sync::Weak`], but using [portable-atomic] for synchronization. /// See the documentation for [`std::sync::Weak`] for more details. /// +/// +/// **Note:** Unlike `std::sync::Weak`, coercing `Weak` to `Weak` is not possible, not even if +/// the optional cfg `portable_atomic_unstable_coerce_unsized` is enabled. +/// /// [`upgrade`]: Weak::upgrade /// [portable-atomic]: https://crates.io/crates/portable-atomic /// @@ -1508,11 +1519,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 +2245,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. let arr: [T; 0] = []; Arc::from(arr) } diff --git a/portable-atomic-util/src/lib.rs b/portable-atomic-util/src/lib.rs index 02a2c29d..a59a9c3a 100644 --- a/portable-atomic-util/src/lib.rs +++ b/portable-atomic-util/src/lib.rs @@ -32,6 +32,30 @@ 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` + + + +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 +84,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 the user explicitly opts-in to unstable cfg +#![cfg_attr(portable_atomic_unstable_coerce_unsized, feature(coerce_unsized, unsize))] #[cfg(all(feature = "alloc", not(portable_atomic_no_alloc)))] extern crate alloc; diff --git a/portable-atomic-util/tests/arc.rs b/portable-atomic-util/tests/arc.rs index 86058a7c..d9f152cb 100644 --- a/portable-atomic-util/tests/arc.rs +++ b/portable-atomic-util/tests/arc.rs @@ -257,8 +257,10 @@ mod alloc_tests { assert_eq!(unsafe { &*ptr }, "foo"); assert_eq!(arc, arc2); - // TODO: CoerceUnsized is needed to cast to Arc - // let arc: Arc = Arc::new(123); + #[cfg(portable_atomic_unstable_coerce_unsized)] + let arc: Arc = Arc::new(123); + // TODO: This is a workaround in case CoerceUnsized is not available - remove this once it is no longer needed + #[cfg(not(portable_atomic_unstable_coerce_unsized))] let arc: Arc = Arc::from(Box::new(123) as Box); let ptr = Arc::into_raw(arc.clone()); @@ -301,6 +303,7 @@ mod alloc_tests { // assert!(weak.ptr_eq(&weak2)); // // TODO: CoerceUnsized is needed to cast to Arc + // // (may be possible to support this with portable_atomic_unstable_coerce_unsized cfg option) // // let arc: Arc = Arc::new(123); // let arc: Arc = Arc::from(Box::new(123) as Box); // let weak: Weak = Arc::downgrade(&arc); @@ -477,8 +480,10 @@ mod alloc_tests { #[test] fn test_unsized() { - // TODO: CoerceUnsized is needed to cast to Arc<[..]> - // let x: Arc<[i32]> = Arc::new([1, 2, 3]); + #[cfg(portable_atomic_unstable_coerce_unsized)] + let x: Arc<[i32]> = Arc::new([1, 2, 3]); + // TODO: This is a workaround in case CoerceUnsized is not available - remove this once it is no longer needed + #[cfg(not(portable_atomic_unstable_coerce_unsized))] let x: Arc<[i32]> = Arc::from(Box::new([1, 2, 3]) as Box<[i32]>); assert_eq!(format!("{:?}", x), "[1, 2, 3]"); let y = Arc::downgrade(&x.clone()); @@ -652,11 +657,17 @@ mod alloc_tests { fn test_downcast() { use std::any::Any; - // TODO: CoerceUnsized is needed to cast to Arc - // let r1: Arc = Arc::new(i32::MAX); - // let r2: Arc = Arc::new("abc"); + #[cfg(portable_atomic_unstable_coerce_unsized)] + let r1: Arc = Arc::new(i32::MAX); + // TODO: This is a workaround in case CoerceUnsized is not available - remove this once it is no longer needed + #[cfg(not(portable_atomic_unstable_coerce_unsized))] let r1: Arc = Arc::from(Box::new(i32::MAX) as Box); + + #[cfg(portable_atomic_unstable_coerce_unsized)] + let r2: Arc = Arc::new("abc"); + // TODO: This is a workaround in case CoerceUnsized is not available - remove this once it is no longer needed + #[cfg(not(portable_atomic_unstable_coerce_unsized))] let r2: Arc = Arc::from(Box::new("abc") as Box);