diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b86152cbf6..aa6073cc6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,16 +10,13 @@ name: Build & Tests on: pull_request: - push: - branches: - - main - - v0.6.x merge_group: permissions: read-all env: CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 RUSTFLAGS: -Dwarnings RUSTDOCFLAGS: -Dwarnings # `ZC_NIGHTLY_XXX` are flags that we add to `XXX` only on the nightly @@ -56,10 +53,6 @@ jobs: # which a particular feature is supported. "zerocopy-core-error", "zerocopy-diagnostic-on-unimplemented", - "zerocopy-generic-bounds-in-const-fn", - "zerocopy-target-has-atomics", - "zerocopy-aarch64-simd", - "zerocopy-panic-in-const-and-vec-try-reserve" ] target: [ "i686-unknown-linux-gnu", @@ -93,14 +86,6 @@ jobs: features: "--all-features" - toolchain: "zerocopy-diagnostic-on-unimplemented" features: "--all-features" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - features: "--all-features" - - toolchain: "zerocopy-target-has-atomics" - features: "--all-features" - - toolchain: "zerocopy-aarch64-simd" - features: "--all-features" - - toolchain: "zerocopy-panic-in-const-and-vec-try-reserve" - features: "--all-features" # Exclude any combination for the zerocopy-derive crate which # uses zerocopy features. - crate: "zerocopy-derive" @@ -117,36 +102,6 @@ jobs: toolchain: "zerocopy-core-error" - crate: "zerocopy-derive" toolchain: "zerocopy-diagnostic-on-unimplemented" - - crate: "zerocopy-derive" - toolchain: "zerocopy-generic-bounds-in-const-fn" - - crate: "zerocopy-derive" - toolchain: "zerocopy-target-has-atomics" - - crate: "zerocopy-derive" - toolchain: "zerocopy-aarch64-simd" - - crate: "zerocopy-derive" - toolchain: "zerocopy-panic-in-const-and-vec-try-reserve" - # Exclude non-aarch64 targets from the `zerocopy-aarch64-simd` - # toolchain. - - toolchain: "zerocopy-aarch64-simd" - target: "i686-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "x86_64-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "arm-unknown-linux-gnueabi" - - toolchain: "zerocopy-aarch64-simd" - target: "powerpc-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "powerpc64-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "riscv64gc-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "s390x-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "x86_64-pc-windows-msvc" - - toolchain: "zerocopy-aarch64-simd" - target: "thumbv6m-none-eabi" - - toolchain: "zerocopy-aarch64-simd" - target: "wasm32-wasi" # Exclude most targets targets from the `zerocopy-core-error` # toolchain since the `zerocopy-core-error` feature is unrelated to # compilation target. This only leaves i686 and x86_64 targets. @@ -190,28 +145,6 @@ jobs: target: "thumbv6m-none-eabi" - toolchain: "zerocopy-diagnostic-on-unimplemented" target: "wasm32-wasi" - # Exclude most targets targets from the - # `zerocopy-generic-bounds-in-const-fn` toolchain since the - # `zerocopy-generic-bounds-in-const-fn` feature is unrelated to - # compilation target. This only leaves i686 and x86_64 targets. - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "arm-unknown-linux-gnueabi" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "aarch64-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "powerpc-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "powerpc64-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "riscv64gc-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "s390x-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "x86_64-pc-windows-msvc" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "thumbv6m-none-eabi" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "wasm32-wasi" # Exclude `thumbv6m-none-eabi` combined with any feature that implies # the `std` feature since `thumbv6m-none-eabi` does not include a # pre-compiled std. @@ -259,7 +192,7 @@ jobs: set -eo pipefail # Override the exising `syn` dependency with one which requires an exact # version. - cargo add -p zerocopy-derive 'syn@=2.0.46' + cargo add -p zerocopy-derive 'syn@=2.0.79' - name: Configure environment variables run: | @@ -321,7 +254,7 @@ jobs: components: clippy, rust-src ${{ matrix.toolchain == 'nightly' && ', miri' || '' }} - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: key: "${{ matrix.target }}" @@ -575,6 +508,77 @@ jobs: # `roll-pinned-toolchain-versions.yml`. kani-version: 0.55.0 + unsafe_fields: + runs-on: ubuntu-latest + needs: generate_cache + strategy: + # By default, this is set to `true`, which means that a single CI job + # failure will cause all outstanding jobs to be canceled. This slows down + # development because it means that errors need to be encountered and + # fixed one at a time. + fail-fast: false + matrix: + toolchain: [ + "msrv", + "stable", + "nightly", + ] + features: [ + "", + "--features zerocopy_0_8", + ] + steps: + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - name: Configure environment variables + run: | + set -eo pipefail + ZC_TOOLCHAIN="$(./cargo.sh --version ${{ matrix.toolchain }})" + echo "ZC_TOOLCHAIN=$ZC_TOOLCHAIN" >> $GITHUB_ENV + - name: Install stable Rust for use in 'cargo.sh' + uses: dtolnay/rust-toolchain@00b49be78f40fba4e87296b2ead62868750bdd83 # stable + with: + toolchain: stable + - name: Install Rust with nightly toolchain (${{ env.ZC_TOOLCHAIN }}) and target aarch64_be-unknown-linux-gnu + uses: dtolnay/rust-toolchain@00b49be78f40fba4e87296b2ead62868750bdd83 # stable + with: + toolchain: ${{ env.ZC_TOOLCHAIN }} + components: clippy, rust-src + - name: Check + run: ./cargo.sh +${{ matrix.toolchain }} check --package unsafe-fields ${{ matrix.features }} --verbose + - name: Check tests + run: ./cargo.sh +${{ matrix.toolchain }} check --tests --package unsafe-fields ${{ matrix.features }} --verbose + - name: Build + run: ./cargo.sh +${{ matrix.toolchain }} build --package unsafe-fields ${{ matrix.features }} --verbose + - name: Run tests + run: ./cargo.sh +${{ matrix.toolchain }} test --package unsafe-fields ${{ matrix.features }} --verbose + - name: Clippy + run: ./cargo.sh +${{ matrix.toolchain }} clippy --package unsafe-fields ${{ matrix.features }} --verbose + # See comment in next step for why we only run on nightly. + if: matrix.toolchain == 'nightly' + - name: Clippy tests + run: ./cargo.sh +${{ matrix.toolchain }} clippy --package unsafe-fields --tests ${{ matrix.features }} --verbose + # Clippy improves the accuracy of lints over time, and fixes bugs. Only + # running Clippy on nightly allows us to avoid having to write code + # which is compatible with older versions of Clippy, which sometimes + # requires hacks to work around limitations that are fixed in more + # recent versions. + if: matrix.toolchain == 'nightly' + - name: Cargo doc + # We pass --document-private-items and --document-hidden items to ensure + # that documentation always builds even for these items. This makes + # future changes to make those items public/non-hidden more painless. + # Note that --document-hidden-items is unstable; if a future release + # breaks or removes it, we can just update CI to no longer pass that + # flag. + run: | + # Include arguments passed during docs.rs deployments to make sure those + # work properly. + set -eo pipefail + METADATA_DOCS_RS_RUSTDOC_ARGS="$(cargo metadata --format-version 1 | \ + jq -r ".packages[] | select(.name == \"unsafe-fields\").metadata.docs.rs.\"rustdoc-args\"[]" | tr '\n' ' ')" + export RUSTDOCFLAGS="${{ matrix.toolchain == 'nightly' && '-Z unstable-options --document-hidden-items $METADATA_DOCS_RS_RUSTDOC_ARGS'|| '' }} $RUSTDOCFLAGS" + ./cargo.sh +${{ matrix.toolchain }} doc --document-private-items --package unsafe-fields --all-features + # NEON intrinsics are currently broken on big-endian platforms. [1] This test ensures # that we don't accidentally attempt to compile these intrinsics on such platforms. We # can't use this as part of the build matrix because rustup doesn't support the @@ -594,7 +598,7 @@ jobs: echo "RUSTFLAGS=$RUSTFLAGS" >> $GITHUB_ENV echo "ZC_TOOLCHAIN=$ZC_TOOLCHAIN" >> $GITHUB_ENV - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: key: aarch64_be-unknown-linux-gnu - name: Install stable Rust for use in 'cargo.sh' @@ -681,7 +685,7 @@ jobs: # # TODO(#1595): Debug why this step is still necessary after #1564 and # maybe remove it. - cargo add -p zerocopy-derive 'syn@=2.0.46' &> /dev/null + cargo add -p zerocopy-derive 'syn@=2.0.79' &> /dev/null cargo check --workspace --tests &> /dev/null & cargo metadata &> /dev/null & @@ -738,7 +742,7 @@ jobs: # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks if: failure() runs-on: ubuntu-latest - needs: [build_test, kani,check_be_aarch64 , check_fmt, check_readme, check_versions, generate_cache, check-all-toolchains-tested, check-job-dependencies, run-git-hooks] + needs: [build_test, kani,check_be_aarch64, check_fmt, check_readme, check_versions, generate_cache, check-all-toolchains-tested, check-job-dependencies, run-git-hooks, unsafe_fields] steps: - name: Mark the job as failed run: exit 1 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 6e6f292f78..0c80c45396 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -32,4 +32,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: 'Dependency Review' - uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 + uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5 diff --git a/.github/workflows/roll-pinned-toolchain-versions.yml b/.github/workflows/roll-pinned-toolchain-versions.yml index 90de5927d1..7592de8179 100644 --- a/.github/workflows/roll-pinned-toolchain-versions.yml +++ b/.github/workflows/roll-pinned-toolchain-versions.yml @@ -35,7 +35,7 @@ jobs: fail-fast: false matrix: toolchain: ["stable", "nightly"] - branch: ["main"] + branch: ["main", "v0.8.x"] name: Roll pinned toolchain ${{ matrix.toolchain }} version on ${{ matrix.branch }} steps: - name: Checkout code diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b8fc853a0f..eaaad9f67f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 with: sarif_file: results.sarif diff --git a/Cargo.toml b/Cargo.toml index efc21f3e69..17698bf35b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,17 +12,23 @@ # https://github.com/dtolnay/trybuild/issues/207#issuecomment-131227.594 [workspace] +members = ["unsafe-fields", "zerocopy-derive"] + +[workspace.package] +# Inherited by zerocopy and unsafe-fields. +rust-version = "1.65.0" + [package] edition = "2021" name = "zerocopy" -version = "0.8.5" +version = "0.9.0-alpha.0" authors = ["Joshua Liebow-Feeser "] description = "Zerocopy makes zero-cost memory manipulation effortless. We write \"unsafe\" so you don't have to." categories = ["embedded", "encoding", "no-std::no-alloc", "parsing", "rust-patterns"] keywords = ["cast", "convert", "transmute", "transmutation", "type-punning"] license = "BSD-2-Clause OR Apache-2.0 OR MIT" repository = "https://github.com/google/zerocopy" -rust-version = "1.56.0" +rust-version = { workspace = true } exclude = [".*"] @@ -38,25 +44,10 @@ zerocopy-core-error = "1.81.0" # From 1.78.0, Rust supports the `#[diagnostic::on_unimplemented]` attribute. zerocopy-diagnostic-on-unimplemented = "1.78.0" -# From 1.61.0, Rust supports generic types with trait bounds in `const fn`. -zerocopy-generic-bounds-in-const-fn = "1.61.0" - -# From 1.60.0, Rust supports `cfg(target_has_atomics)`, which allows us to -# detect whether a target supports particular sets of atomics. -zerocopy-target-has-atomics = "1.60.0" - -# When the "simd" feature is enabled, include SIMD types from the -# `core::arch::aarch64` module, which was stabilized in 1.59.0. On earlier Rust -# versions, these types require the "simd-nightly" feature. -zerocopy-aarch64-simd = "1.59.0" - -# Permit panicking in `const fn`s and calling `Vec::try_reserve`. -zerocopy-panic-in-const-and-vec-try-reserve = "1.57.0" - [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. -pinned-stable = "1.81.0" -pinned-nightly = "nightly-2024-10-11" +pinned-stable = "1.82.0" +pinned-nightly = "nightly-2024-10-21" [package.metadata.docs.rs] all-features = true @@ -77,26 +68,26 @@ std = ["alloc"] __internal_use_only_features_that_work_on_stable = ["alloc", "derive", "simd", "std"] [dependencies] -zerocopy-derive = { version = "=0.8.5", path = "zerocopy-derive", optional = true } +zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive", optional = true } # The "associated proc macro pattern" ensures that the versions of zerocopy and # zerocopy-derive remain equal, even if the 'derive' feature isn't used. # See: https://github.com/matklad/macro-dep-test [target.'cfg(any())'.dependencies] -zerocopy-derive = { version = "=0.8.5", path = "zerocopy-derive" } +zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive" } [dev-dependencies] -itertools = "0.11" +itertools = "0.13.0" rand = { version = "0.8.5", default-features = false, features = ["small_rng"] } -rustversion = "1.0" -static_assertions = "1.1" +rustversion = "1.0.17" +static_assertions = "1.1.0" testutil = { path = "testutil" } # Pinned to a specific version so that the version used for local development # and the version used in CI are guaranteed to be the same. Future versions # sometimes change the output format slightly, so a version mismatch can cause # CI test failures. -trybuild = { version = "=1.0.89", features = ["diff"] } +trybuild = { version = "=1.0.90", features = ["diff"] } # In tests, unlike in production, zerocopy-derive is not optional -zerocopy-derive = { version = "=0.8.5", path = "zerocopy-derive" } +zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive" } # TODO(#381) Remove this dependency once we have our own layout gadgets. elain = "0.3.0" diff --git a/README.md b/README.md index 358a4a6a7e..6fa9a240f5 100644 --- a/README.md +++ b/README.md @@ -201,4 +201,4 @@ Zerocopy uses [GitHub Releases]. ## Disclaimer -Disclaimer: Zerocopy is not an officially supported Google product. +Disclaimer: This is not an officially supported Google product. diff --git a/ci/check_readme.sh b/ci/check_readme.sh index 241128d0d0..413f5a866d 100755 --- a/ci/check_readme.sh +++ b/ci/check_readme.sh @@ -16,4 +16,6 @@ set -eo pipefail cargo install -q cargo-readme --version 3.2.0 diff <(cargo -q run --manifest-path tools/Cargo.toml -p generate-readme) README.md >&2 -exit $? + +cd unsafe-fields +diff <(cargo -q run --manifest-path ../tools/Cargo.toml -p generate-readme) README.md >&2 diff --git a/src/byteorder.rs b/src/byteorder.rs index b6b4687c0f..a65cb167d7 100644 --- a/src/byteorder.rs +++ b/src/byteorder.rs @@ -539,33 +539,29 @@ example of how it can be used for parsing UDP packets. } impl $name { - maybe_const_trait_bounded_fn! { - /// Constructs a new value, possibly performing an endianness - /// swap to guarantee that the returned value has endianness - /// `O`. - #[must_use = "has no side effects"] - #[inline(always)] - pub const fn new(n: $native) -> $name { - let bytes = match O::ORDER { - Order::BigEndian => $to_be_fn(n), - Order::LittleEndian => $to_le_fn(n), - }; + /// Constructs a new value, possibly performing an endianness + /// swap to guarantee that the returned value has endianness + /// `O`. + #[must_use = "has no side effects"] + #[inline(always)] + pub const fn new(n: $native) -> $name { + let bytes = match O::ORDER { + Order::BigEndian => $to_be_fn(n), + Order::LittleEndian => $to_le_fn(n), + }; - $name(bytes, PhantomData) - } + $name(bytes, PhantomData) } - maybe_const_trait_bounded_fn! { - /// Returns the value as a primitive type, possibly performing - /// an endianness swap to guarantee that the return value has - /// the endianness of the native platform. - #[must_use = "has no side effects"] - #[inline(always)] - pub const fn get(self) -> $native { - match O::ORDER { - Order::BigEndian => $from_be_fn(self.0), - Order::LittleEndian => $from_le_fn(self.0), - } + /// Returns the value as a primitive type, possibly performing + /// an endianness swap to guarantee that the return value has + /// the endianness of the native platform. + #[must_use = "has no side effects"] + #[inline(always)] + pub const fn get(self) -> $native { + match O::ORDER { + Order::BigEndian => $from_be_fn(self.0), + Order::LittleEndian => $from_le_fn(self.0), } } @@ -971,6 +967,7 @@ module!(network_endian, NetworkEndian, "network-endian"); module!(native_endian, NativeEndian, "native-endian"); #[cfg(any(test, kani))] +#[allow(clippy::missing_const_for_fn)] mod tests { use super::*; @@ -1057,8 +1054,8 @@ mod tests { /// themselves. This method is like `assert_eq!`, but it treats NaN /// values as equal. fn assert_eq_or_nan(self, other: Self) { - let slf = (!self.is_nan()).then(|| self); - let other = (!other.is_nan()).then(|| other); + let slf = (!self.is_nan()).then_some(self); + let other = (!other.is_nan()).then_some(other); assert_eq!(slf, other); } } @@ -1088,8 +1085,8 @@ mod tests { /// themselves. This method is like `assert_eq!`, but it treats NaN /// values as equal. fn assert_eq_or_nan(self, other: Self) { - let slf = (!self.get().is_nan()).then(|| self); - let other = (!other.get().is_nan()).then(|| other); + let slf = (!self.get().is_nan()).then_some(self); + let other = (!other.get().is_nan()).then_some(other); assert_eq!(slf, other); } } @@ -1396,11 +1393,11 @@ mod tests { // For `f32` and `f64`, NaN values are not considered equal to // themselves. We store `Option`/`Option` and store // NaN as `None` so they can still be compared. - let val_or_none = |t: T| (!T::Native::is_nan(t.get())).then(|| t.get()); + let val_or_none = |t: T| (!T::Native::is_nan(t.get())).then_some(t.get()); let t_t_res = val_or_none(t_t_res); let t_n_res = val_or_none(t_n_res); let n_t_res = val_or_none(n_t_res); - let n_n_res = (!T::Native::is_nan(n_n_res)).then(|| n_n_res); + let n_n_res = (!T::Native::is_nan(n_n_res)).then_some(n_n_res); assert_eq!(t_t_res, n_n_res); assert_eq!(t_n_res, n_n_res); assert_eq!(n_t_res, n_n_res); @@ -1418,7 +1415,7 @@ mod tests { // NaN as `None` so they can still be compared. let t_t_res = val_or_none(t_t_res); let t_n_res = val_or_none(t_n_res); - let n_t_res = (!T::Native::is_nan(n_t_res)).then(|| n_t_res); + let n_t_res = (!T::Native::is_nan(n_t_res)).then_some(n_t_res); assert_eq!(t_t_res, n_n_res); assert_eq!(t_n_res, n_n_res); assert_eq!(n_t_res, n_n_res); diff --git a/src/deprecated.rs b/src/deprecated.rs deleted file mode 100644 index 4c5e4981c8..0000000000 --- a/src/deprecated.rs +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2024 The Fuchsia Authors -// -// Licensed under the 2-Clause BSD License , Apache License, Version 2.0 -// , or the MIT -// license , at your option. -// This file may not be copied, modified, or distributed except according to -// those terms. - -//! Deprecated items. These are kept separate so that they don't clutter up -//! other modules. - -use super::*; - -impl Ref -where - B: ByteSlice, - T: KnownLayout + Immutable + ?Sized, -{ - #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_bytes`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new(bytes: B) -> Option> { - Self::from_bytes(bytes).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: KnownLayout + Immutable + ?Sized, -{ - #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_prefix`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_from_prefix(bytes: B) -> Option<(Ref, B)> { - Self::from_prefix(bytes).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: KnownLayout + Immutable + ?Sized, -{ - #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_suffix`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_from_suffix(bytes: B) -> Option<(B, Ref)> { - Self::from_suffix(bytes).ok() - } -} - -impl Ref -where - B: ByteSlice, - T: Unaligned + KnownLayout + Immutable + ?Sized, -{ - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_bytes`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_unaligned(bytes: B) -> Option> { - Self::from_bytes(bytes).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: Unaligned + KnownLayout + Immutable + ?Sized, -{ - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_prefix`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_unaligned_from_prefix(bytes: B) -> Option<(Ref, B)> { - Self::from_prefix(bytes).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: Unaligned + KnownLayout + Immutable + ?Sized, -{ - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_suffix`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, Ref)> { - Self::from_suffix(bytes).ok() - } -} - -impl Ref -where - B: ByteSlice, - T: Immutable, -{ - #[deprecated(since = "0.8.0", note = "`Ref::from_bytes` now supports slices")] - #[doc(hidden)] - #[inline(always)] - pub fn new_slice(bytes: B) -> Option> { - Self::from_bytes(bytes).ok() - } -} - -impl Ref -where - B: ByteSlice, - T: Unaligned + Immutable, -{ - #[deprecated( - since = "0.8.0", - note = "`Ref::from_bytes` now supports slices; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[inline(always)] - pub fn new_slice_unaligned(bytes: B) -> Option> { - Ref::from_bytes(bytes).ok() - } -} - -impl<'a, B, T> Ref -where - B: 'a + IntoByteSlice<'a>, - T: FromBytes + Immutable, -{ - #[deprecated(since = "0.8.0", note = "`Ref::into_ref` now supports slices")] - #[doc(hidden)] - #[inline(always)] - pub fn into_slice(self) -> &'a [T] { - Ref::into_ref(self) - } -} - -impl<'a, B, T> Ref -where - B: 'a + IntoByteSliceMut<'a>, - T: FromBytes + IntoBytes + Immutable, -{ - #[deprecated(since = "0.8.0", note = "`Ref::into_mut` now supports slices")] - #[doc(hidden)] - #[inline(always)] - pub fn into_mut_slice(self) -> &'a mut [T] { - Ref::into_mut(self) - } -} - -impl Ref -where - B: SplitByteSlice, - T: Immutable, -{ - #[deprecated(since = "0.8.0", note = "replaced by `Ref::from_prefix_with_elems`")] - #[must_use = "has no side effects"] - #[doc(hidden)] - #[inline(always)] - pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { - Ref::from_prefix_with_elems(bytes, count).ok() - } - - #[deprecated(since = "0.8.0", note = "replaced by `Ref::from_suffix_with_elems`")] - #[must_use = "has no side effects"] - #[doc(hidden)] - #[inline(always)] - pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { - Ref::from_suffix_with_elems(bytes, count).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: Unaligned + Immutable, -{ - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_prefix_with_elems`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_slice_unaligned_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { - Ref::from_prefix_with_elems(bytes, count).ok() - } - - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_suffix_with_elems`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_slice_unaligned_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { - Ref::from_suffix_with_elems(bytes, count).ok() - } -} diff --git a/src/error.rs b/src/error.rs index e30b6895ce..2380195014 100644 --- a/src/error.rs +++ b/src/error.rs @@ -258,10 +258,10 @@ impl AlignmentError { /// /// The caller must ensure that `Dst`'s alignment requirement is greater /// than one. - pub(crate) unsafe fn new_unchecked(src: Src) -> Self { + pub(crate) const unsafe fn new_unchecked(src: Src) -> Self { // INVARIANT: The caller guarantees that `Dst`'s alignment requirement // is greater than one. - Self { src, dst: SendSyncPhantomData::default() } + Self { src, dst: SendSyncPhantomData::new() } } /// Produces the source underlying the failed conversion. @@ -274,7 +274,7 @@ impl AlignmentError { // INVARIANT: `with_src` doesn't change the type of `Dst`, so the // invariant that `Dst`'s alignment requirement is greater than one is // preserved. - AlignmentError { src: new_src, dst: SendSyncPhantomData::default() } + AlignmentError { src: new_src, dst: SendSyncPhantomData::new() } } /// Maps the source value associated with the conversion error. @@ -299,10 +299,10 @@ impl AlignmentError { /// ``` #[inline] pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> AlignmentError { - AlignmentError { src: f(self.src), dst: SendSyncPhantomData::default() } + AlignmentError { src: f(self.src), dst: SendSyncPhantomData::new() } } - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Alignment(self) } @@ -416,8 +416,8 @@ pub struct SizeError { } impl SizeError { - pub(crate) fn new(src: Src) -> Self { - Self { src, dst: SendSyncPhantomData::default() } + pub(crate) const fn new(src: Src) -> Self { + Self { src, dst: SendSyncPhantomData::new() } } /// Produces the source underlying the failed conversion. @@ -428,7 +428,7 @@ impl SizeError { /// Sets the source value associated with the conversion error. pub(crate) fn with_src(self, new_src: NewSrc) -> SizeError { - SizeError { src: new_src, dst: SendSyncPhantomData::default() } + SizeError { src: new_src, dst: SendSyncPhantomData::new() } } /// Maps the source value associated with the conversion error. @@ -454,16 +454,16 @@ impl SizeError { /// ``` #[inline] pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> SizeError { - SizeError { src: f(self.src), dst: SendSyncPhantomData::default() } + SizeError { src: f(self.src), dst: SendSyncPhantomData::new() } } /// Sets the destination type associated with the conversion error. pub(crate) fn with_dst(self) -> SizeError { - SizeError { src: self.src, dst: SendSyncPhantomData::default() } + SizeError { src: self.src, dst: SendSyncPhantomData::new() } } /// Converts the error into a general [`ConvertError`]. - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Size(self) } @@ -559,8 +559,8 @@ pub struct ValidityError { } impl ValidityError { - pub(crate) fn new(src: Src) -> Self { - Self { src, dst: SendSyncPhantomData::default() } + pub(crate) const fn new(src: Src) -> Self { + Self { src, dst: SendSyncPhantomData::new() } } /// Produces the source underlying the failed conversion. @@ -591,11 +591,11 @@ impl ValidityError { /// ``` #[inline] pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> ValidityError { - ValidityError { src: f(self.src), dst: SendSyncPhantomData::default() } + ValidityError { src: f(self.src), dst: SendSyncPhantomData::new() } } /// Converts the error into a general [`ConvertError`]. - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Validity(self) } @@ -957,6 +957,7 @@ pub type AlignedTryCastError = pub struct AllocError; #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] mod tests { use super::*; diff --git a/src/impls.rs b/src/impls.rs index 678f8fb2e6..0a552d5231 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -180,7 +180,7 @@ safety_comment! { /// /// [4] TODO(#429): Justify this claim. unsafe_impl!(char: TryFromBytes; |candidate: MaybeAligned| { - let candidate = candidate.read_unaligned(); + let candidate = candidate.read_unaligned::(); char::from_u32(candidate).is_some() }); } @@ -290,15 +290,6 @@ safety_comment! { /// because `NonZeroXxx` and `xxx` have the same size. [1] Neither `r` /// nor `t` refer to any `UnsafeCell`s because neither `NonZeroXxx` [2] /// nor `xxx` do. - /// - Since the closure takes a `&xxx` argument, given a `Maybe<'a, - /// NonZeroXxx>` which satisfies the preconditions of - /// `TryFromBytes::::is_bit_valid`, it must be guaranteed - /// that the memory referenced by that `MabyeValid` always contains a - /// valid `xxx`. Since `NonZeroXxx`'s bytes are always initialized [1], - /// `is_bit_valid`'s precondition requires that the same is true of its - /// argument. Since `xxx`'s only bit validity invariant is that its - /// bytes must be initialized, this memory is guaranteed to contain a - /// valid `xxx`. /// - The impl must only return `true` for its argument if the original /// `Maybe` refers to a valid `NonZeroXxx`. The only /// `xxx` which is not also a valid `NonZeroXxx` is 0. [1] @@ -310,18 +301,18 @@ safety_comment! { /// /// [2] `NonZeroXxx` self-evidently does not contain `UnsafeCell`s. This is /// not a proof, but we are accepting this as a known risk per #1358. - unsafe_impl!(NonZeroU8: TryFromBytes; |n: MaybeAligned| NonZeroU8::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI8: TryFromBytes; |n: MaybeAligned| NonZeroI8::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroU16: TryFromBytes; |n: MaybeAligned| NonZeroU16::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI16: TryFromBytes; |n: MaybeAligned| NonZeroI16::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroU32: TryFromBytes; |n: MaybeAligned| NonZeroU32::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI32: TryFromBytes; |n: MaybeAligned| NonZeroI32::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroU64: TryFromBytes; |n: MaybeAligned| NonZeroU64::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI64: TryFromBytes; |n: MaybeAligned| NonZeroI64::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroU128: TryFromBytes; |n: MaybeAligned| NonZeroU128::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI128: TryFromBytes; |n: MaybeAligned| NonZeroI128::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroUsize: TryFromBytes; |n: MaybeAligned| NonZeroUsize::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroIsize: TryFromBytes; |n: MaybeAligned| NonZeroIsize::new(n.read_unaligned()).is_some()); + unsafe_impl!(NonZeroU8: TryFromBytes; |n: MaybeAligned| NonZeroU8::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI8: TryFromBytes; |n: MaybeAligned| NonZeroI8::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroU16: TryFromBytes; |n: MaybeAligned| NonZeroU16::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI16: TryFromBytes; |n: MaybeAligned| NonZeroI16::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroU32: TryFromBytes; |n: MaybeAligned| NonZeroU32::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI32: TryFromBytes; |n: MaybeAligned| NonZeroI32::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroU64: TryFromBytes; |n: MaybeAligned| NonZeroU64::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI64: TryFromBytes; |n: MaybeAligned| NonZeroI64::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroU128: TryFromBytes; |n: MaybeAligned| NonZeroU128::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI128: TryFromBytes; |n: MaybeAligned| NonZeroI128::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroUsize: TryFromBytes; |n: MaybeAligned| NonZeroUsize::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroIsize: TryFromBytes; |n: MaybeAligned| NonZeroIsize::new(n.read_unaligned::()).is_some()); } safety_comment! { /// SAFETY: @@ -441,15 +432,12 @@ safety_comment! { unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...)); } -#[cfg(all( - zerocopy_target_has_atomics, - any( - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr" - ) +#[cfg(any( + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr" ))] mod atomics { use super::*; @@ -660,9 +648,7 @@ unsafe impl TryFromBytes for UnsafeCell { } #[inline] - fn is_bit_valid>( - candidate: Maybe<'_, Self, A>, - ) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { // The only way to implement this function is using an exclusive-aliased // pointer. `UnsafeCell`s cannot be read via shared-aliased pointers // (other than by using `unsafe` code, which we can't use since we can't @@ -933,7 +919,6 @@ mod simd { #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))] powerpc64, powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long ); - #[cfg(zerocopy_aarch64_simd)] simd_arch_mod!( // NOTE(https://github.com/rust-lang/stdarch/issues/1484): NEON intrinsics are currently // broken on big-endian platforms. @@ -956,6 +941,7 @@ mod simd { #[cfg(test)] mod tests { use super::*; + use crate::pointer::invariant; #[test] fn test_impls() { @@ -1138,10 +1124,7 @@ mod tests { pub(super) trait TestIsBitValidShared { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared< - 'ptr, - A: invariant::Aliasing + invariant::AtLeast, - >( + fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &self, candidate: Maybe<'ptr, T, A>, ) -> Option; @@ -1149,10 +1132,7 @@ mod tests { impl TestIsBitValidShared for AutorefWrapper { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared< - 'ptr, - A: invariant::Aliasing + invariant::AtLeast, - >( + fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &self, candidate: Maybe<'ptr, T, A>, ) -> Option { @@ -1242,7 +1222,7 @@ mod tests { #[allow(unused, non_local_definitions)] impl AutorefWrapper<$ty> { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared<'ptr, A: invariant::Aliasing + invariant::AtLeast>( + fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &mut self, candidate: Maybe<'ptr, $ty, A>, ) -> Option { @@ -1882,7 +1862,7 @@ mod tests { vector_signed_long, vector_unsigned_long ); - #[cfg(all(target_arch = "aarch64", zerocopy_aarch64_simd))] + #[cfg(target_arch = "aarch64")] #[rustfmt::skip] test_simd_arch_mod!( aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t, diff --git a/src/layout.rs b/src/layout.rs index 24d8fb6ef3..5aaf102f8a 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -96,7 +96,7 @@ impl DstLayout { /// The minimum possible alignment of a type. const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) { Some(min_align) => min_align, - None => const_unreachable!(), + None => unreachable!(), }; /// The maximum theoretic possible alignment of a type. @@ -107,7 +107,7 @@ impl DstLayout { pub(crate) const THEORETICAL_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << (POINTER_WIDTH_BITS - 1)) { Some(max_align) => max_align, - None => const_unreachable!(), + None => unreachable!(), }; /// The current, documented max alignment of a type \[1\]. @@ -119,7 +119,7 @@ impl DstLayout { #[cfg(not(kani))] pub(crate) const CURRENT_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << 28) { Some(max_align) => max_align, - None => const_unreachable!(), + None => unreachable!(), }; /// Constructs a `DstLayout` for a zero-sized type with `repr_align` @@ -142,7 +142,7 @@ impl DstLayout { None => Self::MIN_ALIGN, }; - const_assert!(align.get().is_power_of_two()); + assert!(align.get().is_power_of_two()); DstLayout { align, size_info: SizeInfo::Sized { size: 0 } } } @@ -162,7 +162,7 @@ impl DstLayout { DstLayout { align: match NonZeroUsize::new(mem::align_of::()) { Some(align) => align, - None => const_unreachable!(), + None => unreachable!(), }, size_info: SizeInfo::Sized { size: mem::size_of::() }, } @@ -185,7 +185,7 @@ impl DstLayout { DstLayout { align: match NonZeroUsize::new(mem::align_of::()) { Some(align) => align, - None => const_unreachable!(), + None => unreachable!(), }, size_info: SizeInfo::SliceDst(TrailingSliceLayout { offset: 0, @@ -232,17 +232,17 @@ impl DstLayout { None => Self::THEORETICAL_MAX_ALIGN, }; - const_assert!(max_align.get().is_power_of_two()); + assert!(max_align.get().is_power_of_two()); // We use Kani to prove that this method is robust to future increases // in Rust's maximum allowed alignment. However, if such a change ever // actually occurs, we'd like to be notified via assertion failures. #[cfg(not(kani))] { - const_debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); - const_debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); if let Some(repr_packed) = repr_packed { - const_debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); } } @@ -263,7 +263,7 @@ impl DstLayout { let size_info = match self.size_info { // If the layout is already a DST, we panic; DSTs cannot be extended // with additional fields. - SizeInfo::SliceDst(..) => const_panic!("Cannot extend a DST with additional fields."), + SizeInfo::SliceDst(..) => panic!("Cannot extend a DST with additional fields."), SizeInfo::Sized { size: preceding_size } => { // Compute the minimum amount of inter-field padding needed to @@ -284,7 +284,7 @@ impl DstLayout { // exceeding `isize::MAX`). let offset = match preceding_size.checked_add(padding) { Some(offset) => offset, - None => const_panic!("Adding padding to `self`'s size overflows `usize`."), + None => panic!("Adding padding to `self`'s size overflows `usize`."), }; match field.size_info { @@ -302,7 +302,7 @@ impl DstLayout { // `usize::MAX`). let size = match offset.checked_add(field_size) { Some(size) => size, - None => const_panic!("`field` cannot be appended without the total size overflowing `usize`"), + None => panic!("`field` cannot be appended without the total size overflowing `usize`"), }; SizeInfo::Sized { size } } @@ -324,7 +324,7 @@ impl DstLayout { // `usize::MAX`). let offset = match offset.checked_add(trailing_offset) { Some(offset) => offset, - None => const_panic!("`field` cannot be appended without the total size overflowing `usize`"), + None => panic!("`field` cannot be appended without the total size overflowing `usize`"), }; SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) } @@ -372,7 +372,7 @@ impl DstLayout { let padding = padding_needed_for(unpadded_size, self.align); let size = match unpadded_size.checked_add(padding) { Some(size) => size, - None => const_panic!("Adding padding caused size to overflow `usize`."), + None => panic!("Adding padding caused size to overflow `usize`."), }; SizeInfo::Sized { size } } @@ -458,9 +458,9 @@ impl DstLayout { cast_type: CastType, ) -> Result<(usize, usize), MetadataCastError> { // `debug_assert!`, but with `#[allow(clippy::arithmetic_side_effects)]`. - macro_rules! __const_debug_assert { + macro_rules! __debug_assert { ($e:expr $(, $msg:expr)?) => { - const_debug_assert!({ + debug_assert!({ #[allow(clippy::arithmetic_side_effects)] let e = $e; e @@ -474,19 +474,12 @@ impl DstLayout { // invalid type) instead of allowing this panic to be hidden if the cast // would have failed anyway for runtime reasons (such as a too-small // memory region). - // - // TODO(#67): Once our MSRV is 1.65, use let-else: - // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements - let size_info = match self.size_info.try_to_nonzero_elem_size() { - Some(size_info) => size_info, - None => const_panic!("attempted to cast to slice type with zero-sized element"), + let Some(size_info) = self.size_info.try_to_nonzero_elem_size() else { + panic!("attempted to cast to slice type with zero-sized element"); }; // Precondition - __const_debug_assert!( - addr.checked_add(bytes_len).is_some(), - "`addr` + `bytes_len` > usize::MAX" - ); + __debug_assert!(addr.checked_add(bytes_len).is_some(), "`addr` + `bytes_len` > usize::MAX"); // Alignment checks go in their own block to avoid introducing variables // into the top-level scope. @@ -534,13 +527,9 @@ impl DstLayout { util::round_down_to_next_multiple_of_alignment(bytes_len, self.align); // Calculate the maximum number of bytes that could be consumed // by the trailing slice. - // - // TODO(#67): Once our MSRV is 1.65, use let-else: - // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements - let max_slice_and_padding_bytes = match max_total_bytes.checked_sub(offset) { - Some(max) => max, + let Some(max_slice_and_padding_bytes) = max_total_bytes.checked_sub(offset) else { // `bytes_len` too small even for 0 trailing slice elements. - None => return Err(MetadataCastError::Size), + return Err(MetadataCastError::Size); }; // Calculate the number of elements that fit in @@ -582,7 +571,7 @@ impl DstLayout { } }; - __const_debug_assert!(self_bytes <= bytes_len); + __debug_assert!(self_bytes <= bytes_len); let split_at = match cast_type { CastType::Prefix => self_bytes, @@ -599,11 +588,6 @@ impl DstLayout { } } -// TODO(#67): For some reason, on our MSRV toolchain, this `allow` isn't -// enforced despite having `#![allow(unknown_lints)]` at the crate root, but -// putting it here works. Once our MSRV is high enough that this bug has been -// fixed, remove this `allow`. -#[allow(unknown_lints)] #[cfg(test)] mod tests { use super::*; @@ -842,7 +826,7 @@ mod tests { /// call to `validate_cast_and_convert_metadata` panics with the given /// panic message or, if the current Rust toolchain version is too /// early to support panicking in `const fn`s, panics with *some* - /// message. In the latter case, the `const_panic!` macro is used, + /// message. In the latter case, the `panic!` macro is used, /// which emits code which causes a non-panicking error at const eval /// time, but which does panic when invoked at runtime. Thus, it is /// merely difficult to predict the *value* of this panic. We deem @@ -880,7 +864,7 @@ mod tests { layout(size_info, align).validate_cast_and_convert_metadata(addr, bytes_len, cast_type) }).map_err(|d| { let msg = d.downcast::<&'static str>().ok().map(|s| *s.as_ref()); - assert!(msg.is_some() || cfg!(not(zerocopy_panic_in_const_and_vec_try_reserve)), "non-string panic messages are not permitted when `--cfg zerocopy_panic_in_const_and_vec_try_reserve` is set"); + assert!(msg.is_some(), "non-string panic messages are not permitted"); msg }); std::panic::set_hook(previous_hook); diff --git a/src/lib.rs b/src/lib.rs index 296836425a..ab27e375b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -203,7 +203,7 @@ // `unknown_lints` is `warn` by default and we deny warnings in CI, so without // this attribute, any unknown lint would cause a CI failure when testing with // our MSRV. -#![allow(unknown_lints, unreachable_patterns)] +#![allow(unknown_lints, non_local_definitions, unreachable_patterns)] #![deny(renamed_and_removed_lints)] #![deny( anonymous_parameters, @@ -248,6 +248,7 @@ clippy::double_must_use, clippy::get_unwrap, clippy::indexing_slicing, + clippy::missing_const_for_fn, clippy::missing_inline_in_public_items, clippy::missing_safety_doc, clippy::must_use_candidate, @@ -306,7 +307,7 @@ #![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr( __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, - feature(layout_for_ptr, strict_provenance, coverage_attribute) + feature(layout_for_ptr, strict_provenance, coverage_attribute, marker_trait_attr) )] // This is a hack to allow zerocopy-derive derives to work in this crate. They @@ -321,7 +322,6 @@ pub mod util; pub mod byte_slice; pub mod byteorder; -mod deprecated; // This module is `pub` so that zerocopy's error types and error handling // documentation is grouped together in a cohesive module. In practice, we // expect most users to use the re-export of `error`'s items to avoid identifier @@ -359,7 +359,7 @@ use core::{ slice, }; -use crate::pointer::{invariant, BecauseExclusive, BecauseImmutable}; +use crate::pointer::invariant::{self, BecauseExclusive}; #[cfg(any(feature = "alloc", test))] extern crate alloc; @@ -371,7 +371,7 @@ use core::alloc::Layout; // Used by `TryFromBytes::is_bit_valid`. #[doc(hidden)] -pub use crate::pointer::{Maybe, MaybeAligned, Ptr}; +pub use crate::pointer::{invariant::BecauseImmutable, Maybe, MaybeAligned, Ptr}; // Used by `KnownLayout`. #[doc(hidden)] pub use crate::layout::*; @@ -394,27 +394,6 @@ const _: () = { _WARNING }; -// These exist so that code which was written against the old names will get -// less confusing error messages when they upgrade to a more recent version of -// zerocopy. On our MSRV toolchain, the error messages read, for example: -// -// error[E0603]: trait `FromZeroes` is private -// --> examples/deprecated.rs:1:15 -// | -// 1 | use zerocopy::FromZeroes; -// | ^^^^^^^^^^ private trait -// | -// note: the trait `FromZeroes` is defined here -// --> /Users/josh/workspace/zerocopy/src/lib.rs:1845:5 -// | -// 1845 | use FromZeros as FromZeroes; -// | ^^^^^^^^^^^^^^^^^^^^^^^ -// -// The "note" provides enough context to make it easy to figure out how to fix -// the error. -#[allow(unused)] -use {FromZeros as FromZeroes, IntoBytes as AsBytes, Ref as LayoutVerified}; - /// Implements [`KnownLayout`]. /// /// This derive analyzes various aspects of a type's layout that are needed for @@ -722,6 +701,14 @@ pub unsafe trait KnownLayout { /// The type of metadata stored in a pointer to `Self`. /// /// This is `()` for sized types and `usize` for slice DSTs. + /// + /// # Safety + /// + /// Callers may assume for soundness that one of the following holds: + /// - `Self::LAYOUT.size_info` is a `SizeInfo::Sized` and + /// `Self::PointerMetadata = ()` + /// - `Self::LAYOUT.size_info` is a `SizeInfo::SliceDst` and + /// `Self::PointerMetadata = usize` type PointerMetadata: PointerMetadata; /// The layout of `Self`. @@ -784,7 +771,7 @@ pub unsafe trait KnownLayout { /// The metadata associated with a [`KnownLayout`] type. #[doc(hidden)] -pub trait PointerMetadata: Copy + Eq + Debug { +pub trait PointerMetadata: Copy + Eq + Debug + IntoBytes + Immutable { /// Constructs a `Self` from an element count. /// /// If `Self = ()`, this returns `()`. If `Self = usize`, this returns @@ -1341,9 +1328,7 @@ pub unsafe trait TryFromBytes { /// [`UnsafeCell`]: core::cell::UnsafeCell /// [`Shared`]: invariant::Shared #[doc(hidden)] - fn is_bit_valid>( - candidate: Maybe<'_, Self, A>, - ) -> bool; + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool; /// Attempts to interpret the given `source` as a `&Self`. /// @@ -1983,7 +1968,7 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &[85, 85][..]; + /// let src = 0xCAFEu16.as_bytes(); /// let zsty = ZSTy::try_ref_from_bytes_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2090,7 +2075,7 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &[85, 85][..]; + /// let src = 0xCAFEu16.as_bytes(); /// let (zsty, _) = ZSTy::try_ref_from_prefix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2179,7 +2164,7 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &[85, 85][..]; + /// let src = 0xCAFEu16.as_bytes(); /// let (_, zsty) = ZSTy::try_ref_from_suffix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2269,7 +2254,8 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &mut [85, 85][..]; + /// let mut src = 0xCAFEu16; + /// let src = src.as_mut_bytes(); /// let zsty = ZSTy::try_mut_from_bytes_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2381,7 +2367,8 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &mut [85, 85][..]; + /// let mut src = 0xCAFEu16; + /// let src = src.as_mut_bytes(); /// let (zsty, _) = ZSTy::try_mut_from_prefix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2475,7 +2462,8 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &mut [85, 85][..]; + /// let mut src = 0xCAFEu16; + /// let src = src.as_mut_bytes(); /// let (_, zsty) = ZSTy::try_mut_from_suffix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -3030,17 +3018,6 @@ pub unsafe trait FromZeros: TryFromBytes { }; let align = Self::LAYOUT.align.get(); - // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a - // bug in which sufficiently-large allocations (those which, when - // rounded up to the alignment, overflow `isize`) are not rejected, - // which can cause undefined behavior. See #64 for details. - // - // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion. - #[allow(clippy::as_conversions)] - let max_alloc = (isize::MAX as usize).saturating_sub(align); - if size > max_alloc { - return Err(AllocError); - } // TODO(https://github.com/rust-lang/rust/issues/55724): Use // `Layout::repeat` once it's stabilized. @@ -3055,7 +3032,6 @@ pub unsafe trait FromZeros: TryFromBytes { None => return Err(AllocError), } } else { - let align = Self::LAYOUT.align.get(); // We use `transmute` instead of an `as` cast since Miri (with // strict provenance enabled) notices and complains that an `as` // cast creates a pointer with no provenance. Miri isn't smart @@ -3095,19 +3071,6 @@ pub unsafe trait FromZeros: TryFromBytes { Ok(unsafe { Box::from_raw(ptr.as_ptr()) }) } - #[deprecated(since = "0.8.0", note = "renamed to `FromZeros::new_box_zeroed_with_elems`")] - #[doc(hidden)] - #[cfg(feature = "alloc")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] - #[must_use = "has no side effects (other than allocation)"] - #[inline(always)] - fn new_box_slice_zeroed(len: usize) -> Result, AllocError> - where - Self: Sized, - { - <[Self]>::new_box_zeroed_with_elems(len) - } - /// Creates a `Vec` from zeroed bytes. /// /// This function is useful for allocating large values of `Vec`s and @@ -3141,7 +3104,6 @@ pub unsafe trait FromZeros: TryFromBytes { /// Extends a `Vec` by pushing `additional` new items onto the end of /// the vector. The new items are initialized with zeros. - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[inline(always)] @@ -3160,7 +3122,6 @@ pub unsafe trait FromZeros: TryFromBytes { /// # Panics /// /// Panics if `position > v.len()`. - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[inline] @@ -4181,8 +4142,8 @@ pub unsafe trait FromBytes: FromZeros { /// ``` /// /// Since an explicit `count` is provided, this method supports types with - /// zero-sized trailing slice elements. Methods such as [`mut_from`] which - /// do not take an explicit count do not support such types. + /// zero-sized trailing slice elements. Methods such as [`mut_from_bytes`] + /// which do not take an explicit count do not support such types. /// /// ``` /// use zerocopy::*; @@ -4200,7 +4161,7 @@ pub unsafe trait FromBytes: FromZeros { /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// - /// [`mut_from`]: FromBytes::mut_from + /// [`mut_from_bytes`]: FromBytes::mut_from_bytes #[must_use = "has no side effects"] #[inline] fn mut_from_bytes_with_elems( @@ -4521,105 +4482,6 @@ pub unsafe trait FromBytes: FromZeros { Err(CastError::Validity(i)) => match i {}, } } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_bytes`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn ref_from(source: &[u8]) -> Option<&Self> - where - Self: KnownLayout + Immutable, - { - Self::ref_from_bytes(source).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_bytes`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn mut_from(source: &mut [u8]) -> Option<&mut Self> - where - Self: KnownLayout + IntoBytes, - { - Self::mut_from_bytes(source).ok() - } - - #[deprecated(since = "0.8.0", note = "`FromBytes::ref_from_bytes` now supports slices")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn slice_from(source: &[u8]) -> Option<&[Self]> - where - Self: Sized + Immutable, - { - <[Self]>::ref_from_bytes(source).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_prefix_with_elems`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn slice_from_prefix(source: &[u8], count: usize) -> Option<(&[Self], &[u8])> - where - Self: Sized + Immutable, - { - <[Self]>::ref_from_prefix_with_elems(source, count).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_suffix_with_elems`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn slice_from_suffix(source: &[u8], count: usize) -> Option<(&[u8], &[Self])> - where - Self: Sized + Immutable, - { - <[Self]>::ref_from_suffix_with_elems(source, count).ok() - } - - #[deprecated(since = "0.8.0", note = "`FromBytes::mut_from_bytes` now supports slices")] - #[must_use = "has no side effects"] - #[doc(hidden)] - #[inline(always)] - fn mut_slice_from(source: &mut [u8]) -> Option<&mut [Self]> - where - Self: Sized + IntoBytes, - { - <[Self]>::mut_from_bytes(source).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_prefix_with_elems`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn mut_slice_from_prefix(source: &mut [u8], count: usize) -> Option<(&mut [Self], &mut [u8])> - where - Self: Sized + IntoBytes, - { - <[Self]>::mut_from_prefix_with_elems(source, count).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_suffix_with_elems`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn mut_slice_from_suffix(source: &mut [u8], count: usize) -> Option<(&mut [u8], &mut [Self])> - where - Self: Sized + IntoBytes, - { - <[Self]>::mut_from_suffix_with_elems(source, count).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::read_from_bytes`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn read_from(source: &[u8]) -> Option - where - Self: Sized, - { - Self::read_from_bytes(source).ok() - } } /// Interprets the given affix of the given bytes as a `&Self`. @@ -5206,16 +5068,6 @@ pub unsafe trait IntoBytes { } Ok(()) } - - #[deprecated(since = "0.8.0", note = "`IntoBytes::as_bytes_mut` was renamed to `as_mut_bytes`")] - #[doc(hidden)] - #[inline] - fn as_bytes_mut(&mut self) -> &mut [u8] - where - Self: FromBytes, - { - self.as_mut_bytes() - } } /// Analyzes whether a type is [`Unaligned`]. @@ -5360,51 +5212,12 @@ pub unsafe trait Unaligned { Self: Sized; } -#[cfg(feature = "alloc")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -#[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] -mod alloc_support { - use super::*; - - /// Extends a `Vec` by pushing `additional` new items onto the end of the - /// vector. The new items are initialized with zeros. - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - #[doc(hidden)] - #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] - #[inline(always)] - pub fn extend_vec_zeroed( - v: &mut Vec, - additional: usize, - ) -> Result<(), AllocError> { - ::extend_vec_zeroed(v, additional) - } - - /// Inserts `additional` new items into `Vec` at `position`. The new - /// items are initialized with zeros. - /// - /// # Panics - /// - /// Panics if `position > v.len()`. - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - #[doc(hidden)] - #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] - #[inline(always)] - pub fn insert_vec_zeroed( - v: &mut Vec, - position: usize, - additional: usize, - ) -> Result<(), AllocError> { - ::insert_vec_zeroed(v, position, additional) - } -} - -#[cfg(feature = "alloc")] -#[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] -#[doc(hidden)] -pub use alloc_support::*; - #[cfg(test)] -#[allow(clippy::assertions_on_result_states, clippy::unreadable_literal)] +#[allow( + clippy::assertions_on_result_states, + clippy::unreadable_literal, + clippy::missing_const_for_fn +)] mod tests { use static_assertions::assert_impl_all; @@ -6262,7 +6075,6 @@ mod tests { mod alloc { use super::*; - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[test] fn test_extend_vec_zeroed() { // Test extending when there is an existing allocation. @@ -6280,7 +6092,6 @@ mod tests { drop(v); } - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[test] fn test_extend_vec_zeroed_zst() { // Test extending when there is an existing (fake) allocation. @@ -6297,7 +6108,6 @@ mod tests { drop(v); } - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[test] fn test_insert_vec_zeroed() { // Insert at start (no existing allocation). @@ -6329,7 +6139,6 @@ mod tests { drop(v); } - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[test] fn test_insert_vec_zeroed_zst() { // Insert at start (no existing fake allocation). diff --git a/src/pointer/aliasing_safety.rs b/src/pointer/aliasing_safety.rs deleted file mode 100644 index 7308cf5529..0000000000 --- a/src/pointer/aliasing_safety.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2024 The Fuchsia Authors -// -// Licensed under a BSD-style license , Apache License, Version 2.0 -// , or the MIT -// license , at your option. -// This file may not be copied, modified, or distributed except according to -// those terms. - -//! Machinery for statically proving the "aliasing-safety" of a `Ptr`. - -use crate::{invariant, Immutable}; - -/// Pointer conversions which do not violate aliasing. -/// -/// `U: AliasingSafe` implies that a pointer conversion from `T` to `U` -/// does not violate the aliasing invariant, `A`. This can be because `A` is -/// [`Exclusive`] or because neither `T` nor `U` permit interior mutability. -/// -/// # Safety -/// -/// `U: AliasingSafe` if either of the following conditions holds: -/// - `A` is [`Exclusive`] -/// - `T` and `U` both implement [`Immutable`] -/// -/// [`Exclusive`]: crate::pointer::invariant::Exclusive -#[doc(hidden)] -pub unsafe trait AliasingSafe {} - -/// Used to prevent user implementations of `AliasingSafeReason`. -mod sealed { - pub trait Sealed {} - - impl Sealed for super::BecauseExclusive {} - impl Sealed for super::BecauseImmutable {} - impl Sealed for (S,) {} -} - -#[doc(hidden)] -pub trait AliasingSafeReason: sealed::Sealed {} -impl AliasingSafeReason for (R,) {} - -/// The conversion is safe because only one live `Ptr` or reference may exist to -/// the referent bytes at a time. -#[derive(Copy, Clone, Debug)] -#[doc(hidden)] -pub enum BecauseExclusive {} -impl AliasingSafeReason for BecauseExclusive {} - -/// The conversion is safe because no live `Ptr`s or references permit mutation. -#[derive(Copy, Clone, Debug)] -#[doc(hidden)] -pub enum BecauseImmutable {} -impl AliasingSafeReason for BecauseImmutable {} - -/// SAFETY: `T: AliasingSafe` because for all -/// `Ptr<'a, T, I>` such that `I::Aliasing = Exclusive`, there cannot exist -/// other live references to the memory referenced by `Ptr`. -unsafe impl AliasingSafe for U {} - -/// SAFETY: `U: AliasingSafe` because for all `Ptr<'a, T, -/// I>` and `Ptr<'a, U, I>` such that `I::Aliasing = A`, all live references and -/// live `Ptr`s agree, by invariant on `Immutable`, that the referenced bytes -/// contain no `UnsafeCell`s, and thus do not permit mutation except via -/// exclusive aliasing. -unsafe impl AliasingSafe for U -where - A: invariant::Aliasing, - T: Immutable, - U: Immutable, -{ -} - -/// This ensures that `U: AliasingSafe` implies `T: AliasingSafe` in -/// a manner legible to rustc, which in turn means we can write simpler bounds in -/// some places. -/// -/// SAFETY: Per `U: AliasingSafe`, either: -/// - `A` is `Exclusive` -/// - `T` and `U` both implement `Immutable` -/// -/// Neither property depends on which of `T` and `U` are in the `Self` position -/// vs the first type parameter position. -unsafe impl AliasingSafe for T -where - A: invariant::Aliasing, - R: AliasingSafeReason, - U: AliasingSafe, -{ -} diff --git a/src/pointer/inner.rs b/src/pointer/inner.rs new file mode 100644 index 0000000000..4534da75c1 --- /dev/null +++ b/src/pointer/inner.rs @@ -0,0 +1,542 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use core::{marker::PhantomData, ops::Range, ptr::NonNull}; + +#[allow(unused_imports)] +use crate::util::polyfills::NumExt as _; +use crate::{ + layout::{CastType, DstLayout, MetadataCastError}, + util::AsAddress, + AlignmentError, CastError, KnownLayout, PointerMetadata, SizeError, +}; + +pub(crate) use _def::PtrInner; + +mod _def { + use super::*; + /// The inner pointer stored inside a [`Ptr`][crate::Ptr]. + /// + /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. + /// + /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html + pub(crate) struct PtrInner<'a, T> + where + T: ?Sized, + { + /// # Invariants + /// + /// 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from + /// some valid Rust allocation, `A`. + /// 1. If `ptr`'s referent is not zero sized, then `ptr` has valid + /// provenance for `A`. + /// 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a + /// byte range which is entirely contained in `A`. + /// 3. `ptr` addresses a byte range whose length fits in an `isize`. + /// 4. `ptr` addresses a byte range which does not wrap around the + /// address space. + /// 5. If `ptr`'s referent is not zero sized,`A` is guaranteed to live + /// for at least `'a`. + // SAFETY: `NonNull` is covariant over `T` [1]. + // + // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html + ptr: NonNull, + // SAFETY: `&'a T` is covariant over `'a` [1]. + // + // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance + _marker: PhantomData<&'a T>, + } + + impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {} + impl<'a, T: 'a + ?Sized> Clone for PtrInner<'a, T> { + fn clone(&self) -> PtrInner<'a, T> { + // SAFETY: None of the invariants on `ptr` are affected by having + // multiple copies of a `PtrInner`. + *self + } + } + + impl<'a, T: 'a + ?Sized> PtrInner<'a, T> { + /// Constructs a `Ptr` from a [`NonNull`]. + /// + /// # Safety + /// + /// The caller promises that: + /// + /// 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from + /// some valid Rust allocation, `A`. + /// 1. If `ptr`'s referent is not zero sized, then `ptr` has valid + /// provenance for `A`. + /// 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a + /// byte range which is entirely contained in `A`. + /// 3. `ptr` addresses a byte range whose length fits in an `isize`. + /// 4. `ptr` addresses a byte range which does not wrap around the + /// address space. + /// 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to + /// live for at least `'a`. + pub(crate) const unsafe fn new(ptr: NonNull) -> PtrInner<'a, T> { + // SAFETY: The caller has promised to satisfy all safety invariants + // of `PtrInner`. + Self { ptr, _marker: PhantomData } + } + + /// Converts this `PtrInner` to a [`NonNull`]. + /// + /// Note that this method does not consume `self`. The caller should + /// watch out for `unsafe` code which uses the returned `NonNull` in a + /// way that violates the safety invariants of `self`. + pub(crate) const fn as_non_null(&self) -> NonNull { + self.ptr + } + } +} + +impl<'a, T: ?Sized> PtrInner<'a, T> { + /// Constructs a `PtrInner` from a reference. + #[inline] + pub(crate) fn from_ref(ptr: &'a T) -> Self { + let ptr = NonNull::from(ptr); + // SAFETY: + // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a T`, is derived from some valid Rust allocation, `A`. + // 1. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a T`, has valid provenance for `A`. + // 2. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a T`, addresses a byte range which is entirely contained in + // `A`. + // 3. `ptr`, by invariant on `&'a T`, addresses a byte range whose + // length fits in an `isize`. + // 4. `ptr`, by invariant on `&'a T`, addresses a byte range which does + // not wrap around the address space. + // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant on + // `&'a T`, is guaranteed to live for at least `'a`. + unsafe { Self::new(ptr) } + } + + /// Constructs a `PtrInner` from a mutable reference. + #[inline] + pub(crate) fn from_mut(ptr: &'a mut T) -> Self { + let ptr = NonNull::from(ptr); + // SAFETY: + // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a mut T`, is derived from some valid Rust allocation, `A`. + // 1. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a mut T`, has valid provenance for `A`. + // 2. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a mut T`, addresses a byte range which is entirely contained in + // `A`. + // 3. `ptr`, by invariant on `&'a mut T`, addresses a byte range whose + // length fits in an `isize`. + // 4. `ptr`, by invariant on `&'a mut T`, addresses a byte range which + // does not wrap around the address space. + // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant on + // `&'a mut T`, is guaranteed to live for at least `'a`. + unsafe { Self::new(ptr) } + } +} + +#[allow(clippy::needless_lifetimes)] +impl<'a, T> PtrInner<'a, [T]> { + /// Creates a pointer which addresses the given `range` of self. + /// + /// # Safety + /// + /// `range` is a valid range (`start <= end`) and `end <= self.len()`. + pub(crate) const unsafe fn slice_unchecked(self, range: Range) -> Self { + let base = self.as_non_null().cast::().as_ptr(); + + // SAFETY: The caller promises that `start <= end <= self.len()`. By + // invariant, if `self`'s referent is not zero-sized, then `self` refers + // to a byte range which is contained within a single allocation, which + // is no more than `isize::MAX` bytes long, and which does not wrap + // around the address space. Thus, this pointer arithmetic remains + // in-bounds of the same allocation, and does not wrap around the + // address space. The offset (in bytes) does not overflow `isize`. + // + // If `self`'s referent is zero-sized, then these conditions are + // trivially satisfied. + let base = unsafe { base.add(range.start) }; + + // SAFETY: The caller promises that `start <= end`, and so this will not + // underflow. + #[allow(unstable_name_collisions, clippy::incompatible_msrv)] + let len = unsafe { range.end.unchecked_sub(range.start) }; + + let ptr = core::ptr::slice_from_raw_parts_mut(base, len); + + // SAFETY: By invariant, `self`'s address is non-null and its range does + // not wrap around the address space. Since, by the preceding lemma, + // `ptr` addresses a range within that addressed by `self`, `ptr` is + // non-null. + let ptr = unsafe { NonNull::new_unchecked(ptr) }; + + // SAFETY: + // + // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`, + // and has the same provenance. Proof: The caller guarantees + // that `start <= end <= self.len()`. Thus, `base` is in-bounds of + // `self`, and `base + (end - start)` is also in-bounds of self. + // Finally, `ptr` is constructed using provenance-preserving + // operations. + // + // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not + // zero sized, then `ptr` is derived from some valid Rust allocation, + // `A`. + // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not + // zero sized, then `ptr` has valid provenance for `A`. + // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not + // zero sized, then `ptr` addresses a byte range which is entirely + // contained in `A`. + // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte + // range whose length fits in an `isize`. + // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte + // range which does not wrap around the address space. + // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not + // zero sized, then `A` is guaranteed to live for at least `'a`. + unsafe { PtrInner::new(ptr) } + } + + /// Splits the slice in two. + /// + /// # Safety + /// + /// The caller promises that `l_len <= self.len()`. + /// + /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed + /// that `left` and `right` are contiguous and non-overlapping. + pub(crate) const unsafe fn split_at(self, l_len: usize) -> (Self, Self) { + // SAFETY: The caller promises that `l_len <= self.len()`. + // Trivially, `0 <= l_len`. + let left = unsafe { self.slice_unchecked(0..l_len) }; + + // SAFETY: The caller promises that `l_len <= self.len() = + // slf.len()`. Trivially, `slf.len() <= slf.len()`. + let right = unsafe { self.slice_unchecked(l_len..self.len()) }; + + // SAFETY: `left` and `right` are non-overlapping. Proof: `left` is + // constructed from `slf` with `l_len` as its (exclusive) upper + // bound, while `right` is constructed from `slf` with `l_len` as + // its (inclusive) lower bound. Thus, no index is a member of both + // ranges. + (left, right) + } + + /// Iteratively projects the elements `PtrInner` from `PtrInner<[T]>`. + pub(crate) fn iter(&self) -> impl Iterator> { + // TODO(#429): Once `NonNull::cast` documents that it preserves + // provenance, cite those docs. + let base = self.as_non_null().cast::().as_ptr(); + (0..self.len()).map(move |i| { + // TODO(https://github.com/rust-lang/rust/issues/74265): Use + // `NonNull::get_unchecked_mut`. + + // SAFETY: If the following conditions are not satisfied + // `pointer::cast` may induce Undefined Behavior [1]: + // + // > - The computed offset, `count * size_of::()` bytes, must not + // > overflow `isize``. + // > - If the computed offset is non-zero, then `self` must be + // > derived from a pointer to some allocated object, and the + // > entire memory range between `self` and the result must be in + // > bounds of that allocated object. In particular, this range + // > must not “wrap around” the edge of the address space. + // + // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add + // + // We satisfy both of these conditions here: + // - By invariant on `Ptr`, `self` addresses a byte range whose + // length fits in an `isize`. Since `elem` is contained in `self`, + // the computed offset of `elem` must fit within `isize.` + // - If the computed offset is non-zero, then this means that the + // referent is not zero-sized. In this case, `base` points to an + // allocated object (by invariant on `self`). Thus: + // - By contract, `self.len()` accurately reflects the number of + // elements in the slice. `i` is in bounds of `c.len()` by + // construction, and so the result of this addition cannot + // overflow past the end of the allocation referred to by `c`. + // - By invariant on `Ptr`, `self` addresses a byte range which + // does not wrap around the address space. Since `elem` is + // contained in `self`, the computed offset of `elem` must wrap + // around the address space. + // + // TODO(#429): Once `pointer::add` documents that it preserves + // provenance, cite those docs. + let elem = unsafe { base.add(i) }; + + // SAFETY: + // - `elem` must not be null. `base` is constructed from a + // `NonNull` pointer, and the addition that produces `elem` must + // not overflow or wrap around, so `elem >= base > 0`. + // + // TODO(#429): Once `NonNull::new_unchecked` documents that it + // preserves provenance, cite those docs. + let elem = unsafe { NonNull::new_unchecked(elem) }; + + // SAFETY: The safety invariants of `Ptr::new` (see definition) are + // satisfied: + // 0. If `elem`'s referent is not zero sized, then `elem` is derived + // from a valid Rust allocation, because `self` is derived from a + // valid Rust allocation, by invariant on `Ptr`. + // 1. If `elem`'s referent is not zero sized, then `elem` has valid + // provenance for `self`, because it derived from `self` using a + // series of provenance-preserving operations. + // 2. If `elem`'s referent is not zero sized, then `elem` is + // entirely contained in the allocation of `self` (see above). + // 3. `elem` addresses a byte range whose length fits in an `isize` + // (see above). + // 4. `elem` addresses a byte range which does not wrap around the + // address space (see above). + // 5. If `elem`'s referent is not zero sized, then the allocation of + // `elem` is guaranteed to live for at least `'a`, because `elem` + // is entirely contained in `self`, which lives for at least `'a` + // by invariant on `Ptr`. + unsafe { PtrInner::new(elem) } + }) + } + + /// The number of slice elements in the object referenced by `self`. + /// + /// # Safety + /// + /// Unsafe code my rely on `len` satisfying the above contract. + pub(crate) const fn len(&self) -> usize { + self.trailing_slice_len() + } +} + +#[allow(clippy::needless_lifetimes)] +impl<'a, T> PtrInner<'a, T> +where + T: ?Sized + KnownLayout, +{ + /// The number of trailing slice elements in the object referenced by + /// `self`. + /// + /// # Safety + /// + /// Unsafe code my rely on `trailing_slice_len` satisfying the above + /// contract. + pub(super) fn trailing_slice_len(&self) -> usize { + T::pointer_to_metadata(self.as_non_null().as_ptr()) + } +} + +impl<'a, T, const N: usize> PtrInner<'a, [T; N]> { + /// Casts this pointer-to-array into a slice. + /// + /// # Safety + /// + /// Callers may assume that the returned `PtrInner` references the same + /// address and length as `self`. + #[allow(clippy::wrong_self_convention)] + pub(crate) fn as_slice(self) -> PtrInner<'a, [T]> { + let start = self.as_non_null().cast::().as_ptr(); + let slice = core::ptr::slice_from_raw_parts_mut(start, N); + // SAFETY: `slice` is not null, because it is derived from `start` + // which is non-null. + let slice = unsafe { NonNull::new_unchecked(slice) }; + // SAFETY: Lemma: In the following safety arguments, note that `slice` + // is derived from `self` in two steps: first, by casting `self: [T; N]` + // to `start: T`, then by constructing a pointer to a slice starting at + // `start` of length `N`. As a result, `slice` references exactly the + // same allocation as `self`, if any. + // + // 0. By the above lemma, if `slice`'s referent is not zero sized, then + // `slice` is derived from the same allocation as `self`, which, by + // invariant on `Ptr`, is valid. + // 1. By the above lemma, if `slice`'s referent is not zero sized, then + // , `slice` has valid provenance for `A`, since it is derived from + // the pointer `self`, which, by invariant on `Ptr`, has valid + // provenance for `A`. + // 2. By the above lemma, if `slice`'s referent is not zero sized, then + // `slice` addresses a byte range which is entirely contained in `A`, + // because it references exactly the same byte range as `self`, + // which, by invariant on `Ptr`, is entirely contained in `A`. + // 3. By the above lemma, `slice` addresses a byte range whose length + // fits in an `isize`, since it addresses exactly the same byte range + // as `self`, which, by invariant on `Ptr`, has a length that fits in + // an `isize`. + // 4. By the above lemma, `slice` addresses a byte range which does not + // wrap around the address space, since it addresses exactly the same + // byte range as `self`, which, by invariant on `Ptr`, does not wrap + // around the address space. + // 5. By the above lemma, if `slice`'s referent is not zero sized, then + // `A` is guaranteed to live for at least `'a`, because it is derived + // from the same allocation as `self`, which, by invariant on `Ptr`, + // lives for at least `'a`. + unsafe { PtrInner::new(slice) } + } +} + +impl<'a> PtrInner<'a, [u8]> { + /// Attempts to cast `self` to a `U` using the given cast type. + /// + /// If `U` is a slice DST and pointer metadata (`meta`) is provided, then + /// the cast will only succeed if it would produce an object with the given + /// metadata. + /// + /// Returns `None` if the resulting `U` would be invalidly-aligned, if no + /// `U` can fit in `self`, or if the provided pointer metadata describes an + /// invalid instance of `U`. On success, returns a pointer to the + /// largest-possible `U` which fits in `self`. + /// + /// # Safety + /// + /// The caller may assume that this implementation is correct, and may rely + /// on that assumption for the soundness of their code. In particular, the + /// caller may assume that, if `try_cast_into` returns `Some((ptr, + /// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte + /// ranges within `self`, and that `ptr` and `remainder` entirely cover + /// `self`. Finally: + /// - If this is a prefix cast, `ptr` has the same address as `self`. + /// - If this is a suffix cast, `remainder` has the same address as `self`. + pub(crate) const fn try_cast_into( + self, + cast_type: CastType, + meta: Option, + ) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError> + where + U: 'a + ?Sized + KnownLayout, + { + let layout = match meta { + None => U::LAYOUT, + // This can return `None` if the metadata describes an object + // which can't fit in an `isize`. + Some(meta) => { + let size = match crate::util::size_for_metadata::(meta) { + Some(size) => size, + None => return Err(CastError::Size(SizeError::new(self))), + }; + DstLayout { align: U::LAYOUT.align, size_info: crate::SizeInfo::Sized { size } } + } + }; + // PANICS: By invariant, the byte range addressed by + // `self.as_non_null()` does not wrap around the address space. This + // implies that the sum of the address (represented as a `usize`) and + // length do not overflow `usize`, as required by + // `validate_cast_and_convert_metadata`. Thus, this call to + // `validate_cast_and_convert_metadata` will only panic if `U` is a DST + // whose trailing slice element is zero-sized. + let maybe_metadata = layout.validate_cast_and_convert_metadata( + self.as_non_null().as_ptr() as *mut u8 as usize, + self.len(), + cast_type, + ); + + let (elems, split_at) = match maybe_metadata { + Ok((elems, split_at)) => (elems, split_at), + Err(MetadataCastError::Alignment) => { + // SAFETY: Since `validate_cast_and_convert_metadata` returned + // an alignment error, `U` must have an alignment requirement + // greater than one. + let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) }; + return Err(CastError::Alignment(err)); + } + Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))), + }; + + // SAFETY: `validate_cast_and_convert_metadata` promises to return + // `split_at <= self.len()`. + let (l_slice, r_slice) = unsafe { self.split_at(split_at) }; + + let (target, remainder) = match cast_type { + CastType::Prefix => (l_slice, r_slice), + CastType::Suffix => (r_slice, l_slice), + }; + + let base = target.as_non_null().cast::(); + + // let elems = ::PointerMetadata::from_elem_count(elems); + let elems = crate::util::metadata_from_elem_count::(elems); + // For a slice DST type, if `meta` is `Some(elems)`, then we synthesize + // `layout` to describe a sized type whose size is equal to the size of + // the instance that we are asked to cast. For sized types, + // `validate_cast_and_convert_metadata` returns `elems == 0`. Thus, in + // this case, we need to use the `elems` passed by the caller, not the + // one returned by `validate_cast_and_convert_metadata`. + let elems = meta.unwrap_or(elems); + + let ptr = U::raw_from_ptr_len(base, elems); + + // SAFETY: + // 0. By invariant, if `target`'s referent is not zero sized, then + // `target` is derived from some valid Rust allocation, `A`. By + // contract on `cast`, `ptr` is derived from `self`, and thus from + // the same valid Rust allocation, `A`. + // 1. By invariant, if `target`'s referent is not zero sized, then + // `target` has provenance valid for some Rust allocation, `A`. + // Because `ptr` is derived from `target` via provenance-preserving + // operations, `ptr` will also have provenance valid for `A`. + // - `validate_cast_and_convert_metadata` promises that the object + // described by `elems` and `split_at` lives at a byte range which is + // a subset of the input byte range. Thus: + // 2. Since, by invariant, if `target`'s referent is not zero sized, + // then `target` addresses a byte range which is entirely + // contained in `A`, so does `ptr`. + // 3. Since, by invariant, `target` addresses a byte range whose + // length fits in an `isize`, so does `ptr`. + // 4. Since, by invariant, `target` addresses a byte range which does + // not wrap around the address space, so does `ptr`. + // 5. Since, by invariant, if `target`'s referent is not zero sized, + // then `target` refers to an allocation which is guaranteed to + // live for at least `'a`, so does `ptr`. + Ok((unsafe { PtrInner::new(ptr) }, remainder)) + } +} + +#[allow(clippy::needless_lifetimes)] +impl<'a, T> PtrInner<'a, T> { + /// Performs an unaligned read of `self`'s referent. + /// + /// # Safety + /// + /// `self` must point to a properly initialized value of type `T`, and + /// reading a copy of `T` must not violate `T`'s safety invariants. + /// + /// `self`'s referent must not be concurrently modified during this call. + pub(crate) unsafe fn read_unaligned(self) -> T { + let raw = self.as_non_null().as_ptr(); + // SAFETY: The caller promises that `self` points to a bit-valid `T` and + // that reading a copy of it won't violate `T`'s safety invariants. The + // caller promises that `self`'s referent won't be concurrently modified + // during this operation. + // + // `raw` is valid for reads: + // - `self.as_non_null()` returns a `NonNull`, which is guaranteed to be + // non-null. + // - By invariant on `PtrInner`, `raw` is is either zero-sized or: + // - ...is within bounds of a single allocated object which lives for + // at least `'a`. + // - ...has valid provenance for that object. + unsafe { core::ptr::read_unaligned(raw) } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_split_at() { + const N: usize = 16; + let arr = [1; N]; + let ptr = PtrInner::from_ref(&arr).as_slice(); + for i in 0..=N { + assert_eq!(ptr.len(), N); + // SAFETY: `i` is in bounds by construction. + let (l, r) = unsafe { ptr.split_at(i) }; + // SAFETY: Points to a valid value by construction. + let l_sum: usize = l.iter().map(|ptr| unsafe { ptr.read_unaligned() }).sum(); + // SAFETY: Points to a valid value by construction. + let r_sum: usize = r.iter().map(|ptr| unsafe { ptr.read_unaligned() }).sum(); + assert_eq!(l_sum, i); + assert_eq!(r_sum, N - i); + assert_eq!(l_sum + r_sum, N); + } + } +} diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs new file mode 100644 index 0000000000..e52a458650 --- /dev/null +++ b/src/pointer/invariant.rs @@ -0,0 +1,363 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(missing_copy_implementations, missing_debug_implementations)] + +//! The parameterized invariants of a [`Ptr`][super::Ptr]. +//! +//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) +//! triples implementing the [`Invariants`] trait. + +/// The invariants of a [`Ptr`][super::Ptr]. +pub trait Invariants: Sealed { + type Aliasing: Aliasing; + type Alignment: Alignment; + type Validity: Validity; + + /// Invariants identical to `Self` except with a different aliasing + /// invariant. + type WithAliasing: Invariants< + Aliasing = A, + Alignment = Self::Alignment, + Validity = Self::Validity, + >; + + /// Invariants identical to `Self` except with a different alignment + /// invariant. + type WithAlignment: Invariants< + Aliasing = Self::Aliasing, + Alignment = A, + Validity = Self::Validity, + >; + + /// Invariants identical to `Self` except with a different validity + /// invariant. + type WithValidity: Invariants< + Aliasing = Self::Aliasing, + Alignment = Self::Alignment, + Validity = V, + >; +} + +impl Invariants for (A, AA, V) { + type Aliasing = A; + type Alignment = AA; + type Validity = V; + + type WithAliasing = (AB, AA, V); + type WithAlignment = (A, AB, V); + type WithValidity = (A, AA, VB); +} + +/// The aliasing invariant of a [`Ptr`][super::Ptr]. +pub trait Aliasing: Sealed { + /// Is `Self` [`Exclusive`]? + #[doc(hidden)] + const IS_EXCLUSIVE: bool; + + /// A type which has the correct variance over `'a` and `T` for this + /// aliasing invariant. `Ptr` stores a `::Variance<'a, T>` to inherit this variance. + #[doc(hidden)] + type Variance<'a, T: 'a + ?Sized>; + + #[doc(hidden)] + type MappedTo: Aliasing; +} + +/// The alignment invariant of a [`Ptr`][super::Ptr]. +pub trait Alignment: Sealed { + #[doc(hidden)] + type MappedTo: Alignment; +} + +/// The validity invariant of a [`Ptr`][super::Ptr]. +pub trait Validity: Sealed { + #[doc(hidden)] + type MappedTo: Validity; +} + +/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. +/// +/// # Safety +/// +/// Given `A: Reference`, callers may assume that either `A = Shared` or `A = +/// Exclusive`. +pub trait Reference: Aliasing + Sealed {} + +/// It is unknown whether any invariant holds. +pub enum Unknown {} + +impl Alignment for Unknown { + type MappedTo = M::FromUnknown; +} +impl Validity for Unknown { + type MappedTo = M::FromUnknown; +} + +/// The `Ptr<'a, T>` does not permit any reads or writes from or to its referent. +pub enum Inaccessible {} + +impl Aliasing for Inaccessible { + const IS_EXCLUSIVE: bool = false; + + // SAFETY: Inaccessible `Ptr`s permit neither reads nor writes, and so it + // doesn't matter how long the referent actually lives. Thus, covariance is + // fine (and is chosen because it is maximally permissive). Shared + // references are covariant [1]. + // + // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance + type Variance<'a, T: 'a + ?Sized> = &'a T; + type MappedTo = M::FromInaccessible; +} + +/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. +/// +/// The referent of a shared-aliased `Ptr` may be concurrently referenced by any +/// number of shared-aliased `Ptr` or `&T` references, and may not be +/// concurrently referenced by any exclusively-aliased `Ptr`s or `&mut T` +/// references. The referent must not be mutated, except via [`UnsafeCell`]s. +/// +/// [`UnsafeCell`]: core::cell::UnsafeCell +pub enum Shared {} +impl Aliasing for Shared { + const IS_EXCLUSIVE: bool = false; + type Variance<'a, T: 'a + ?Sized> = &'a T; + type MappedTo = M::FromShared; +} +impl Reference for Shared {} + +/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. +/// +/// The referent of an exclusively-aliased `Ptr` may not be concurrently +/// referenced by any other `Ptr`s or references, and may not be accessed (read +/// or written) other than via this `Ptr`. +pub enum Exclusive {} +impl Aliasing for Exclusive { + const IS_EXCLUSIVE: bool = true; + type Variance<'a, T: 'a + ?Sized> = &'a mut T; + type MappedTo = M::FromExclusive; +} +impl Reference for Exclusive {} + +/// The referent is aligned: for `Ptr`, the referent's address is a +/// multiple of the `T`'s alignment. +pub enum Aligned {} +impl Alignment for Aligned { + type MappedTo = M::FromAligned; +} + +/// The byte ranges initialized in `T` are also initialized in the referent. +/// +/// Formally: uninitialized bytes may only be present in `Ptr`'s referent +/// where they are guaranteed to be present in `T`. This is a dynamic property: +/// if, at a particular byte offset, a valid enum discriminant is set, the +/// subsequent bytes may only have uninitialized bytes as specificed by the +/// corresponding enum. +/// +/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in +/// the range `[0, len)`: +/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t` +/// is initialized, then the byte at offset `b` within `*ptr` must be +/// initialized. +/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be +/// the subset of valid instances of `T` of length `len` which contain `c` in +/// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte +/// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr` +/// must be initialized. +/// +/// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum +/// type at a particular offset, and the enum discriminant stored in `*ptr` +/// corresponds to a valid variant of that enum type, then it is guaranteed +/// that the appropriate bytes of `*ptr` are initialized as defined by that +/// variant's bit validity (although note that the variant may contain another +/// enum type, in which case the same rules apply depending on the state of +/// its discriminant, and so on recursively). +pub enum AsInitialized {} +impl Validity for AsInitialized { + type MappedTo = M::FromAsInitialized; +} + +/// The byte ranges in the referent are fully initialized. In other words, if +/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. +pub enum Initialized {} +impl Validity for Initialized { + type MappedTo = M::FromInitialized; +} + +/// The referent is bit-valid for `T`. +pub enum Valid {} +impl Validity for Valid { + type MappedTo = M::FromValid; +} + +/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. +/// +/// `T: Read` implies that a pointer to `T` with aliasing `A` permits +/// unsynchronized read oeprations. This can be because `A` is [`Exclusive`] or +/// because `T` does not permit interior mutation. +/// +/// # Safety +/// +/// `T: Read` if either of the following conditions holds: +/// - `A` is [`Exclusive`] +/// - `T` implements [`Immutable`](crate::Immutable) +/// +/// As a consequence, if `T: Read`, then any `Ptr` is +/// permitted to perform unsynchronized reads from its referent. +#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, marker)] +pub unsafe trait Read {} + +define_because!( + /// Unsynchronized reads are permitted because only one live + /// [`Ptr`](crate::Ptr) or reference may exist to the referent bytes at a + /// time. + #[doc(hidden)] + pub BecauseExclusive +); +// SAFETY: The aliasing parameter is `Exclusive`. +unsafe impl Read for T {} + +define_because!( + /// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s + /// or references permit interior mutation. + #[doc(hidden)] + pub BecauseImmutable +); +// SAFETY: `T: Immutable`. +unsafe impl Read for T {} + +use sealed::Sealed; +mod sealed { + use super::*; + + pub trait Sealed {} + + impl Sealed for Unknown {} + + impl Sealed for Inaccessible {} + impl Sealed for Shared {} + impl Sealed for Exclusive {} + + impl Sealed for Aligned {} + + impl Sealed for AsInitialized {} + impl Sealed for Initialized {} + impl Sealed for Valid {} + + impl Sealed for (A, AA, V) {} +} + +pub use mapping::*; +mod mapping { + use super::*; + + /// A mapping from one [`Aliasing`] type to another. + /// + /// An `AliasingMapping` is a type-level map which maps one `Aliasing` type + /// to another. It is always "total" in the sense of having a mapping for + /// any `A: Aliasing`. + /// + /// Given `A: Aliasing` and `M: AliasingMapping`, `M` can be applied to `A` + /// as [`MappedAliasing`](MappedAliasing). + /// + /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve + /// or modify invariants as required by each method's semantics. + pub trait AliasingMapping { + type FromInaccessible: Aliasing; + type FromShared: Aliasing; + type FromExclusive: Aliasing; + } + + /// A mapping from one [`Alignment`] type to another. + /// + /// An `AlignmentMapping` is a type-level map which maps one `Alignment` + /// type to another. It is always "total" in the sense of having a mapping + /// for any `A: Alignment`. + /// + /// Given `A: Alignment` and `M: AlignmentMapping`, `M` can be applied to + /// `A` as [`MappedAlignment`](MappedAlignment). + /// + /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve + /// or modify invariants as required by each method's semantics. + pub trait AlignmentMapping { + type FromUnknown: Alignment; + type FromAligned: Alignment; + } + + /// A mapping from one [`Validity`] type to another. + /// + /// An `ValidityMapping` is a type-level map which maps one `Validity` type + /// to another. It is always "total" in the sense of having a mapping for + /// any `A: Validity`. + /// + /// Given `V: Validity` and `M: ValidityMapping`, `M` can be applied to `V` + /// as [`MappedValidity`](MappedValidity). + /// + /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve + /// or modify invariants as required by each method's semantics. + pub trait ValidityMapping { + type FromUnknown: Validity; + type FromAsInitialized: Validity; + type FromInitialized: Validity; + type FromValid: Validity; + } + + /// The application of the [`AliasingMapping`] `M` to the [`Aliasing`] `A`. + #[allow(type_alias_bounds)] + pub type MappedAliasing = A::MappedTo; + + /// The application of the [`AlignmentMapping`] `M` to the [`Alignment`] `A`. + #[allow(type_alias_bounds)] + pub type MappedAlignment = A::MappedTo; + + /// The application of the [`ValidityMapping`] `M` to the [`Validity`] `A`. + #[allow(type_alias_bounds)] + pub type MappedValidity = V::MappedTo; + + impl AliasingMapping + for ((Inaccessible, FromInaccessible), (Shared, FromShared), (Exclusive, FromExclusive)) + { + type FromInaccessible = FromInaccessible; + type FromShared = FromShared; + type FromExclusive = FromExclusive; + } + + impl AlignmentMapping + for ((Unknown, FromUnknown), (Shared, FromAligned)) + { + type FromUnknown = FromUnknown; + type FromAligned = FromAligned; + } + + impl< + FromUnknown: Validity, + FromAsInitialized: Validity, + FromInitialized: Validity, + FromValid: Validity, + > ValidityMapping + for ( + (Unknown, FromUnknown), + (AsInitialized, FromAsInitialized), + (Initialized, FromInitialized), + (Valid, FromValid), + ) + { + type FromUnknown = FromUnknown; + type FromAsInitialized = FromAsInitialized; + type FromInitialized = FromInitialized; + type FromValid = FromValid; + } + + impl ValidityMapping for (Initialized, FromInitialized) { + type FromUnknown = Unknown; + type FromAsInitialized = Unknown; + type FromInitialized = FromInitialized; + type FromValid = Unknown; + } +} diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 1533eb9efd..1b9bd44234 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -8,11 +8,15 @@ //! Abstractions over raw pointers. -mod aliasing_safety; +mod inner; +#[doc(hidden)] +pub mod invariant; mod ptr; -pub use aliasing_safety::{AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable}; -pub use ptr::{invariant, Ptr}; +#[doc(hidden)] +pub use invariant::{BecauseExclusive, BecauseImmutable, Read}; +#[doc(hidden)] +pub use ptr::Ptr; use crate::Unaligned; @@ -20,14 +24,14 @@ use crate::Unaligned; /// to [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid -pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Any> = +pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>; /// A semi-user-facing wrapper type representing a maybe-aligned reference, for /// use in [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid -pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Any> = +pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = Ptr<'a, T, (Aliasing, Alignment, invariant::Valid)>; // These methods are defined on the type alias, `MaybeAligned`, so as to bring @@ -35,23 +39,30 @@ pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment> where T: 'a + ?Sized, - Aliasing: invariant::Aliasing + invariant::AtLeast, + Aliasing: invariant::Aliasing, Alignment: invariant::Alignment, { /// Reads the value from `MaybeAligned`. #[must_use] #[inline] - pub fn read_unaligned(self) -> T + pub fn read_unaligned(self) -> T where T: Copy, + T: invariant::Read, { - let raw = self.as_non_null().as_ptr(); // SAFETY: By invariant on `MaybeAligned`, `raw` contains - // validly-initialized data for `T`. The value is safe to read and - // return, because `T` is copy. - unsafe { core::ptr::read_unaligned(raw) } + // validly-initialized data for `T`. By `T: Read`, we are + // permitted to perform a read of `self`'s referent. + unsafe { self.as_inner().read_unaligned() } } +} +impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment> +where + T: 'a + ?Sized, + Aliasing: invariant::Reference, + Alignment: invariant::Alignment, +{ /// Views the value as an aligned reference. /// /// This is only available if `T` is [`Unaligned`]. @@ -70,7 +81,7 @@ pub(crate) fn is_zeroed(ptr: Ptr<'_, T, I>) -> bool where T: crate::Immutable + crate::KnownLayout, I: invariant::Invariants, - I::Aliasing: invariant::AtLeast, + I::Aliasing: invariant::Reference, { ptr.as_bytes::().as_ref().iter().all(|&byte| byte == 0) } diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index affdd921f9..b476d1428f 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -6,16 +6,17 @@ // This file may not be copied, modified, or distributed except according to // those terms. -use core::ptr::NonNull; +use core::{marker::PhantomData, ptr::NonNull}; -use crate::{util::AsAddress, CastType, KnownLayout}; +use super::{inner::PtrInner, invariant::*}; +use crate::{CastType, KnownLayout}; /// Module used to gate access to [`Ptr`]'s fields. mod def { + use super::*; + #[cfg(doc)] - use super::invariant; - use super::Invariants; - use core::{marker::PhantomData, ptr::NonNull}; + use super::super::invariant; /// A raw pointer with more restrictions. /// @@ -42,37 +43,21 @@ mod def { /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html pub struct Ptr<'a, T, I> where - T: 'a + ?Sized, + T: ?Sized, I: Invariants, { /// # Invariants /// - /// 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from - /// some valid Rust allocation, `A`. - /// 1. If `ptr`'s referent is not zero sized, then `ptr` has valid - /// provenance for `A`. - /// 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a - /// byte range which is entirely contained in `A`. - /// 3. `ptr` addresses a byte range whose length fits in an `isize`. - /// 4. `ptr` addresses a byte range which does not wrap around the - /// address space. - /// 5. If `ptr`'s referent is not zero sized,`A` is guaranteed to live - /// for at least `'a`. - /// 6. `T: 'a`. - /// 7. `ptr` conforms to the aliasing invariant of + /// 0. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 8. `ptr` conforms to the alignment invariant of + /// 1. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 9. `ptr` conforms to the validity invariant of + /// 2. `ptr` conforms to the validity invariant of /// [`I::Validity`](invariant::Validity). - // SAFETY: `NonNull` is covariant over `T` [1]. - // - // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html - ptr: NonNull, - // SAFETY: `&'a ()` is covariant over `'a` [1]. - // - // [1]: https://doc.rust-lang.org/reference/subtyping.html#variance - _invariants: PhantomData<&'a I>, + // SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`. + ptr: PtrInner<'a, T>, + _variance: PhantomData<::Variance<'a, T>>, + _invariants: PhantomData, } impl<'a, T, I> Ptr<'a, T, I> @@ -103,233 +88,68 @@ mod def { /// [`I::Alignment`](invariant::Alignment). /// 8. `ptr` conforms to the validity invariant of /// [`I::Validity`](invariant::Validity). - pub(super) unsafe fn new(ptr: NonNull) -> Ptr<'a, T, I> { + pub(super) const unsafe fn new(ptr: NonNull) -> Ptr<'a, T, I> { + // SAFETY: The caller has promised (in 0 - 5) to satisfy all safety + // invariants of `PtrInner::new`. + let ptr = unsafe { PtrInner::new(ptr) }; + // SAFETY: The caller has promised (in 6 - 8) to satisfy all safety + // invariants of `Ptr`. + Self { ptr, _variance: PhantomData, _invariants: PhantomData } + } + + /// Constructs a new `Ptr` from a [`PtrInner`]. + /// + /// # Safety + /// + /// The caller promises that: + /// + /// 0. `ptr` conforms to the aliasing invariant of + /// [`I::Aliasing`](invariant::Aliasing). + /// 1. `ptr` conforms to the alignment invariant of + /// [`I::Alignment`](invariant::Alignment). + /// 2. `ptr` conforms to the validity invariant of + /// [`I::Validity`](invariant::Validity). + pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, T>) -> Ptr<'a, T, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. - Self { ptr, _invariants: PhantomData } + Self { ptr, _variance: PhantomData, _invariants: PhantomData } } - /// Converts this `Ptr` to a [`NonNull`]. + /// Converts this `Ptr` to a [`PtrInner`]. /// /// Note that this method does not consume `self`. The caller should - /// watch out for `unsafe` code which uses the returned `NonNull` in a - /// way that violates the safety invariants of `self`. - pub(crate) fn as_non_null(&self) -> NonNull { + /// watch out for `unsafe` code which uses the returned value in a way + /// that violates the safety invariants of `self`. + pub(crate) const fn as_inner(&self) -> PtrInner<'a, T> { self.ptr } } } -#[allow(unreachable_pub)] // This is a false positive on our MSRV toolchain. pub use def::Ptr; -/// Used to define the system of [invariants][invariant] of `Ptr`. -macro_rules! define_system { - ($(#[$system_attr:meta])* $system:ident { - $($(#[$set_attr:meta])* $set:ident { - $( $(#[$elem_attr:meta])* $elem:ident $(< $($stronger_elem:ident)|*)?,)* - })* - }) => { - /// No requirement - any invariant is allowed. - #[allow(missing_copy_implementations, missing_debug_implementations)] - pub enum Any {} - - /// `Self` imposes a requirement at least as strict as `I`. - pub trait AtLeast {} - - mod sealed { - pub trait Sealed {} - - impl<$($set,)*> Sealed for ($($set,)*) - where - $($set: super::$set,)* - {} - - impl Sealed for super::Any {} - - $($( - impl Sealed for super::$elem {} - )*)* - } - - $(#[$system_attr])* - /// - #[doc = concat!( - stringify!($system), - " are encoded as tuples of (", - )] - $(#[doc = concat!( - "[`", - stringify!($set), - "`]," - )])* - #[doc = concat!( - ").", - )] - /// This trait is implemented for such tuples, and can be used to - /// project out the components of these tuples via its associated types. - pub trait $system: sealed::Sealed { - $( - $(#[$set_attr])* - type $set: $set; - )* - } - - impl<$($set,)*> $system for ($($set,)*) - where - $($set: self::$set,)* - { - $(type $set = $set;)* - } - - $( - $(#[$set_attr])* - pub trait $set: 'static + sealed::Sealed { - // This only exists for use in - // `into_exclusive_or_post_monomorphization_error`. - #[doc(hidden)] - const NAME: &'static str; - } - - impl $set for Any { - const NAME: &'static str = stringify!(Any); - } - - $( - $(#[$elem_attr])* - #[allow(missing_copy_implementations, missing_debug_implementations)] - pub enum $elem {} - - $(#[$elem_attr])* - impl $set for $elem { - const NAME: &'static str = stringify!($elem); - } - )* - )* - - $($( - impl AtLeast for $elem {} - impl AtLeast<$elem> for $elem {} - - $($(impl AtLeast<$elem> for $stronger_elem {})*)? - )*)* - }; -} - -/// The parameterized invariants of a [`Ptr`]. -/// -/// Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) -/// triples implementing the [`Invariants`] trait. -#[doc(hidden)] -pub mod invariant { - define_system! { - /// The invariants of a [`Ptr`][super::Ptr]. - Invariants { - /// The aliasing invariant of a [`Ptr`][super::Ptr]. - Aliasing { - /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. - /// - /// The referent of a shared-aliased `Ptr` may be concurrently - /// referenced by any number of shared-aliased `Ptr` or `&T` - /// references, and may not be concurrently referenced by any - /// exclusively-aliased `Ptr`s or `&mut T` references. The - /// referent must not be mutated, except via [`UnsafeCell`]s. - /// - /// [`UnsafeCell`]: core::cell::UnsafeCell - Shared < Exclusive, - - /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut - /// T`. - /// - /// The referent of an exclusively-aliased `Ptr` may not be - /// concurrently referenced by any other `Ptr`s or references, - /// and may not be accessed (read or written) other than via - /// this `Ptr`. - Exclusive, - } - - /// The alignment invariant of a [`Ptr`][super::Ptr]. - Alignment { - /// The referent is aligned: for `Ptr`, the referent's - /// address is a multiple of the `T`'s alignment. - Aligned, - } - - /// The validity invariant of a [`Ptr`][super::Ptr]. - Validity { - /// The byte ranges initialized in `T` are also initialized in - /// the referent. - /// - /// Formally: uninitialized bytes may only be present in - /// `Ptr`'s referent where they are guaranteed to be present - /// in `T`. This is a dynamic property: if, at a particular byte - /// offset, a valid enum discriminant is set, the subsequent - /// bytes may only have uninitialized bytes as specificed by the - /// corresponding enum. - /// - /// Formally, given `len = size_of_val_raw(ptr)`, at every byte - /// offset, `b`, in the range `[0, len)`: - /// - If, in any instance `t: T` of length `len`, the byte at - /// offset `b` in `t` is initialized, then the byte at offset - /// `b` within `*ptr` must be initialized. - /// - Let `c` be the contents of the byte range `[0, b)` in - /// `*ptr`. Let `S` be the subset of valid instances of `T` of - /// length `len` which contain `c` in the offset range `[0, - /// b)`. If, in any instance of `t: T` in `S`, the byte at - /// offset `b` in `t` is initialized, then the byte at offset - /// `b` in `*ptr` must be initialized. - /// - /// Pragmatically, this means that if `*ptr` is guaranteed to - /// contain an enum type at a particular offset, and the enum - /// discriminant stored in `*ptr` corresponds to a valid - /// variant of that enum type, then it is guaranteed that the - /// appropriate bytes of `*ptr` are initialized as defined by - /// that variant's bit validity (although note that the - /// variant may contain another enum type, in which case the - /// same rules apply depending on the state of its - /// discriminant, and so on recursively). - AsInitialized < Initialized | Valid, - - /// The byte ranges in the referent are fully initialized. In - /// other words, if the referent is `N` bytes long, then it - /// contains a bit-valid `[u8; N]`. - Initialized, - - /// The referent is bit-valid for `T`. - Valid, - } - } - } -} - -pub(crate) use invariant::*; - /// External trait implementations on [`Ptr`]. mod _external { use super::*; use core::fmt::{Debug, Formatter}; - /// SAFETY: Shared pointers are safely `Copy`. We do not implement `Copy` - /// for exclusive pointers, since at most one may exist at a time. `Ptr`'s - /// other invariants are unaffected by the number of references that exist + /// SAFETY: Shared pointers are safely `Copy`. `Ptr`'s other invariants + /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. impl<'a, T, I> Copy for Ptr<'a, T, I> where T: 'a + ?Sized, - I: Invariants, - Shared: AtLeast, + I: Invariants, { } - /// SAFETY: Shared pointers are safely `Clone`. We do not implement `Clone` - /// for exclusive pointers, since at most one may exist at a time. `Ptr`'s - /// other invariants are unaffected by the number of references that exist + /// SAFETY: Shared pointers are safely `Clone`. `Ptr`'s other invariants + /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. impl<'a, T, I> Clone for Ptr<'a, T, I> where T: 'a + ?Sized, - I: Invariants, - Shared: AtLeast, + I: Invariants, { #[inline] fn clone(&self) -> Self { @@ -344,7 +164,7 @@ mod _external { { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - self.as_non_null().fmt(f) + self.as_inner().as_non_null().fmt(f) } } } @@ -363,30 +183,15 @@ mod _conversions { #[doc(hidden)] #[inline] pub fn from_ref(ptr: &'a T) -> Self { - let ptr = NonNull::from(ptr); + let inner = PtrInner::from_ref(ptr); // SAFETY: - // 0. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a T`, is derived from some valid Rust - // allocation, `A`. - // 1. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a T`, has valid provenance for `A`. - // 2. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a T`, addresses a byte range which is entirely - // contained in `A`. - // 3. `ptr`, by invariant on `&'a T`, addresses a byte range whose - // length fits in an `isize`. - // 4. `ptr`, by invariant on `&'a T`, addresses a byte range which - // does not wrap around the address space. - // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant - // on `&'a T`, is guaranteed to live for at least `'a`. - // 6. `T: 'a`. - // 7. `ptr`, by invariant on `&'a T`, conforms to the aliasing + // 0. `ptr`, by invariant on `&'a T`, conforms to the aliasing // invariant of `Shared`. - // 8. `ptr`, by invariant on `&'a T`, conforms to the alignment + // 1. `ptr`, by invariant on `&'a T`, conforms to the alignment // invariant of `Aligned`. - // 9. `ptr`, by invariant on `&'a T`, conforms to the validity + // 2. `ptr`, by invariant on `&'a T`, conforms to the validity // invariant of `Valid`. - unsafe { Self::new(ptr) } + unsafe { Self::from_inner(inner) } } } @@ -398,29 +203,15 @@ mod _conversions { /// Constructs a `Ptr` from an exclusive reference. #[inline] pub(crate) fn from_mut(ptr: &'a mut T) -> Self { - let ptr = NonNull::from(ptr); + let inner = PtrInner::from_mut(ptr); // SAFETY: - // 0. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a mut T`, is derived from some valid Rust - // allocation, `A`. - // 1. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a mut T`, has valid provenance for `A`. - // 2. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a mut T`, addresses a byte range which is - // entirely contained in `A`. - // 3. `ptr`, by invariant on `&'a mut T`, addresses a byte range - // whose length fits in an `isize`. - // 4. `ptr`, by invariant on `&'a mut T`, addresses a byte range - // which does not wrap around the address space. - // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant - // on `&'a mut T`, is guaranteed to live for at least `'a`. - // 6. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing + // 0. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing // invariant of `Exclusive`. - // 7. `ptr`, by invariant on `&'a mut T`, conforms to the alignment + // 1. `ptr`, by invariant on `&'a mut T`, conforms to the alignment // invariant of `Aligned`. - // 8. `ptr`, by invariant on `&'a mut T`, conforms to the validity + // 2. `ptr`, by invariant on `&'a mut T`, conforms to the validity // invariant of `Valid`. - unsafe { Self::new(ptr) } + unsafe { Self::from_inner(inner) } } } @@ -429,7 +220,7 @@ mod _conversions { where T: 'a + ?Sized, I: Invariants, - I::Aliasing: AtLeast, + I::Aliasing: Reference, { /// Converts `self` to a shared reference. // This consumes `self`, not `&self`, because `self` is, logically, a @@ -438,7 +229,7 @@ mod _conversions { // calling `as_ref`. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_ref(self) -> &'a T { - let raw = self.as_non_null(); + let raw = self.as_inner().as_non_null(); // SAFETY: This invocation of `NonNull::as_ref` satisfies its // documented safety preconditions: // @@ -453,17 +244,17 @@ mod _conversions { // > must all be within the bounds of a single allocated object. // > [2] // - // This is ensured by contract on all `Ptr`s. + // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to an initialized instance of `T`. This // is ensured by-contract on `Ptr`, because the `I::Validity` is // `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by - // contract on `Ptr`, because the `I::Aliasing` is - // `AtLeast`. Either it is `Shared` or `Exclusive`. If it - // is `Shared`, other references may not mutate the referent - // outside of `UnsafeCell`s. + // contract on `Ptr`, because `I::Aliasing: Reference`. Either it + // is `Shared` or `Exclusive`. If it is `Shared`, other + // references may not mutate the referent outside of + // `UnsafeCell`s. // // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.as_ref // [2]: https://doc.rust-lang.org/std/ptr/index.html#safety @@ -475,7 +266,7 @@ mod _conversions { where T: 'a + ?Sized, I: Invariants, - I::Aliasing: AtLeast, + I::Aliasing: Reference, { /// Reborrows `self`, producing another `Ptr`. /// @@ -490,25 +281,14 @@ mod _conversions { 'a: 'b, { // SAFETY: The following all hold by invariant on `self`, and thus - // hold of `ptr = self.as_non_null()`: - // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived - // from some valid Rust allocation, `A`. - // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid - // provenance for `A`. - // 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a - // byte range which is entirely contained in `A`. - // 3. `ptr` addresses a byte range whose length fits in an `isize`. - // 4. `ptr` addresses a byte range which does not wrap around the - // address space. - // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed - // to live for at least `'a`. - // 6. SEE BELOW. - // 7. `ptr` conforms to the alignment invariant of + // hold of `ptr = self.as_inner()`: + // 0. SEE BELOW. + // 1. `ptr` conforms to the alignment invariant of // [`I::Alignment`](invariant::Alignment). - // 8. `ptr` conforms to the validity invariant of + // 2. `ptr` conforms to the validity invariant of // [`I::Validity`](invariant::Validity). // - // For aliasing (6 above), since `I::Aliasing: AtLeast`, + // For aliasing (6 above), since `I::Aliasing: Reference`, // there are two cases for `I::Aliasing`: // - For `invariant::Shared`: `'a` outlives `'b`, and so the // returned `Ptr` does not permit accessing the referent any @@ -525,7 +305,7 @@ mod _conversions { // while `self` is live. Thus, as long as the returned `Ptr` // exists, no other references or `Ptr`s which refer to the same // memory may be live. - unsafe { Ptr::new(self.as_non_null()) } + unsafe { Ptr::from_inner(self.as_inner()) } } } @@ -537,7 +317,7 @@ mod _conversions { /// Converts `self` to a mutable reference. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_mut(self) -> &'a mut T { - let mut raw = self.as_non_null(); + let mut raw = self.as_inner().as_non_null(); // SAFETY: This invocation of `NonNull::as_mut` satisfies its // documented safety preconditions: // @@ -552,11 +332,11 @@ mod _conversions { // > must all be within the bounds of a single allocated object. // > [2] // - // This is ensured by contract on all `Ptr`s. + // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to an initialized instance of `T`. This - // is ensured by-contract on `Ptr`, because the - // `VALIDITY_INVARIANT` is `Valid`. + // is ensured by-contract on `Ptr`, because the validity + // invariant is `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because the `ALIASING_INVARIANT` is @@ -597,7 +377,7 @@ mod _conversions { // byte ranges. Since `p` and the returned pointer address the // same byte range, they refer to `UnsafeCell`s at the same byte // ranges. - let c = unsafe { self.cast_unsized(|p| T::cast_into_inner(p)) }; + let c = unsafe { self.cast_unsized_unchecked(|p| T::cast_into_inner(p)) }; // SAFETY: By invariant on `TransparentWrapper`, since `self` // satisfies the alignment invariant `I::Alignment`, `c` (of type // `T::Inner`) satisfies the given "applied" alignment invariant. @@ -621,9 +401,7 @@ mod _conversions { { /// Converts a `Ptr` an unaligned `T` into a `Ptr` to an aligned /// `Unalign`. - pub(crate) fn into_unalign( - self, - ) -> Ptr<'a, crate::Unalign, (I::Aliasing, Aligned, I::Validity)> { + pub(crate) fn into_unalign(self) -> Ptr<'a, crate::Unalign, I::WithAlignment> { // SAFETY: // - This cast preserves provenance. // - This cast preserves address. `Unalign` promises to have the @@ -633,7 +411,7 @@ mod _conversions { // `UnsafeCell`s at the same locations as `p`. let ptr = unsafe { #[allow(clippy::as_conversions)] - self.cast_unsized(|p: *mut T| p as *mut crate::Unalign) + self.cast_unsized_unchecked(|p: *mut T| p as *mut crate::Unalign) }; // SAFETY: `Unalign` promises to have the same bit validity as // `T`. @@ -641,7 +419,7 @@ mod _conversions { // SAFETY: `Unalign` promises to have alignment 1, and so it is // trivially aligned. let ptr = unsafe { ptr.assume_alignment::() }; - ptr + ptr.unify_invariants() } } } @@ -662,53 +440,34 @@ mod _transitions { /// This allows code which is generic over aliasing to down-cast to a /// concrete aliasing. /// - /// [`Exclusive`]: invariant::Exclusive + /// [`Exclusive`]: crate::pointer::invariant::Exclusive #[inline] pub(crate) fn into_exclusive_or_post_monomorphization_error( self, - ) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> { + ) -> Ptr<'a, T, I::WithAliasing> { + // NOTE(https://github.com/rust-lang/rust/issues/131625): We do this + // rather than just having `Aliasing::IS_EXCLUSIVE` have the panic + // behavior because doing it that way causes rustdoc to fail while + // attempting to document hidden items (since it evaluates the + // constant - and thus panics). trait AliasingExt: Aliasing { - const IS_EXCLUSIVE: bool; + const IS_EXCL: bool; } impl AliasingExt for A { - const IS_EXCLUSIVE: bool = { - let is_exclusive = - strs_are_equal(::NAME, ::NAME); - const_assert!(is_exclusive); + const IS_EXCL: bool = { + assert!(Self::IS_EXCLUSIVE); true }; } - const fn strs_are_equal(s: &str, t: &str) -> bool { - if s.len() != t.len() { - return false; - } - - let s = s.as_bytes(); - let t = t.as_bytes(); - - let mut i = 0; - #[allow(clippy::arithmetic_side_effects)] - while i < s.len() { - #[allow(clippy::indexing_slicing)] - if s[i] != t[i] { - return false; - } - - i += 1; - } - - true - } - - assert!(I::Aliasing::IS_EXCLUSIVE); + assert!(I::Aliasing::IS_EXCL); // SAFETY: We've confirmed that `self` already has the aliasing // `Exclusive`. If it didn't, either the preceding assert would fail - // or evaluating `I::Aliasing::IS_EXCLUSIVE` would fail. We're - // *pretty* sure that it's guaranteed to fail const eval, but the - // `assert!` provides a backstop in case that doesn't work. + // or evaluating `I::Aliasing::IS_EXCL` would fail. We're *pretty* + // sure that it's guaranteed to fail const eval, but the `assert!` + // provides a backstop in case that doesn't work. unsafe { self.assume_exclusive() } } @@ -717,16 +476,16 @@ mod _transitions { /// # Safety /// /// The caller promises that `self` satisfies the invariants `H`. - unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { + const unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { // SAFETY: The caller has promised to satisfy all parameterized // invariants of `Ptr`. `Ptr`'s other invariants are satisfied // by-contract by the source `Ptr`. - unsafe { Ptr::new(self.as_non_null()) } + unsafe { Ptr::from_inner(self.as_inner()) } } /// Helps the type system unify two distinct invariant types which are /// actually the same. - pub(crate) fn unify_invariants< + pub(crate) const fn unify_invariants< H: Invariants, >( self, @@ -743,9 +502,9 @@ mod _transitions { /// The caller promises that `self` satisfies the aliasing requirement /// of `A`. #[inline] - pub(crate) unsafe fn assume_aliasing( + pub(crate) const unsafe fn assume_aliasing( self, - ) -> Ptr<'a, T, (A, I::Alignment, I::Validity)> { + ) -> Ptr<'a, T, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `A`. unsafe { self.assume_invariants() } @@ -758,11 +517,11 @@ mod _transitions { /// The caller promises that `self` satisfies the aliasing requirement /// of `Exclusive`. /// - /// [`Exclusive`]: invariant::Exclusive + /// [`Exclusive`]: crate::pointer::invariant::Exclusive #[inline] - pub(crate) unsafe fn assume_exclusive( + pub(crate) const unsafe fn assume_exclusive( self, - ) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> { + ) -> Ptr<'a, T, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `Exclusive`. unsafe { self.assume_aliasing::() } @@ -776,9 +535,9 @@ mod _transitions { /// The caller promises that `self`'s referent conforms to the alignment /// invariant of `T` if required by `A`. #[inline] - pub(crate) unsafe fn assume_alignment( + pub(crate) const unsafe fn assume_alignment( self, - ) -> Ptr<'a, T, (I::Aliasing, A, I::Validity)> { + ) -> Ptr<'a, T, I::WithAlignment> { // SAFETY: The caller promises that `self`'s referent is // well-aligned for `T` if required by `A` . unsafe { self.assume_invariants() } @@ -788,11 +547,13 @@ mod _transitions { /// on success. pub(crate) fn bikeshed_try_into_aligned( self, - ) -> Result, AlignmentError> + ) -> Result>, AlignmentError> where T: Sized, { - if let Err(err) = crate::util::validate_aligned_to::<_, T>(self.as_non_null()) { + if let Err(err) = + crate::util::validate_aligned_to::<_, T>(self.as_inner().as_non_null()) + { return Err(err.with_src(self)); } @@ -804,9 +565,7 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub(crate) fn bikeshed_recall_aligned( - self, - ) -> Ptr<'a, T, (I::Aliasing, Aligned, I::Validity)> + pub(crate) const fn bikeshed_recall_aligned(self) -> Ptr<'a, T, I::WithAlignment> where T: crate::Unaligned, { @@ -825,9 +584,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub unsafe fn assume_validity( - self, - ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)> { + pub const unsafe fn assume_validity(self) -> Ptr<'a, T, I::WithValidity> { // SAFETY: The caller promises that `self`'s referent conforms to // the validity requirement of `V`. unsafe { self.assume_invariants() } @@ -842,9 +599,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub unsafe fn assume_initialized( - self, - ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)> { + pub const unsafe fn assume_initialized(self) -> Ptr<'a, T, I::WithValidity> { // SAFETY: The caller has promised to uphold the safety // preconditions. unsafe { self.assume_validity::() } @@ -859,7 +614,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub unsafe fn assume_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> { + pub const unsafe fn assume_valid(self) -> Ptr<'a, T, I::WithValidity> { // SAFETY: The caller has promised to uphold the safety // preconditions. unsafe { self.assume_validity::() } @@ -871,7 +626,7 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> + pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, I::WithValidity> where T: crate::FromBytes, I: Invariants, @@ -896,18 +651,18 @@ mod _transitions { /// On error, unsafe code may rely on this method's returned /// `ValidityError` containing `self`. #[inline] - pub(crate) fn try_into_valid( + pub(crate) fn try_into_valid( mut self, - ) -> Result, ValidityError> + ) -> Result>, ValidityError> where - T: TryFromBytes, - I::Aliasing: AtLeast, + T: TryFromBytes + Read, + I::Aliasing: Reference, I: Invariants, { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. - if T::is_bit_valid(self.reborrow().forget_aligned()) { + if T::is_bit_valid(self.reborrow().forget_aligned().unify_invariants()) { // SAFETY: If `T::is_bit_valid`, code may assume that `self` // contains a bit-valid instance of `Self`. Ok(unsafe { self.assume_valid() }) @@ -916,25 +671,12 @@ mod _transitions { } } - /// Forgets that `self`'s referent exclusively references `T`, - /// downgrading to a shared reference. - #[doc(hidden)] - #[must_use] - #[inline] - pub fn forget_exclusive(self) -> Ptr<'a, T, (Shared, I::Alignment, I::Validity)> - where - I::Aliasing: AtLeast, - { - // SAFETY: `I::Aliasing` is at least as restrictive as `Shared`. - unsafe { self.assume_invariants() } - } - /// Forgets that `self`'s referent is validly-aligned for `T`. #[doc(hidden)] #[must_use] #[inline] - pub fn forget_aligned(self) -> Ptr<'a, T, (I::Aliasing, Any, I::Validity)> { - // SAFETY: `Any` is less restrictive than `Aligned`. + pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment> { + // SAFETY: `Unknown` is less restrictive than `Aligned`. unsafe { self.assume_invariants() } } } @@ -943,18 +685,19 @@ mod _transitions { /// Casts of the referent type. mod _casts { use super::*; - use crate::{ - layout::{DstLayout, MetadataCastError}, - pointer::aliasing_safety::*, - AlignmentError, CastError, PointerMetadata, SizeError, - }; + use crate::{CastError, SizeError}; impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { - /// Casts to a different (unsized) target type. + /// Casts to a different (unsized) target type without checking interior + /// mutability. + /// + /// Callers should prefer [`cast_unsized`] where possible. + /// + /// [`cast_unsized`]: Ptr::cast_unsized /// /// # Safety /// @@ -962,19 +705,22 @@ mod _casts { /// following properties: /// - `u` addresses a subset of the bytes addressed by `p` /// - `u` has the same provenance as `p` - /// - If `I::Aliasing` is [`Any`] or [`Shared`], `UnsafeCell`s in `*u` - /// must exist at ranges identical to those at which `UnsafeCell`s - /// exist in `*p` + /// - If `I::Aliasing` is [`Shared`], `UnsafeCell`s in `*u` must exist + /// at ranges identical to those at which `UnsafeCell`s exist in `*p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized *mut U>( + pub unsafe fn cast_unsized_unchecked *mut U>( self, cast: F, - ) -> Ptr<'a, U, (I::Aliasing, Any, Any)> { - let ptr = cast(self.as_non_null().as_ptr()); + ) -> Ptr< + 'a, + U, + (I::Aliasing, Unknown, MappedValidity), + > { + let ptr = cast(self.as_inner().as_non_null().as_ptr()); // SAFETY: Caller promises that `cast` returns a pointer whose - // address is in the range of `self.as_non_null()`'s referent. By + // address is in the range of `self.as_inner().as_non_null()`'s referent. By // invariant, none of these addresses are null. let ptr = unsafe { NonNull::new_unchecked(ptr) }; @@ -982,7 +728,7 @@ mod _casts { // // Lemma 1: `ptr` has the same provenance as `self`. The caller // promises that `cast` preserves provenance, and we call it with - // `self.as_non_null()`. + // `self.as_inner().as_non_null()`. // // 0. By invariant, if `self`'s referent is not zero sized, then // `self` is derived from some valid Rust allocation, `A`. By @@ -1024,11 +770,51 @@ mod _casts { // pointer will permit mutation of this byte during `'a`, by // invariant on `self`, no other code assumes that this will // not happen. + // - `Inaccessible`: There are no restrictions we need to uphold. // 7. `ptr`, trivially, conforms to the alignment invariant of - // `Any`. - // 8. `ptr`, trivially, conforms to the validity invariant of `Any`. + // `Unknown`. + // 8. If `I::Validity = Unknown`, `AsInitialized`, or `Valid`, the + // output validity invariant is `Unknown`. `ptr` trivially + // conforms to this invariant. If `I::Validity = Initialized`, + // the output validity invariant is `Initialized`. Regardless of + // what subset of `self`'s referent is referred to by `ptr`, if + // all of `self`'s referent is initialized, then the same holds + // of `ptr`'s referent. unsafe { Ptr::new(ptr) } } + + /// Casts to a different (unsized) target type. + /// + /// # Safety + /// + /// The caller promises that `u = cast(p)` is a pointer cast with the + /// following properties: + /// - `u` addresses a subset of the bytes addressed by `p` + /// - `u` has the same provenance as `p` + #[doc(hidden)] + #[inline] + pub unsafe fn cast_unsized( + self, + cast: F, + ) -> Ptr< + 'a, + U, + (I::Aliasing, Unknown, MappedValidity), + > + where + T: Read, + U: 'a + ?Sized + Read, + F: FnOnce(*mut T) -> *mut U, + { + // SAFETY: Because `T` and `U` both implement `Read`, + // either: + // - `I::Aliasing` is `Exclusive` + // - `T` and `U` are both `Immutable`, in which case they trivially + // contain `UnsafeCell`s at identical locations + // + // The caller promises all other safety preconditions. + unsafe { self.cast_unsized_unchecked(cast) } + } } impl<'a, T, I> Ptr<'a, T, I> @@ -1040,10 +826,10 @@ mod _casts { #[allow(clippy::wrong_self_convention)] pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> where - [u8]: AliasingSafe, - R: AliasingSafeReason, + T: Read, + I::Aliasing: Reference, { - let bytes = match T::size_of_val_raw(self.as_non_null()) { + let bytes = match T::size_of_val_raw(self.as_inner().as_non_null()) { Some(bytes) => bytes, // SAFETY: `KnownLayout::size_of_val_raw` promises to always // return `Some` so long as the resulting size fits in a @@ -1058,10 +844,6 @@ mod _casts { // pointer's address, and `bytes` is the length of `p`, so the // returned pointer addresses the same bytes as `p` // - `slice_from_raw_parts_mut` and `.cast` both preserve provenance - // - Because `[u8]: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `T` and `[u8]` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations let ptr: Ptr<'a, [u8], _> = unsafe { self.cast_unsized(|p: *mut T| { #[allow(clippy::as_conversions)] @@ -1069,14 +851,7 @@ mod _casts { }) }; - let ptr = ptr.bikeshed_recall_aligned(); - - // SAFETY: `ptr`'s referent begins as `Initialized`, denoting that - // all bytes of the referent are initialized bytes. The referent - // type is then casted to `[u8]`, whose only validity invariant is - // that its bytes are initialized. This validity invariant is - // satisfied by the `Initialized` invariant on the starting `ptr`. - unsafe { ptr.assume_validity::() } + ptr.bikeshed_recall_aligned().bikeshed_recall_valid() } } @@ -1088,51 +863,17 @@ mod _casts { /// Casts this pointer-to-array into a slice. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_slice(self) -> Ptr<'a, [T], I> { - let start = self.as_non_null().cast::().as_ptr(); - let slice = core::ptr::slice_from_raw_parts_mut(start, N); - // SAFETY: `slice` is not null, because it is derived from `start` - // which is non-null. - let slice = unsafe { NonNull::new_unchecked(slice) }; - // SAFETY: Lemma: In the following safety arguments, note that - // `slice` is derived from `self` in two steps: first, by casting - // `self: [T; N]` to `start: T`, then by constructing a pointer to a - // slice starting at `start` of length `N`. As a result, `slice` - // references exactly the same allocation as `self`, if any. + let slice = self.as_inner().as_slice(); + // SAFETY: Note that, by post-condition on `PtrInner::as_slice`, + // `slice` refers to the same byte range as `self.as_inner()`. // - // 0. By the above lemma, if `slice`'s referent is not zero sized, - // then `slice` is derived from the same allocation as `self`, - // which, by invariant on `Ptr`, is valid. - // 1. By the above lemma, if `slice`'s referent is not zero sized, - // then , `slice` has valid provenance for `A`, since it is - // derived from the pointer `self`, which, by invariant on `Ptr`, - // has valid provenance for `A`. - // 2. By the above lemma, if `slice`'s referent is not zero sized, - // then `slice` addresses a byte range which is entirely - // contained in `A`, because it references exactly the same byte - // range as `self`, which, by invariant on `Ptr`, is entirely - // contained in `A`. - // 3. By the above lemma, `slice` addresses a byte range whose - // length fits in an `isize`, since it addresses exactly the same - // byte range as `self`, which, by invariant on `Ptr`, has a - // length that fits in an `isize`. - // 4. By the above lemma, `slice` addresses a byte range which does - // not wrap around the address space, since it addresses exactly - // the same byte range as `self`, which, by invariant on `Ptr`, - // does not wrap around the address space. - // 5. By the above lemma, if `slice`'s referent is not zero sized, - // then `A` is guaranteed to live for at least `'a`, because it - // is derived from the same allocation as `self`, which, by - // invariant on `Ptr`, lives for at least `'a`. - // 6. By the above lemma, `slice` conforms to the aliasing invariant - // of `I::Aliasing`, because the operations that produced `slice` - // from `self` do not impact aliasing. + // 6. Thus, `slice` conforms to the aliasing invariant of + // `I::Aliasing` because `self` does. // 7. By the above lemma, `slice` conforms to the alignment - // invariant of `I::Alignment`, because the operations that - // produced `slice` from `self` do not impact alignment. + // invariant of `I::Alignment` because `self` does. // 8. By the above lemma, `slice` conforms to the validity invariant - // of `I::Validity`, because the operations that produced `slice` - // from `self` do not impact validity. - unsafe { Ptr::new(slice) } + // of `I::Validity` because `self` does. + unsafe { Ptr::from_inner(slice) } } } @@ -1174,106 +915,48 @@ mod _casts { CastError, > where - R: AliasingSafeReason, - U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, + I::Aliasing: Reference, + U: 'a + ?Sized + KnownLayout + Read, { - let layout = match meta { - None => U::LAYOUT, - // This can return `None` if the metadata describes an object - // which can't fit in an `isize`. - Some(meta) => { - let size = match meta.size_for_metadata(U::LAYOUT) { - Some(size) => size, - None => return Err(CastError::Size(SizeError::new(self))), - }; - DstLayout { align: U::LAYOUT.align, size_info: crate::SizeInfo::Sized { size } } - } - }; - // PANICS: By invariant, the byte range addressed by `self.ptr` does - // not wrap around the address space. This implies that the sum of - // the address (represented as a `usize`) and length do not overflow - // `usize`, as required by `validate_cast_and_convert_metadata`. - // Thus, this call to `validate_cast_and_convert_metadata` will only - // panic if `U` is a DST whose trailing slice element is zero-sized. - let maybe_metadata = layout.validate_cast_and_convert_metadata( - AsAddress::addr(self.as_non_null().as_ptr()), - self.len(), - cast_type, - ); - - let (elems, split_at) = match maybe_metadata { - Ok((elems, split_at)) => (elems, split_at), - Err(MetadataCastError::Alignment) => { - // SAFETY: Since `validate_cast_and_convert_metadata` - // returned an alignment error, `U` must have an alignment - // requirement greater than one. - let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) }; - return Err(CastError::Alignment(err)); - } - Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))), - }; - - // SAFETY: `validate_cast_and_convert_metadata` promises to return - // `split_at <= self.len()`. - let (l_slice, r_slice) = unsafe { self.split_at(split_at) }; - - let (target, remainder) = match cast_type { - CastType::Prefix => (l_slice, r_slice), - CastType::Suffix => (r_slice, l_slice), - }; - - let base = target.as_non_null().cast::(); - - let elems = ::PointerMetadata::from_elem_count(elems); - // For a slice DST type, if `meta` is `Some(elems)`, then we - // synthesize `layout` to describe a sized type whose size is equal - // to the size of the instance that we are asked to cast. For sized - // types, `validate_cast_and_convert_metadata` returns `elems == 0`. - // Thus, in this case, we need to use the `elems` passed by the - // caller, not the one returned by - // `validate_cast_and_convert_metadata`. - let elems = meta.unwrap_or(elems); - - let ptr = U::raw_from_ptr_len(base, elems); + let (inner, remainder) = + self.as_inner().try_cast_into(cast_type, meta).map_err(|err| { + err.map_src(|inner| + // SAFETY: `PtrInner::try_cast_into` promises to return its + // original argument on error, which was originally produced + // by `self.as_inner()`, which is guaranteed to satisfy + // `Ptr`'s invariants. + unsafe { Ptr::from_inner(inner) }) + })?; // SAFETY: - // 0. By invariant, if `target`'s referent is not zero sized, then - // `target` is derived from some valid Rust allocation, `A`. By - // contract on `cast`, `ptr` is derived from `self`, and thus - // from the same valid Rust allocation, `A`. - // 1. By invariant, if `target`'s referent is not zero sized, then - // `target` has provenance valid for some Rust allocation, `A`. - // Because `ptr` is derived from `target` via - // provenance-preserving operations, `ptr` will also have - // provenance valid for `A`. - // - `validate_cast_and_convert_metadata` promises that the object - // described by `elems` and `split_at` lives at a byte range - // which is a subset of the input byte range. Thus: - // 2. Since, by invariant, if `target`'s referent is not zero - // sized, then `target` addresses a byte range which is - // entirely contained in `A`, so does `ptr`. - // 3. Since, by invariant, `target` addresses a byte range whose - // length fits in an `isize`, so does `ptr`. - // 4. Since, by invariant, `target` addresses a byte range which - // does not wrap around the address space, so does `ptr`. - // 5. Since, by invariant, if `target`'s referent is not zero - // sized, then `target` refers to an allocation which is - // guaranteed to live for at least `'a`, so does `ptr`. - // 6. Since `U: AliasingSafe<[u8], I::Aliasing, _>`, either: - // - `I::Aliasing` is `Exclusive`, in which case both `src` - // and `ptr` conform to `Exclusive` - // - `I::Aliasing` is `Shared` or `Any` and both `U` and - // `[u8]` are `Immutable`. In this case, neither pointer - // permits mutation, and so `Shared` aliasing is satisfied. - // 7. `ptr` conforms to the alignment invariant of `Aligned` because - // it is derived from `validate_cast_and_convert_metadata`, which - // promises that the object described by `target` is validly - // aligned for `U`. - // 8. By trait bound, `self` - and thus `target` - is a bit-valid + // 0. Since `U: Read`, either: + // - `I::Aliasing` is `Exclusive`, in which case both `src` and + // `ptr` conform to `Exclusive` + // - `I::Aliasing` is `Shared` or `Inaccessible` and `U` is + // `Immutable` (we already know that `[u8]: Immutable`). In + // this case, neither `U` nor `[u8]` permit mutation, and so + // `Shared` aliasing is satisfied. `Inaccessible` is trivially + // satisfied since it imposes no requirements. + // 1. `ptr` conforms to the alignment invariant of `Aligned` because + // it is derived from `try_cast_into`, which promises that the + // object described by `target` is validly aligned for `U`. + // 2. By trait bound, `self` - and thus `target` - is a bit-valid // `[u8]`. All bit-valid `[u8]`s have all of their bytes // initialized, so `ptr` conforms to the validity invariant of // `Initialized`. - Ok((unsafe { Ptr::new(ptr) }, remainder)) + let res = unsafe { Ptr::from_inner(inner) }; + + // SAFETY: + // 0. `self` and `remainder` both have the type `[u8]`. Thus, they + // have `UnsafeCell`s at the same locations. Type casting does + // not affect aliasing. + // 1. `[u8]` has no alignment requirement. + // 2. `self` has validity `Valid` and has type `[u8]`. Since + // `remainder` references a subset of `self`'s referent, it is + // also bit-valid. + let remainder = unsafe { Ptr::from_inner(remainder) }; + + Ok((res, remainder)) } /// Attempts to cast `self` into a `U`, failing if all of the bytes of @@ -1293,12 +976,9 @@ mod _casts { meta: Option, ) -> Result, CastError> where - U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, - R: AliasingSafeReason, + I::Aliasing: Reference, + U: 'a + ?Sized + KnownLayout + Read, { - // TODO(#67): Remove this allow. See NonNulSlicelExt for more - // details. - #[allow(unstable_name_collisions)] match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { if remainder.len() == 0 { @@ -1341,11 +1021,8 @@ mod _casts { #[must_use] #[inline(always)] pub fn get_mut(self) -> Ptr<'a, T, I> { - // SAFETY: - // - The closure uses an `as` cast, which preserves address range - // and provenance. - // - We require `I: Invariants`, so we are not - // required to uphold `UnsafeCell` equality. + // SAFETY: The closure uses an `as` cast, which preserves address + // range and provenance. #[allow(clippy::as_conversions)] let ptr = unsafe { self.cast_unsized(|p| p as *mut T) }; @@ -1380,11 +1057,6 @@ mod _casts { /// Projections through the referent. mod _project { - use core::ops::Range; - - #[allow(unused_imports)] - use crate::util::polyfills::NumExt as _; - use super::*; impl<'a, T, I> Ptr<'a, T, I> @@ -1396,42 +1068,36 @@ mod _project { /// /// # Safety /// - /// `project` has the same safety preconditions as `cast_unsized`. + /// `project` has the same safety preconditions as + /// `cast_unsized_unchecked`. #[doc(hidden)] #[inline] pub unsafe fn project( self, projector: impl FnOnce(*mut T) -> *mut U, - ) -> Ptr<'a, U, (I::Aliasing, Any, Initialized)> { + ) -> Ptr<'a, U, (I::Aliasing, Unknown, Initialized)> { // TODO(#1122): If `cast_unsized` were able to reason that, when // casting from an `Initialized` pointer, the result is another // `Initialized` pointer, we could remove this method entirely. // SAFETY: This method has the same safety preconditions as - // `cast_unsized`. - let ptr = unsafe { self.cast_unsized(projector) }; - - // SAFETY: If all of the bytes of `self` are initialized (as - // promised by `I: Invariants`), then any - // subset of those bytes are also all initialized. - unsafe { ptr.assume_validity::() } + // `cast_unsized_unchecked`. + unsafe { self.cast_unsized_unchecked(projector) } } } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, T, I> Ptr<'a, [T], I> where - T: 'a + KnownLayout + ?Sized, + T: 'a, I: Invariants, { - /// The number of trailing slice elements in the object referenced by - /// `self`. + /// The number of slice elements in the object referenced by `self`. /// /// # Safety /// - /// Unsafe code my rely on `trailing_slice_len` satisfying the above - /// contract. - pub(super) fn trailing_slice_len(&self) -> usize { - T::pointer_to_metadata(self.as_non_null().as_ptr()) + /// Unsafe code my rely on `len` satisfying the above contract. + pub(crate) fn len(&self) -> usize { + self.as_inner().len() } } @@ -1439,233 +1105,34 @@ mod _project { where T: 'a, I: Invariants, + I::Aliasing: Reference, { - /// The number of slice elements in the object referenced by `self`. - /// - /// # Safety - /// - /// Unsafe code my rely on `len` satisfying the above contract. - pub(crate) fn len(&self) -> usize { - self.trailing_slice_len() - } - - /// Creates a pointer which addresses the given `range` of self. - /// - /// # Safety - /// - /// `range` is a valid range (`start <= end`) and `end <= self.len()`. - pub(crate) unsafe fn slice_unchecked(self, range: Range) -> Self { - let base = self.as_non_null().cast::().as_ptr(); - - // SAFETY: The caller promises that `start <= end <= self.len()`. By - // invariant, if `self`'s referent is not zero-sized, then `self` - // refers to a byte range which is contained within a single - // allocation, which is no more than `isize::MAX` bytes long, and - // which does not wrap around the address space. Thus, this pointer - // arithmetic remains in-bounds of the same allocation, and does not - // wrap around the address space. The offset (in bytes) does not - // overflow `isize`. - // - // If `self`'s referent is zero-sized, then these conditions are - // trivially satisfied. - let base = unsafe { base.add(range.start) }; - - // SAFETY: The caller promises that `start <= end`, and so this will - // not underflow. - #[allow(unstable_name_collisions, clippy::incompatible_msrv)] - let len = unsafe { range.end.unchecked_sub(range.start) }; - - let ptr = core::ptr::slice_from_raw_parts_mut(base, len); - - // SAFETY: By invariant, `self`'s address is non-null and its range - // does not wrap around the address space. Since, by the preceding - // lemma, `ptr` addresses a range within that addressed by `self`, - // `ptr` is non-null. - let ptr = unsafe { NonNull::new_unchecked(ptr) }; - - // SAFETY: - // - // Lemma 0: `ptr` addresses a subset of the bytes addressed by - // `self`, and has the same provenance. - // Proof: The caller guarantees that `start <= end <= self.len()`. - // Thus, `base` is in-bounds of `self`, and `base + (end - - // start)` is also in-bounds of self. Finally, `ptr` is - // constructed using provenance-preserving operations. - // - // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is - // not zero sized, then `ptr` is derived from some valid Rust - // allocation, `A`. - // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is - // not zero sized, then `ptr` has valid provenance for `A`. - // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is - // not zero sized, then `ptr` addresses a byte range which is - // entirely contained in `A`. - // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte - // range whose length fits in an `isize`. - // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte - // range which does not wrap around the address space. - // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is - // not zero sized, then `A` is guaranteed to live for at least - // `'a`. - // 6. Per Lemma 0 and by invariant on `self`, `ptr` conforms to the - // aliasing invariant of [`I::Aliasing`](invariant::Aliasing). - // 7. Per Lemma 0 and by invariant on `self`, `ptr` conforms to the - // alignment invariant of [`I::Alignment`](invariant::Alignment). - // 8. Per Lemma 0 and by invariant on `self`, `ptr` conforms to the - // validity invariant of [`I::Validity`](invariant::Validity). - unsafe { Ptr::new(ptr) } - } - - /// Splits the slice in two. - /// - /// # Safety - /// - /// The caller promises that `l_len <= self.len()`. - pub(crate) unsafe fn split_at(self, l_len: usize) -> (Self, Self) { - // SAFETY: `Any` imposes no invariants, and so this is always sound. - let slf = unsafe { self.assume_aliasing::() }; - - // SAFETY: The caller promises that `l_len <= self.len()`. - // Trivially, `0 <= l_len`. - let left = unsafe { slf.slice_unchecked(0..l_len) }; - - // SAFETY: The caller promises that `l_len <= self.len() = - // slf.len()`. Trivially, `slf.len() <= slf.len()`. - let right = unsafe { slf.slice_unchecked(l_len..slf.len()) }; - - // LEMMA: `left` and `right` are non-overlapping. Proof: `left` is - // constructed from `slf` with `l_len` as its (exclusive) upper - // bound, while `right` is constructed from `slf` with `l_len` as - // its (inclusive) lower bound. Thus, no index is a member of both - // ranges. - - // SAFETY: By the preceding lemma, `left` and `right` do not alias. - // We do not construct any other `Ptr`s or references which alias - // `left` or `right`. Thus, the only `Ptr`s or references which - // alias `left` or `right` are outside of this method. By invariant, - // `self` obeys the aliasing invariant `I::Aliasing` with respect to - // those other `Ptr`s or references, and so `left` and `right` do as - // well. - let (left, right) = unsafe { - (left.assume_aliasing::(), right.assume_aliasing::()) - }; - (left.unify_invariants(), right.unify_invariants()) - } - /// Iteratively projects the elements `Ptr` from `Ptr<[T]>`. pub(crate) fn iter(&self) -> impl Iterator> { - // TODO(#429): Once `NonNull::cast` documents that it preserves - // provenance, cite those docs. - let base = self.as_non_null().cast::().as_ptr(); - (0..self.len()).map(move |i| { - // TODO(https://github.com/rust-lang/rust/issues/74265): Use - // `NonNull::get_unchecked_mut`. - - // SAFETY: If the following conditions are not satisfied - // `pointer::cast` may induce Undefined Behavior [1]: - // - // > - The computed offset, `count * size_of::()` bytes, must - // > not overflow `isize``. - // > - If the computed offset is non-zero, then `self` must be - // > derived from a pointer to some allocated object, and the - // > entire memory range between `self` and the result must be - // > in bounds of that allocated object. In particular, this - // > range must not “wrap around” the edge of the address - // > space. - // - // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add - // - // We satisfy both of these conditions here: - // - By invariant on `Ptr`, `self` addresses a byte range whose - // length fits in an `isize`. Since `elem` is contained in - // `self`, the computed offset of `elem` must fit within - // `isize.` - // - If the computed offset is non-zero, then this means that - // the referent is not zero-sized. In this case, `base` points - // to an allocated object (by invariant on `self`). Thus: - // - By contract, `self.len()` accurately reflects the number - // of elements in the slice. `i` is in bounds of `c.len()` - // by construction, and so the result of this addition - // cannot overflow past the end of the allocation referred - // to by `c`. - // - By invariant on `Ptr`, `self` addresses a byte range - // which does not wrap around the address space. Since - // `elem` is contained in `self`, the computed offset of - // `elem` must wrap around the address space. - // - // TODO(#429): Once `pointer::add` documents that it preserves - // provenance, cite those docs. - let elem = unsafe { base.add(i) }; - - // SAFETY: - // - `elem` must not be null. `base` is constructed from a - // `NonNull` pointer, and the addition that produces `elem` - // must not overflow or wrap around, so `elem >= base > 0`. - // - // TODO(#429): Once `NonNull::new_unchecked` documents that it - // preserves provenance, cite those docs. - let elem = unsafe { NonNull::new_unchecked(elem) }; - - // SAFETY: The safety invariants of `Ptr::new` (see definition) - // are satisfied: - // 0. If `elem`'s referent is not zero sized, then `elem` is - // derived from a valid Rust allocation, because `self` is - // derived from a valid Rust allocation, by invariant on - // `Ptr`. - // 1. If `elem`'s referent is not zero sized, then `elem` has - // valid provenance for `self`, because it derived from - // `self` using a series of provenance-preserving operations. - // 2. If `elem`'s referent is not zero sized, then `elem` is - // entirely contained in the allocation of `self` (see - // above). - // 3. `elem` addresses a byte range whose length fits in an - // `isize` (see above). - // 4. `elem` addresses a byte range which does not wrap around - // the address space (see above). - // 5. If `elem`'s referent is not zero sized, then the - // allocation of `elem` is guaranteed to live for at least - // `'a`, because `elem` is entirely contained in `self`, - // which lives for at least `'a` by invariant on `Ptr`. - // 6. `elem` conforms to the aliasing invariant of `I::Aliasing` - // because projection does not impact the aliasing invariant. - // 7. `elem`, conditionally, conforms to the validity invariant - // of `I::Alignment`. If `elem` is projected from data - // well-aligned for `[T]`, `elem` will be valid for `T`. - // 8. `elem`, conditionally, conforms to the validity invariant - // of `I::Validity`. If `elem` is projected from data valid - // for `[T]`, `elem` will be valid for `T`. - unsafe { Ptr::new(elem) } - }) + // SAFETY: + // 0. `elem` conforms to the aliasing invariant of `I::Aliasing` + // because projection does not impact the aliasing invariant. + // 1. `elem`, conditionally, conforms to the validity invariant of + // `I::Alignment`. If `elem` is projected from data well-aligned + // for `[T]`, `elem` will be valid for `T`. + // 2. `elem`, conditionally, conforms to the validity invariant of + // `I::Validity`. If `elem` is projected from data valid for + // `[T]`, `elem` will be valid for `T`. + self.as_inner().iter().map(|elem| unsafe { Ptr::from_inner(elem) }) } } } #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] mod tests { use core::mem::{self, MaybeUninit}; - use static_assertions::{assert_impl_all, assert_not_impl_any}; - use super::*; + #[allow(unused)] // Needed on our MSRV, but considered unused on later toolchains. + use crate::util::AsAddress; use crate::{pointer::BecauseImmutable, util::testutil::AU64, FromBytes, Immutable}; - #[test] - fn test_split_at() { - const N: usize = 16; - let mut arr = [1; N]; - let mut ptr = Ptr::from_mut(&mut arr).as_slice(); - for i in 0..=N { - assert_eq!(ptr.len(), N); - // SAFETY: `i` is in bounds by construction. - let (l, r) = unsafe { ptr.reborrow().split_at(i) }; - let l_sum: usize = l.iter().map(Ptr::read_unaligned).sum(); - let r_sum: usize = r.iter().map(Ptr::read_unaligned).sum(); - assert_eq!(l_sum, i); - assert_eq!(r_sum, N - i); - assert_eq!(l_sum + r_sum, N); - } - } - mod test_ptr_try_cast_into_soundness { use super::*; @@ -1751,7 +1218,8 @@ mod tests { #[allow(unstable_name_collisions)] let bytes_addr = bytes.as_ptr().addr(); #[allow(unstable_name_collisions)] - let remaining_addr = remaining.as_non_null().as_ptr().addr(); + let remaining_addr = + remaining.as_inner().as_non_null().as_ptr().addr(); match cast_type { CastType::Prefix => { assert_eq!(remaining_addr, bytes_addr + len) @@ -1761,7 +1229,7 @@ mod tests { if let Some(want) = meta { let got = KnownLayout::pointer_to_metadata( - slf.as_non_null().as_ptr(), + slf.as_inner().as_non_null().as_ptr(), ); assert_eq!(got, want); } @@ -1777,8 +1245,9 @@ mod tests { assert_eq!(len, bytes.len()); if let Some(want) = meta { - let got = - KnownLayout::pointer_to_metadata(slf.as_non_null().as_ptr()); + let got = KnownLayout::pointer_to_metadata( + slf.as_inner().as_non_null().as_ptr(), + ); assert_eq!(got, want); } } @@ -1837,21 +1306,6 @@ mod tests { test!(f32, f64); } - #[test] - fn test_invariants() { - // Test that the correct invariant relationships hold. - use super::invariant::*; - - assert_not_impl_any!(Any: AtLeast); - assert_impl_all!(Shared: AtLeast); - assert_impl_all!(Exclusive: AtLeast); - - assert_not_impl_any!(Any: AtLeast); - assert_impl_all!(AsInitialized: AtLeast); - assert_impl_all!(Initialized: AtLeast); - assert_impl_all!(Valid: AtLeast); - } - #[test] fn test_try_cast_into_explicit_count() { macro_rules! test { @@ -1863,7 +1317,7 @@ mod tests { if let Some(expect) = $expect { let (ptr, _) = res.unwrap(); assert_eq!( - KnownLayout::pointer_to_metadata(ptr.as_non_null().as_ptr()), + KnownLayout::pointer_to_metadata(ptr.as_inner().as_non_null().as_ptr()), expect ); } else { diff --git a/src/ref.rs b/src/ref.rs index 0f4ce00214..5a01b01442 100644 --- a/src/ref.rs +++ b/src/ref.rs @@ -75,7 +75,7 @@ mod def { /// [`deref`]: core::ops::Deref::deref /// [`deref_mut`]: core::ops::DerefMut::deref_mut /// [`into`]: core::convert::Into::into - pub(crate) unsafe fn new_unchecked(bytes: B) -> Ref { + pub(crate) const unsafe fn new_unchecked(bytes: B) -> Ref { // INVARIANTS: The caller has promised that `bytes`'s referent is // validly-aligned and has a valid size. Ref(bytes, PhantomData) diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index f7e66056d2..9d3f6ed77c 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -25,10 +25,7 @@ use core::mem::{self, ManuallyDrop}; use core::ptr::{self, NonNull}; use crate::{ - pointer::{ - invariant::{self, AtLeast, Invariants}, - AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable, - }, + pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; @@ -424,7 +421,7 @@ macro_rules! assert_align_gt_eq { #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! assert_size_eq { - ($t:ident, $u: ident) => {{ + ($t:ident, $u:ident) => {{ // The comments here should be read in the context of this macro's // invocations in `transmute_ref!` and `transmute_mut!`. if false { @@ -469,12 +466,7 @@ pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( // - The caller has guaranteed that alignment is not increased. // - We know that the returned lifetime will not outlive the input lifetime // thanks to the lifetime bounds on this function. - // - // TODO(#67): Once our MSRV is 1.58, replace this `transmute` with `&*dst`. - #[allow(clippy::transmute_ptr_to_ref)] - unsafe { - mem::transmute(dst) - } + unsafe { &*dst } } /// Transmutes a mutable reference of one type to a mutable reference of another @@ -528,15 +520,14 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( fn try_cast_or_pme( src: Ptr<'_, Src, I>, ) -> Result< - Ptr<'_, Dst, (I::Aliasing, invariant::Any, invariant::Valid)>, + Ptr<'_, Dst, (I::Aliasing, invariant::Unknown, invariant::Valid)>, ValidityError, Dst>, > where - Src: IntoBytes, - Dst: TryFromBytes + AliasingSafe, + Src: IntoBytes + invariant::Read, + Dst: TryFromBytes + invariant::Read, I: Invariants, - I::Aliasing: AtLeast, - R: AliasingSafeReason, + I::Aliasing: invariant::Reference, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); @@ -545,10 +536,6 @@ where // because we assert above that the size of `Dst` equal to the size of // `Src`. // - `p as *mut Dst` is a provenance-preserving cast - // - Because `Dst: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `Src` and `Dst` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations #[allow(clippy::as_conversions)] let c_ptr = unsafe { src.cast_unsized(|p| p as *mut Dst) }; @@ -568,10 +555,6 @@ where // `ptr`, because we assert above that the size of `Dst` is equal // to the size of `Src`. // - `p as *mut Src` is a provenance-preserving cast - // - Because `Dst: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `Src` and `Dst` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations #[allow(clippy::as_conversions)] let ptr = unsafe { ptr.cast_unsized(|p| p as *mut Src) }; // SAFETY: `ptr` is `src`, and has the same alignment invariant. diff --git a/src/util/macros.rs b/src/util/macros.rs index af751e7523..263fde6ac7 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -52,10 +52,6 @@ macro_rules! safety_comment { /// referred to by `t`. /// - `r` refers to an object with `UnsafeCell`s at the same byte ranges as /// the object referred to by `t`. -/// - If the provided closure takes a `&$repr` argument, then given a `Ptr<'a, -/// $ty>` which satisfies the preconditions of -/// `TryFromBytes::<$ty>::is_bit_valid`, it must be guaranteed that the -/// memory referenced by that `Ptr` always contains a valid `$repr`. /// - The impl of `is_bit_valid` must only return `true` for its argument /// `Ptr<$repr>` if the original `Ptr<$ty>` refers to a valid `$ty`. macro_rules! unsafe_impl { @@ -141,7 +137,7 @@ macro_rules! unsafe_impl { fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] - fn is_bit_valid>(candidate: Maybe<'_, Self, AA>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { // SAFETY: // - The cast preserves address. The caller has promised that the // cast results in an object of equal or lesser size, and so the @@ -151,11 +147,9 @@ macro_rules! unsafe_impl { // - The caller has promised that the destination type has // `UnsafeCell`s at the same byte ranges as the source type. #[allow(clippy::as_conversions)] - let candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) }; + let candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; - // SAFETY: The caller has promised that the referenced memory region - // will contain a valid `$repr`. - let $candidate = unsafe { candidate.assume_validity::() }; + let $candidate = candidate.bikeshed_recall_valid(); $is_bit_valid } }; @@ -165,7 +159,7 @@ macro_rules! unsafe_impl { fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] - fn is_bit_valid>(candidate: Maybe<'_, Self, AA>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { // SAFETY: // - The cast preserves address. The caller has promised that the // cast results in an object of equal or lesser size, and so the @@ -175,12 +169,7 @@ macro_rules! unsafe_impl { // - The caller has promised that the destination type has // `UnsafeCell`s at the same byte ranges as the source type. #[allow(clippy::as_conversions)] - let $candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) }; - - // Restore the invariant that the referent bytes are initialized. - // SAFETY: The above cast does not uninitialize any referent bytes; - // they remain initialized. - let $candidate = unsafe { $candidate.assume_validity::() }; + let $candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; $is_bit_valid } @@ -189,7 +178,7 @@ macro_rules! unsafe_impl { #[allow(clippy::missing_inline_in_public_items)] #[cfg_attr(coverage_nightly, coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() {} - #[inline(always)] fn is_bit_valid>(_: Maybe<'_, Self, A>) -> bool { true } + #[inline(always)] fn is_bit_valid(_: Maybe<'_, Self, AA>) -> bool { true } }; (@method $trait:ident) => { #[allow(clippy::missing_inline_in_public_items)] @@ -255,7 +244,7 @@ macro_rules! impl_for_transparent_wrapper { impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); #[cfg_attr(coverage_nightly, coverage(off))] - fn f() { + const fn f() { is_transparent_wrapper::(); } } @@ -327,7 +316,7 @@ macro_rules! impl_for_transparent_wrapper { }; (@define_is_transparent_wrapper $trait:ident, $variance:ident) => { #[cfg_attr(coverage_nightly, coverage(off))] - fn is_transparent_wrapper + ?Sized>() + const fn is_transparent_wrapper + ?Sized>() where W::Inner: $trait, {} @@ -341,7 +330,7 @@ macro_rules! impl_for_transparent_wrapper { // TryFromBytes)` macro arm for an explanation of why this is a sound // implementation of `is_bit_valid`. #[inline] - fn is_bit_valid>(candidate: Maybe<'_, Self, A>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { TryFromBytes::is_bit_valid(candidate.transparent_wrapper_into_inner()) } }; @@ -615,109 +604,9 @@ macro_rules! assert_unaligned { }; } -/// Emits a function definition as either `const fn` or `fn` depending on -/// whether the current toolchain version supports `const fn` with generic trait -/// bounds. -macro_rules! maybe_const_trait_bounded_fn { - // This case handles both `self` methods (where `self` is by value) and - // non-method functions. Each `$args` may optionally be followed by `: - // $arg_tys:ty`, which can be omitted for `self`. - ($(#[$attr:meta])* $vis:vis const fn $name:ident($($args:ident $(: $arg_tys:ty)?),* $(,)?) $(-> $ret_ty:ty)? $body:block) => { - #[cfg(zerocopy_generic_bounds_in_const_fn)] - $(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body - - #[cfg(not(zerocopy_generic_bounds_in_const_fn))] - $(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body - }; -} - -/// Either panic (if the current Rust toolchain supports panicking in `const -/// fn`) or evaluate a constant that will cause an array indexing error whose -/// error message will include the format string. -/// -/// The type that this expression evaluates to must be `Copy`, or else the -/// non-panicking desugaring will fail to compile. -macro_rules! const_panic { - (@non_panic $($_arg:tt)+) => {{ - // This will type check to whatever type is expected based on the call - // site. - let panic: [_; 0] = []; - // This will always fail (since we're indexing into an array of size 0. - #[allow(unconditional_panic)] - panic[0] - }}; - ($($arg:tt)+) => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - panic!($($arg)+); - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - const_panic!(@non_panic $($arg)+) - }}; -} - -/// Either assert (if the current Rust toolchain supports panicking in `const -/// fn`) or evaluate the expression and, if it evaluates to `false`, call -/// `const_panic!`. This is used in place of `assert!` in const contexts to -/// accommodate old toolchains. -macro_rules! const_assert { - ($e:expr) => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - assert!($e); - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - { - let e = $e; - if !e { - let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e))); - } - } - }}; - ($e:expr, $($args:tt)+) => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - assert!($e, $($args)+); - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - { - let e = $e; - if !e { - let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e), ": ", stringify!($arg)), $($args)*); - } - } - }}; -} - -/// Like `const_assert!`, but relative to `debug_assert!`. -macro_rules! const_debug_assert { - ($e:expr $(, $msg:expr)?) => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - debug_assert!($e $(, $msg)?); - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - { - // Use this (rather than `#[cfg(debug_assertions)]`) to ensure that - // `$e` is always compiled even if it will never be evaluated at - // runtime. - if cfg!(debug_assertions) { - let e = $e; - if !e { - let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e) $(, ": ", $msg)?)); - } - } - } - }} -} - -/// Either invoke `unreachable!()` or `loop {}` depending on whether the Rust -/// toolchain supports panicking in `const fn`. -macro_rules! const_unreachable { - () => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - unreachable!(); - - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - loop {} - }}; -} - /// Asserts at compile time that `$condition` is true for `Self` or the given -/// `$tyvar`s. Unlike `const_assert`, this is *strictly* a compile-time check; -/// it cannot be evaluated in a runtime context. The condition is checked after +/// `$tyvar`s. Unlike `assert!`, this is *strictly* a compile-time check; it +/// cannot be evaluated in a runtime context. The condition is checked after /// monomorphization and, upon failure, emits a compile error. macro_rules! static_assert { (Self $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? => $condition:expr $(, $args:tt)*) => {{ @@ -727,12 +616,12 @@ macro_rules! static_assert { impl StaticAssert for T { const ASSERT: bool = { - const_assert!($condition $(, $args)*); + assert!($condition $(, $args)*); $condition }; } - const_assert!(::ASSERT); + assert!(::ASSERT); }}; ($($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $condition:expr $(, $args:tt)*) => {{ trait StaticAssert { @@ -741,12 +630,12 @@ macro_rules! static_assert { impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?,)*> StaticAssert for ($($tyvar,)*) { const ASSERT: bool = { - const_assert!($condition $(, $args)*); + assert!($condition $(, $args)*); $condition }; } - const_assert!(<($($tyvar,)*) as StaticAssert>::ASSERT); + assert!(<($($tyvar,)*) as StaticAssert>::ASSERT); }}; } @@ -766,3 +655,14 @@ macro_rules! static_assert_dst_is_not_zst { }, "cannot call this method on a dynamically-sized type whose trailing slice element is zero-sized"); }} } + +macro_rules! define_because { + ($(#[$attr:meta])* $vis:vis $name:ident) => { + #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] + $(#[$attr])* + $vis type $name = (); + #[cfg(not(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS))] + $(#[$attr])* + $vis enum $name {} + }; +} diff --git a/src/util/mod.rs b/src/util/mod.rs index a05700cf02..2143f0ada8 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -23,7 +23,7 @@ use core::{ use crate::{ error::AlignmentError, pointer::invariant::{self, Invariants}, - Unalign, + TrailingSliceLayout, Unalign, }; /// A type which has the same layout as the type it wraps. @@ -99,11 +99,11 @@ impl ValidityVariance for Covariant { pub enum Invariant {} impl AlignmentVariance for Invariant { - type Applied = invariant::Any; + type Applied = invariant::Unknown; } impl ValidityVariance for Invariant { - type Applied = invariant::Any; + type Applied = invariant::Unknown; } // SAFETY: @@ -373,15 +373,12 @@ unsafe impl TransparentWrapper for Unalign { /// /// The caller promises that `$atomic` is an atomic type whose natie equivalent /// is `$native`. -#[cfg(all( - zerocopy_target_has_atomics, - any( - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr" - ) +#[cfg(any( + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr" ))] macro_rules! unsafe_impl_transparent_wrapper_for_atomic { ($(#[$attr:meta])* $(,)?) => {}; @@ -484,8 +481,8 @@ unsafe impl Send for SendSyncPhantomData {} // to be called from multiple threads. unsafe impl Sync for SendSyncPhantomData {} -impl Default for SendSyncPhantomData { - fn default() -> SendSyncPhantomData { +impl SendSyncPhantomData { + pub(crate) const fn new() -> SendSyncPhantomData { SendSyncPhantomData(PhantomData) } } @@ -635,7 +632,6 @@ pub(crate) const fn round_down_to_next_multiple_of_alignment( align: NonZeroUsize, ) -> usize { let align = align.get(); - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] debug_assert!(align.is_power_of_two()); // Subtraction can't underflow because `align.get() >= 1`. @@ -683,6 +679,107 @@ pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) { }; } +pub(crate) const fn metadata_from_elem_count( + elems: usize, +) -> T::PointerMetadata { + use crate::layout::SizeInfo; + + // SAFETY: Per `KnownLayout::PointerMetadata`: + // + // # Safety + // + // Callers may assume for soundness that one of the following holds: + // - `Self::LAYOUT.size_info` is a `SizeInfo::Sized` and + // `Self::PointerMetadata = ()` + // - `Self::LAYOUT.size_info` is a `SizeInfo::SliceDst` and + // `Self::PointerMetadata = usize` + // + // In the following branches, we only transmute as consistent with this + // invariant. + match T::LAYOUT.size_info { + SizeInfo::Sized { .. } => unsafe { transmute::<(), T::PointerMetadata>(()) }, + SizeInfo::SliceDst(_) => unsafe { transmute::(elems) }, + } +} + +/// Computes the size of the `T` with the given pointer metadata. +/// +/// # Safety +/// +/// `size_for_metadata` promises to only return `None` if the resulting size +/// would not fit in a `usize`. +pub(crate) const fn size_for_metadata( + meta: T::PointerMetadata, +) -> Option { + use crate::layout::{SizeInfo, TrailingSliceLayout}; + + match T::LAYOUT.size_info { + SizeInfo::Sized { size } => Some(size), + // NOTE: This branch is unreachable, but we return `None` rather + // than `unreachable!()` to avoid generating panic paths. + SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) => { + // SAFETY: Per `KnownLayout::PointerMetadata`: + // + // Callers may assume for soundness that one of the following + // holds: + // ... + // - `Self::LAYOUT.size_info` is a `SizeInfo::SliceDst` and + // `Self::PointerMetadata = usize` + // + // Since, in this branch, we know that `T::LAYOUT.size_info = + // SizeInfo::SliceDst`, we can assume that `T::PointerMetadata = + // usize`. + let count: usize = unsafe { transmute(meta) }; + let Some(slice_len) = elem_size.checked_mul(count) else { return None }; + let Some(without_padding) = offset.checked_add(slice_len) else { return None }; + without_padding + .checked_add(crate::util::padding_needed_for(without_padding, T::LAYOUT.align)) + } + } +} + +/// Casts a `*mut Src` to a `*mut Dst`. +/// +/// # Safety +/// +/// The caller must ensure that `Src` and `Dst` must either both be `Sized` or +/// both be unsized. +#[inline(always)] +pub(crate) const unsafe fn cast_unchecked(src: *mut Src) -> *mut Dst { + // TODO(https://github.com/rust-lang/reference/pull/1661): Add safety + // comment once this lands. + unsafe { transmute(src) } +} + +/// Like [`core::mem::transmute`], but works on generic types and types of +/// different sizes. +/// +/// # Safety +/// +/// The caller must ensure that reinterpreting the bytes of `src` as a `Dst` is +/// sound, including if `Src` and `Dst` are different sizes. +const unsafe fn transmute(src: Src) -> Dst { + use core::mem::ManuallyDrop; + + #[repr(C)] + union Transmute { + src: ManuallyDrop, + dst: ManuallyDrop, + } + + // SAFETY: The caller promises that performing this transmute is sound. + // Since `Transmute` is a `#[repr(C)]` union, both `src` and `dst` are at + // byte offset 0 within `Transmute` [1], and so this is equivalent to + // transmuting a `ManuallyDrop` into a `ManuallyDrop`. Since + // `ManuallyDrop` has the same layout as `T` [2], this is equivalent to + // transmuting `src` directly into `dst`. + // + // [1] TODO + // + // [2] TODO + ManuallyDrop::into_inner(unsafe { Transmute { src: ManuallyDrop::new(src) }.dst }) +} + /// Since we support multiple versions of Rust, there are often features which /// have been stabilized in the most recent stable release which do not yet /// exist (stably) on our MSRV. This module provides polyfills for those @@ -729,7 +826,7 @@ pub(crate) mod polyfills { // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent // method rather than to this trait, and so this trait is considered unused. // - // TODO(#67): Once our MSRV is high enough, remove this. + // TODO(#67): Once our MSRV is >= 1.79, remove this. #[allow(unused)] pub(crate) trait NumExt { /// Subtract without checking for underflow. @@ -760,6 +857,7 @@ pub(crate) mod polyfills { } #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] pub(crate) mod testutil { use crate::*; @@ -849,6 +947,7 @@ pub(crate) mod testutil { } #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] mod tests { use super::*; @@ -869,10 +968,9 @@ mod tests { } } - #[rustversion::since(1.57.0)] #[test] #[should_panic] - fn test_round_down_to_next_multiple_of_alignment_zerocopy_panic_in_const_and_vec_try_reserve() { + fn test_round_down_to_next_multiple_of_alignment_panics() { round_down_to_next_multiple_of_alignment(0, NonZeroUsize::new(3).unwrap()); } } diff --git a/src/wrappers.rs b/src/wrappers.rs index 0637d76025..ac2442486e 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -239,11 +239,7 @@ impl Unalign { // but the caller has promised that `self` is properly aligned, so we // know that it is sound to create a reference to `T` at this memory // location. - // - // We use `mem::transmute` instead of `&*self.get_ptr()` because - // dereferencing pointers is not stable in `const` on our current MSRV - // (1.56 as of this writing). - unsafe { mem::transmute(self) } + unsafe { &*self.get_ptr() } } /// Returns a mutable reference to the wrapped `T` without checking @@ -393,9 +389,8 @@ impl Unalign { impl Unalign { /// Gets a copy of the inner `T`. - // TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`. #[inline(always)] - pub fn get(&self) -> T { + pub const fn get(&self) -> T { let Unalign(val) = *self; val } @@ -525,7 +520,7 @@ mod tests { let au64 = unsafe { x.t.deref_unchecked() }; match au64 { AU64(123) => {} - _ => const_unreachable!(), + _ => unreachable!(), } }; } diff --git a/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr b/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr index 8c7294f7fd..239c69f696 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie 18 | takes_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others note: required by a bound in `takes_from_bytes` --> tests/ui-msrv/diagnostic-not-implemented-from-bytes.rs:21:24 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr b/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr index 894701e17e..03afed0604 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied 18 | takes_from_zeros::(); | ^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `takes_from_zeros` --> tests/ui-msrv/diagnostic-not-implemented-from-zeros.rs:21:24 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr b/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr index d0093ad8a1..4b64f94ffb 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfie 18 | takes_immutable::(); | ^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others note: required by a bound in `takes_immutable` --> tests/ui-msrv/diagnostic-not-implemented-immutable.rs:21:23 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr b/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr index c2959ef8b8..961d77fbad 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfie 18 | takes_into_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `takes_into_bytes` --> tests/ui-msrv/diagnostic-not-implemented-into-bytes.rs:21:24 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr b/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr index 0475a6499e..966dc9fe85 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr @@ -2,10 +2,42 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfie --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); - | ^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` + | --------- ^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` + | | + | required by a bound introduced by this call + | +note: required by a bound in `Foo::write_obj` + --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:58:21 + | +58 | fn write_obj(&mut self, _val: T) {} + | ^^^^^^^^^ required by this bound in `Foo::write_obj` +help: consider borrowing here + | +52 | Foo.write_obj(&NotZerocopy(())); + | + +52 | Foo.write_obj(&mut NotZerocopy(())); + | ++++ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); - | ^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | --------- ^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `Foo::write_obj` + --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:58:33 + | +58 | fn write_obj(&mut self, _val: T) {} + | ^^^^^^^^^ required by this bound in `Foo::write_obj` diff --git a/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr b/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr index d3cfd29c6c..4fc50b9f2e 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisf 18 | takes_known_layout::(); | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::KnownLayout`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `takes_known_layout` --> tests/ui-msrv/diagnostic-not-implemented-known-layout.rs:21:26 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr b/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr index 8e27c9c8cb..09bb2f7399 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 18 | takes_try_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `takes_try_from_bytes` --> tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.rs:21:28 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr b/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr index bde813f691..a7607ce872 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied 18 | takes_unaligned::(); | ^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others note: required by a bound in `takes_unaligned` --> tests/ui-msrv/diagnostic-not-implemented-unaligned.rs:21:23 | diff --git a/tests/ui-msrv/include_value_not_from_bytes.stderr b/tests/ui-msrv/include_value_not_from_bytes.stderr index 14dd22a71a..9e42493e43 100644 --- a/tests/ui-msrv/include_value_not_from_bytes.stderr +++ b/tests/ui-msrv/include_value_not_from_bytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not sat --> tests/ui-msrv/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | -note: required by `AssertIsFromBytes` + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertIsFromBytes` --> tests/ui-msrv/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/include_value_wrong_size.stderr b/tests/ui-msrv/include_value_wrong_size.stderr index b4531c7fa5..d564e20f91 100644 --- a/tests/ui-msrv/include_value_wrong_size.stderr +++ b/tests/ui-msrv/include_value_wrong_size.stderr @@ -6,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `[u8; 4]` (32 bits) = note: target type: `u64` (64 bits) - = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/invalid-impls/invalid-impls.stderr b/tests/ui-msrv/invalid-impls/invalid-impls.stderr index 7e9765e6be..29e98d64ce 100644 --- a/tests/ui-msrv/invalid-impls/invalid-impls.stderr +++ b/tests/ui-msrv/invalid-impls/invalid-impls.stderr @@ -7,9 +7,9 @@ error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:26:1 | 26 | impl_or_verify!(T => TryFromBytes for Foo); - | ---------------------------------------------- in this macro invocation + | --------------------------------------------- in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::TryFromBytes` for `Foo` +note: required for `Foo` to implement `zerocopy::TryFromBytes` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -23,11 +23,12 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:26:1 | 26 | impl_or_verify!(T => TryFromBytes for Foo); - | ---------------------------------------------- in this macro invocation + | --------------------------------------------- in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -26 | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); + | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); | ++++++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied @@ -39,9 +40,9 @@ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:1 | 27 | impl_or_verify!(T => FromZeros for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::FromZeros` for `Foo` +note: required for `Foo` to implement `zerocopy::FromZeros` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -55,11 +56,12 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:1 | 27 | impl_or_verify!(T => FromZeros for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -27 | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); + | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied @@ -71,9 +73,9 @@ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:1 | 28 | impl_or_verify!(T => FromBytes for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::FromBytes` for `Foo` +note: required for `Foo` to implement `zerocopy::FromBytes` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -87,11 +89,12 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:1 | 28 | impl_or_verify!(T => FromBytes for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -28 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); + | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied @@ -103,9 +106,9 @@ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:1 | 29 | impl_or_verify!(T => IntoBytes for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::IntoBytes` for `Foo` +note: required for `Foo` to implement `zerocopy::IntoBytes` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:21 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -119,11 +122,12 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:1 | 29 | impl_or_verify!(T => IntoBytes for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -29 | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); + | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied @@ -135,9 +139,9 @@ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:30:1 | 30 | impl_or_verify!(T => Unaligned for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::Unaligned` for `Foo` +note: required for `Foo` to implement `zerocopy::Unaligned` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:32 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -151,9 +155,10 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:30:1 | 30 | impl_or_verify!(T => Unaligned for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -30 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); + | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); | +++++++++++++++++++++ diff --git a/tests/ui-msrv/transmute-dst-not-frombytes.stderr b/tests/ui-msrv/transmute-dst-not-frombytes.stderr index 744cb48da0..bc351bf725 100644 --- a/tests/ui-msrv/transmute-dst-not-frombytes.stderr +++ b/tests/ui-msrv/transmute-dst-not-frombytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-msrv/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); - | ^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | -note: required by `AssertIsFromBytes` + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertIsFromBytes` --> tests/ui-msrv/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-alignment-increase.stderr b/tests/ui-msrv/transmute-mut-alignment-increase.stderr index 7b771b8521..15561e68b2 100644 --- a/tests/ui-msrv/transmute-mut-alignment-increase.stderr +++ b/tests/ui-msrv/transmute-mut-alignment-increase.stderr @@ -6,30 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: mutable references are not allowed in constants - --> tests/ui-msrv/transmute-mut-alignment-increase.rs:20:54 - | -20 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); - | ^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> tests/ui-msrv/transmute-mut-alignment-increase.rs:20:39 - | -20 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0716]: temporary value dropped while borrowed - --> tests/ui-msrv/transmute-mut-alignment-increase.rs:20:59 - | -20 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); - | --------------------^^^^^^^^- - | | | - | | creates a temporary which is freed while still in use - | temporary value is freed at the end of this statement - | using this value as a constant requires that borrow lasts for `'static` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-const.stderr b/tests/ui-msrv/transmute-mut-const.stderr index 8578fa1932..91c88fb337 100644 --- a/tests/ui-msrv/transmute-mut-const.stderr +++ b/tests/ui-msrv/transmute-mut-const.stderr @@ -11,7 +11,7 @@ note: `const` item defined here --> tests/ui-msrv/transmute-mut-const.rs:17:1 | 17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0658]: mutable references are not allowed in constants --> tests/ui-msrv/transmute-mut-const.rs:20:52 @@ -21,12 +21,13 @@ error[E0658]: mutable references are not allowed in constants | = note: see issue #57349 for more information -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], [u8; 2]>` in constants --> tests/ui-msrv/transmute-mut-const.rs:20:37 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0716]: temporary value dropped while borrowed diff --git a/tests/ui-msrv/transmute-mut-dst-generic.stderr b/tests/ui-msrv/transmute-mut-dst-generic.stderr index f6b54ce1c2..28edcf15eb 100644 --- a/tests/ui-msrv/transmute-mut-dst-generic.stderr +++ b/tests/ui-msrv/transmute-mut-dst-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `T` (this type does not have a fixed size) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-mut-dst-generic.rs:17:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (8 bits) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr b/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr index eaff00fd27..97a3f4a8d7 100644 --- a/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr +++ b/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr @@ -42,8 +42,16 @@ error[E0308]: mismatched types --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected `usize`, found `&mut _` + | arguments to this function are incorrect | = note: expected type `usize` found mutable reference `&mut _` +note: function defined here + --> src/util/macro_util.rs + | + | pub const fn must_use(t: T) -> T { + | ^^^^^^^^ = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr b/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr index 3f92e0d4e4..7d6b7a086e 100644 --- a/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr +++ b/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38 | 24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call | -note: required by `AssertDstIsFromBytes` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertDstIsFromBytes` --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38 | 24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr b/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr index 4ceffcd010..a4d1cf86f9 100644 --- a/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr +++ b/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-mut-dst-not-intobytes.rs:24:36 | 24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call | -note: required by `AssertDstIsIntoBytes` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsIntoBytes` --> tests/ui-msrv/transmute-mut-dst-not-intobytes.rs:24:36 | 24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-dst-unsized.stderr b/tests/ui-msrv/transmute-mut-dst-unsized.stderr index e54fac982c..de5a4f2363 100644 --- a/tests/ui-msrv/transmute-mut-dst-unsized.stderr +++ b/tests/ui-msrv/transmute-mut-dst-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertDstIsSized` +note: required by a bound in `AssertDstIsSized` --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -35,7 +38,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 @@ -49,35 +52,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 - | -17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` - --> src/util/macro_util.rs - | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 diff --git a/tests/ui-msrv/transmute-mut-size-decrease.stderr b/tests/ui-msrv/transmute-mut-size-decrease.stderr index ee3261ed28..6a2dbdab53 100644 --- a/tests/ui-msrv/transmute-mut-size-decrease.stderr +++ b/tests/ui-msrv/transmute-mut-size-decrease.stderr @@ -6,30 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `[u8; 2]` (16 bits) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: mutable references are not allowed in constants - --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:47 - | -17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); - | ^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:32 - | -17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0716]: temporary value dropped while borrowed - --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:52 - | -17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); - | --------------------^^^^^^^^- - | | | - | | creates a temporary which is freed while still in use - | temporary value is freed at the end of this statement - | using this value as a constant requires that borrow lasts for `'static` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-size-increase.stderr b/tests/ui-msrv/transmute-mut-size-increase.stderr index 242493ff0a..06ec48d72a 100644 --- a/tests/ui-msrv/transmute-mut-size-increase.stderr +++ b/tests/ui-msrv/transmute-mut-size-increase.stderr @@ -6,30 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: mutable references are not allowed in constants - --> tests/ui-msrv/transmute-mut-size-increase.rs:17:52 - | -17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); - | ^^^^^^^^ - | - = note: see issue #57349 for more information - -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> tests/ui-msrv/transmute-mut-size-increase.rs:17:37 - | -17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0716]: temporary value dropped while borrowed - --> tests/ui-msrv/transmute-mut-size-increase.rs:17:57 - | -17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); - | --------------------^^^- - | | | - | | creates a temporary which is freed while still in use - | temporary value is freed at the end of this statement - | using this value as a constant requires that borrow lasts for `'static` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-src-dst-generic.stderr b/tests/ui-msrv/transmute-mut-src-dst-generic.stderr index f41be15ad3..f96b268786 100644 --- a/tests/ui-msrv/transmute-mut-src-dst-generic.stderr +++ b/tests/ui-msrv/transmute-mut-src-dst-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `T` (this type does not have a fixed size) = note: target type: `U` (this type does not have a fixed size) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-mut-src-dst-generic.rs:20:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (size can vary because of T) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr b/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr index ff2d7d198d..c1ca231f44 100644 --- a/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr +++ b/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertSrcIsSized` +note: required by a bound in `AssertSrcIsSized` --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -30,14 +33,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertDstIsSized` +note: required by a bound in `AssertDstIsSized` --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -55,7 +61,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute` @@ -63,16 +72,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AlignOf::::into_t` + --> src/util/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -82,7 +99,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -96,35 +113,24 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` - --> src/util/macro_util.rs - | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 - | -17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -138,7 +144,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -152,21 +158,7 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 - | -17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -191,13 +183,33 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/util/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute_mut` diff --git a/tests/ui-msrv/transmute-mut-src-generic.stderr b/tests/ui-msrv/transmute-mut-src-generic.stderr index 319fc27a8b..b230f68eaa 100644 --- a/tests/ui-msrv/transmute-mut-src-generic.stderr +++ b/tests/ui-msrv/transmute-mut-src-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `T` (this type does not have a fixed size) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-mut-src-generic.rs:17:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (size can vary because of T) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr b/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr index ebb8e0bafe..19fd0ce496 100644 --- a/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr +++ b/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `Src: FromBytes` is not satisfied --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 | 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by `AssertSrcIsFromBytes` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 | 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: FromBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `Src: FromBytes` is not satisfied 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` | + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others note: required by a bound in `AssertSrcIsFromBytes` --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 | diff --git a/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr b/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr index 7522b32a69..0691557aa1 100644 --- a/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr +++ b/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `Src: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-mut-src-not-intobytes.rs:24:36 | 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by `AssertSrcIsIntoBytes` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-mut-src-not-intobytes.rs:24:36 | 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: IntoBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `Src: IntoBytes` is not satisfied 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` | + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-mut-src-not-intobytes.rs:24:36 | diff --git a/tests/ui-msrv/transmute-mut-src-unsized.stderr b/tests/ui-msrv/transmute-mut-src-unsized.stderr index df471dc458..e71157fe11 100644 --- a/tests/ui-msrv/transmute-mut-src-unsized.stderr +++ b/tests/ui-msrv/transmute-mut-src-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertSrcIsSized` +note: required by a bound in `AssertSrcIsSized` --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -41,7 +44,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute` @@ -49,16 +55,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AlignOf::::into_t` + --> src/util/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 @@ -68,7 +82,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 @@ -82,21 +96,24 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 @@ -110,21 +127,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 - | -16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 @@ -138,27 +141,16 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 - | -16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute_mut` @@ -167,13 +159,3 @@ note: required by a bound in `transmute_mut` | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( | ^^^ required by this bound in `transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 - | -16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` - = note: all function arguments must have a statically known size - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ptr-to-usize.stderr b/tests/ui-msrv/transmute-ptr-to-usize.stderr index 81d60c71a1..603e06914e 100644 --- a/tests/ui-msrv/transmute-ptr-to-usize.stderr +++ b/tests/ui-msrv/transmute-ptr-to-usize.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `*const usize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `*const usize` + | required by a bound introduced by this call | -note: required by `AssertIsIntoBytes` + = help: the following other types implement trait `IntoBytes`: + f32 + f64 + i128 + i16 + i32 + i64 + i8 + isize + and $N others +note: required by a bound in `AssertIsIntoBytes` --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsIntoBytes` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `*const usize` | + = help: the following other types implement trait `IntoBytes`: + f32 + f64 + i128 + i16 + i32 + i64 + i8 + isize + and $N others note: required by a bound in `AssertIsIntoBytes` --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 | diff --git a/tests/ui-msrv/transmute-ref-alignment-increase.stderr b/tests/ui-msrv/transmute-ref-alignment-increase.stderr index bbf5058287..1db5b9c6e7 100644 --- a/tests/ui-msrv/transmute-ref-alignment-increase.stderr +++ b/tests/ui-msrv/transmute-ref-alignment-increase.stderr @@ -6,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-generic.stderr b/tests/ui-msrv/transmute-ref-dst-generic.stderr index ec7ec74894..efaf33de60 100644 --- a/tests/ui-msrv/transmute-ref-dst-generic.stderr +++ b/tests/ui-msrv/transmute-ref-dst-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `T` (this type does not have a fixed size) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-ref-dst-generic.rs:17:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (8 bits) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-mutable.stderr b/tests/ui-msrv/transmute-ref-dst-mutable.stderr index 3189cd0d4b..ef50d79678 100644 --- a/tests/ui-msrv/transmute-ref-dst-mutable.stderr +++ b/tests/ui-msrv/transmute-ref-dst-mutable.stderr @@ -42,8 +42,16 @@ error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); - | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | ^^^^^^^^^^^^^^^^^^^^ + | | + | types differ in mutability + | arguments to this function are incorrect | = note: expected mutable reference `&mut u8` found reference `&_` +note: function defined here + --> src/util/macro_util.rs + | + | pub const fn must_use(t: T) -> T { + | ^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr b/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr index 60a79caeba..614c30600c 100644 --- a/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr +++ b/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr @@ -42,8 +42,16 @@ error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); - | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | ^^^^^^^^^^^^^^^^^^^^ + | | + | expected `usize`, found reference + | arguments to this function are incorrect | = note: expected type `usize` found reference `&_` +note: function defined here + --> src/util/macro_util.rs + | + | pub const fn must_use(t: T) -> T { + | ^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr b/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr index 9cdc03ef84..8a2239af9a 100644 --- a/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr +++ b/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `Dst: zerocopy::FromBytes` is not satisfied --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `Dst` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call | -note: required by `AssertDstIsFromBytes` + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsFromBytes` --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr b/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr index 899805b05c..d9df2fbb00 100644 --- a/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr +++ b/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `Dst: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `Dst` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::Immutable` is not implemented for `Dst` + | required by a bound introduced by this call | -note: required by `AssertDstIsImmutable` + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others +note: required by a bound in `AssertDstIsImmutable` --> tests/ui-msrv/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-unsized.stderr b/tests/ui-msrv/transmute-ref-dst-unsized.stderr index 5967222fb0..19f18bbcd7 100644 --- a/tests/ui-msrv/transmute-ref-dst-unsized.stderr +++ b/tests/ui-msrv/transmute-ref-dst-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertDstIsSized` +note: required by a bound in `AssertDstIsSized` --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -35,7 +38,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 @@ -49,35 +52,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 - | -17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` - --> src/util/macro_util.rs - | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 diff --git a/tests/ui-msrv/transmute-ref-size-decrease.stderr b/tests/ui-msrv/transmute-ref-size-decrease.stderr index 95669f9063..d85a005c0a 100644 --- a/tests/ui-msrv/transmute-ref-size-decrease.stderr +++ b/tests/ui-msrv/transmute-ref-size-decrease.stderr @@ -6,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `[u8; 2]` (16 bits) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-size-increase.stderr b/tests/ui-msrv/transmute-ref-size-increase.stderr index 10f0e1038c..07d0188e44 100644 --- a/tests/ui-msrv/transmute-ref-size-increase.stderr +++ b/tests/ui-msrv/transmute-ref-size-increase.stderr @@ -6,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-src-dst-generic.stderr b/tests/ui-msrv/transmute-ref-src-dst-generic.stderr index eb3268fa8f..272d11f416 100644 --- a/tests/ui-msrv/transmute-ref-src-dst-generic.stderr +++ b/tests/ui-msrv/transmute-ref-src-dst-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `T` (this type does not have a fixed size) = note: target type: `U` (this type does not have a fixed size) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-ref-src-dst-generic.rs:18:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (size can vary because of T) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr b/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr index 1826e28a52..eeef5ff67c 100644 --- a/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr +++ b/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr @@ -55,8 +55,16 @@ error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); - | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected `usize`, found reference + | arguments to this function are incorrect | = note: expected type `usize` found reference `&_` +note: function defined here + --> src/util/macro_util.rs + | + | pub const fn must_use(t: T) -> T { + | ^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr b/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr index af59584992..9054ad74de 100644 --- a/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr +++ b/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertSrcIsSized` +note: required by a bound in `AssertSrcIsSized` --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -30,14 +33,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertDstIsSized` +note: required by a bound in `AssertDstIsSized` --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -55,7 +61,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute` @@ -63,16 +72,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AlignOf::::into_t` + --> src/util/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -82,7 +99,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -96,35 +113,24 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` - --> src/util/macro_util.rs - | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 - | -17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -138,7 +144,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -152,21 +158,7 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 - | -17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -191,13 +183,33 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/util/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute_ref` diff --git a/tests/ui-msrv/transmute-ref-src-generic.stderr b/tests/ui-msrv/transmute-ref-src-generic.stderr index 4cb3e51bc7..dd9df98eb9 100644 --- a/tests/ui-msrv/transmute-ref-src-generic.stderr +++ b/tests/ui-msrv/transmute-ref-src-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `T` (this type does not have a fixed size) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-ref-src-generic.rs:17:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (size can vary because of T) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr b/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr index 84036b70ba..a4317d985b 100644 --- a/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr +++ b/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `Src` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by `AssertSrcIsIntoBytes` + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `Src` | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | diff --git a/tests/ui-msrv/transmute-ref-src-not-nocell.stderr b/tests/ui-msrv/transmute-ref-src-not-nocell.stderr index 2e94e8064a..e1d50b0f07 100644 --- a/tests/ui-msrv/transmute-ref-src-not-nocell.stderr +++ b/tests/ui-msrv/transmute-ref-src-not-nocell.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `zerocopy::Immutable` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::Immutable` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by `AssertSrcIsImmutable` + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others +note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `Src` | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | diff --git a/tests/ui-msrv/transmute-ref-src-unsized.stderr b/tests/ui-msrv/transmute-ref-src-unsized.stderr index b3705bca36..81b3e3870f 100644 --- a/tests/ui-msrv/transmute-ref-src-unsized.stderr +++ b/tests/ui-msrv/transmute-ref-src-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertSrcIsSized` +note: required by a bound in `AssertSrcIsSized` --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -41,7 +44,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute` @@ -49,16 +55,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AlignOf::::into_t` + --> src/util/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 @@ -68,7 +82,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 @@ -82,21 +96,24 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 @@ -110,21 +127,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 - | -16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 @@ -138,27 +141,16 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 - | -16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute_ref` @@ -167,13 +159,3 @@ note: required by a bound in `transmute_ref` | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( | ^^^ required by this bound in `transmute_ref` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 - | -16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` - = note: all function arguments must have a statically known size - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-src-not-intobytes.stderr b/tests/ui-msrv/transmute-src-not-intobytes.stderr index 6382be909c..38b76d0067 100644 --- a/tests/ui-msrv/transmute-src-not-intobytes.stderr +++ b/tests/ui-msrv/transmute-src-not-intobytes.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa --> tests/ui-msrv/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | -note: required by `AssertIsIntoBytes` + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `AssertIsIntoBytes` --> tests/ui-msrv/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsIntoBytes` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `AssertIsIntoBytes` --> tests/ui-msrv/transmute-src-not-intobytes.rs:19:32 | diff --git a/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr b/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr index 5536f61216..fe3ccbde22 100644 --- a/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr +++ b/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `try_transmute` --> src/util/macro_util.rs | @@ -17,6 +27,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | @@ -29,6 +49,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | diff --git a/tests/ui-msrv/try_transmute-size-decrease.stderr b/tests/ui-msrv/try_transmute-size-decrease.stderr index 6817bc92cc..f8ee5d663a 100644 --- a/tests/ui-msrv/try_transmute-size-decrease.stderr +++ b/tests/ui-msrv/try_transmute-size-decrease.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `decrease_size` - --> tests/ui-msrv/try_transmute-size-decrease.rs:19:9 - | -19 | let decrease_size: Result = try_transmute!(AU16(0)); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute-size-decrease.rs:19:40 | diff --git a/tests/ui-msrv/try_transmute-size-increase.stderr b/tests/ui-msrv/try_transmute-size-increase.stderr index c66289ff9d..e8bd2019b8 100644 --- a/tests/ui-msrv/try_transmute-size-increase.stderr +++ b/tests/ui-msrv/try_transmute-size-increase.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute-size-increase.rs:19:9 - | -19 | let increase_size: Result = try_transmute!(0u8); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute-size-increase.rs:19:42 | diff --git a/tests/ui-msrv/try_transmute-src-not-intobytes.stderr b/tests/ui-msrv/try_transmute-src-not-intobytes.stderr index 589f8931d7..3b79ffbeeb 100644 --- a/tests/ui-msrv/try_transmute-src-not-intobytes.stderr +++ b/tests/ui-msrv/try_transmute-src-not-intobytes.stderr @@ -2,8 +2,21 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa --> tests/ui-msrv/try_transmute-src-not-intobytes.rs:18:47 | 18 | let src_not_into_bytes: Result = try_transmute!(NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `try_transmute` --> src/util/macro_util.rs | diff --git a/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr b/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr index aa67d03d7e..a5b5b224fc 100644 --- a/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr +++ b/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute_mut-alignment-increase.rs:20:9 - | -20 | let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-alignment-increase.rs:20:47 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr b/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr index a722fb99b5..a682314f09 100644 --- a/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr +++ b/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | @@ -17,6 +27,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | @@ -29,6 +49,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | diff --git a/tests/ui-msrv/try_transmute_mut-size-decrease.stderr b/tests/ui-msrv/try_transmute_mut-size-decrease.stderr index 6a5c78050a..24d3ce4cd8 100644 --- a/tests/ui-msrv/try_transmute_mut-size-decrease.stderr +++ b/tests/ui-msrv/try_transmute_mut-size-decrease.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `decrease_size` - --> tests/ui-msrv/try_transmute_mut-size-decrease.rs:20:9 - | -20 | let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-size-decrease.rs:20:45 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_mut-size-increase.stderr b/tests/ui-msrv/try_transmute_mut-size-increase.stderr index b363475e5c..415d2f3278 100644 --- a/tests/ui-msrv/try_transmute_mut-size-increase.stderr +++ b/tests/ui-msrv/try_transmute_mut-size-increase.stderr @@ -6,14 +6,6 @@ warning: unused import: `util::AU16` | = note: `#[warn(unused_imports)]` on by default -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute_mut-size-increase.rs:20:9 - | -20 | let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-size-increase.rs:20:50 | @@ -22,4 +14,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr b/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr index 170c63f9d2..ff726ab6d9 100644 --- a/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr +++ b/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr @@ -2,8 +2,21 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:19:52 | 19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | diff --git a/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr b/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr index 0ff43d87d4..5c9559b160 100644 --- a/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr +++ b/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute_ref-alignment-increase.rs:19:9 - | -19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-alignment-increase.rs:19:43 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr b/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr index 2c4ca40c00..c9c0ee358a 100644 --- a/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr +++ b/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr @@ -2,21 +2,31 @@ error[E0308]: mismatched types --> tests/ui-msrv/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | types differ in mutability + | arguments to this enum variant are incorrect | = note: expected mutable reference `&mut u8` found reference `&_` +note: tuple variant defined here + --> $RUST/core/src/result.rs + | + | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | types differ in mutability - | help: try using a variant of the expected enum: `Err($crate::util::macro_util::try_transmute_ref::<_, _>(e))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected enum `Result<&mut u8, _>` found enum `Result<&_, ValidityError<&u8, _>>` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: try wrapping the expression in `Err` + --> src/macros.rs + | + | Err($crate::util::macro_util::try_transmute_ref::<_, _>(e)) + | ++++ + diff --git a/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr b/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr index fb6e75f23e..46e7083a27 100644 --- a/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr +++ b/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | @@ -17,6 +27,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfie 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | @@ -30,6 +50,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | @@ -42,6 +72,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | diff --git a/tests/ui-msrv/try_transmute_ref-size-decrease.stderr b/tests/ui-msrv/try_transmute_ref-size-decrease.stderr index a2d527d858..c302a98976 100644 --- a/tests/ui-msrv/try_transmute_ref-size-decrease.stderr +++ b/tests/ui-msrv/try_transmute_ref-size-decrease.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `decrease_size` - --> tests/ui-msrv/try_transmute_ref-size-decrease.rs:19:9 - | -19 | let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-size-decrease.rs:19:41 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_ref-size-increase.stderr b/tests/ui-msrv/try_transmute_ref-size-increase.stderr index 44e02b42be..239d3c18de 100644 --- a/tests/ui-msrv/try_transmute_ref-size-increase.stderr +++ b/tests/ui-msrv/try_transmute_ref-size-increase.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute_ref-size-increase.rs:19:9 - | -19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-size-increase.rs:19:43 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr b/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr index ca5a0daf99..25ab032501 100644 --- a/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr +++ b/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr @@ -2,8 +2,21 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa --> tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | @@ -15,8 +28,21 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not sa --> tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `zerocopy::Immutable` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | diff --git a/tests/ui-stable/transmute-mut-dst-unsized.stderr b/tests/ui-stable/transmute-mut-dst-unsized.stderr index 8042fef016..bda6c417e9 100644 --- a/tests/ui-stable/transmute-mut-dst-unsized.stderr +++ b/tests/ui-stable/transmute-mut-dst-unsized.stderr @@ -47,7 +47,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by an implicit `Sized` bound in `transmute` +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | | pub fn transmute(src: Src) -> Dst; diff --git a/tests/ui-stable/transmute-mut-src-dst-unsized.stderr b/tests/ui-stable/transmute-mut-src-dst-unsized.stderr index 68ef6efd22..6fe2c8fbfc 100644 --- a/tests/ui-stable/transmute-mut-src-dst-unsized.stderr +++ b/tests/ui-stable/transmute-mut-src-dst-unsized.stderr @@ -144,7 +144,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by an implicit `Sized` bound in `transmute` +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | | pub fn transmute(src: Src) -> Dst; diff --git a/tests/ui-stable/transmute-ref-dst-unsized.stderr b/tests/ui-stable/transmute-ref-dst-unsized.stderr index 3361707c11..c3c53c2611 100644 --- a/tests/ui-stable/transmute-ref-dst-unsized.stderr +++ b/tests/ui-stable/transmute-ref-dst-unsized.stderr @@ -47,7 +47,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by an implicit `Sized` bound in `transmute` +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | | pub fn transmute(src: Src) -> Dst; diff --git a/tests/ui-stable/transmute-ref-src-dst-unsized.stderr b/tests/ui-stable/transmute-ref-src-dst-unsized.stderr index 3d6765cc3a..f1c285494a 100644 --- a/tests/ui-stable/transmute-ref-src-dst-unsized.stderr +++ b/tests/ui-stable/transmute-ref-src-dst-unsized.stderr @@ -144,7 +144,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by an implicit `Sized` bound in `transmute` +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | | pub fn transmute(src: Src) -> Dst; diff --git a/testutil/src/lib.rs b/testutil/src/lib.rs index d2cabede16..0056f100c9 100644 --- a/testutil/src/lib.rs +++ b/testutil/src/lib.rs @@ -49,7 +49,7 @@ impl PinnedVersions { .ok_or(format!("expected string value for path in Cargo.toml: {:?}", keys)) }; - let msrv = extract(&["package", "rust-version"])?; + let msrv = extract(&["workspace", "package", "rust-version"])?; let stable = extract(&["package", "metadata", "ci", "pinned-stable"])?; let nightly = extract(&["package", "metadata", "ci", "pinned-nightly"])?; Ok(PinnedVersions { msrv, stable, nightly }) diff --git a/tools/cargo-zerocopy/src/main.rs b/tools/cargo-zerocopy/src/main.rs index ec179b54f3..9b720297f9 100644 --- a/tools/cargo-zerocopy/src/main.rs +++ b/tools/cargo-zerocopy/src/main.rs @@ -112,14 +112,17 @@ impl Versions { fn get_toolchain_versions() -> Versions { let manifest_text = fs::read_to_string("Cargo.toml").unwrap(); let manifest = toml::from_str::(&manifest_text).unwrap(); + let manifest_table = manifest.as_table().unwrap(); + let workspace_package = + manifest_table["workspace"].as_table().unwrap()["package"].as_table().unwrap(); let package = manifest.as_table().unwrap()["package"].as_table().unwrap(); let metadata = package["metadata"].as_table().unwrap(); let build_rs = metadata["build-rs"].as_table().unwrap(); let ci = metadata["ci"].as_table().unwrap(); Versions { - msrv: package["rust-version"].as_str().unwrap().to_string(), + msrv: workspace_package["rust-version"].as_str().unwrap().to_string(), stable: ci["pinned-stable"].as_str().unwrap().to_string(), nightly: ci["pinned-nightly"].as_str().unwrap().to_string(), build_rs: build_rs.clone(), diff --git a/tools/generate-readme/src/main.rs b/tools/generate-readme/src/main.rs index 8945caea7b..908231608b 100644 --- a/tools/generate-readme/src/main.rs +++ b/tools/generate-readme/src/main.rs @@ -27,7 +27,7 @@ made in the doc comment on `src/lib.rs` or in `tools/generate-readme`. const DISCLAIMER_FOOTER: &str = "\ ## Disclaimer -Disclaimer: Zerocopy is not an officially supported Google product.\ +Disclaimer: This is not an officially supported Google product.\ "; fn main() { diff --git a/unsafe-fields/Cargo.toml b/unsafe-fields/Cargo.toml new file mode 100644 index 0000000000..43ab479958 --- /dev/null +++ b/unsafe-fields/Cargo.toml @@ -0,0 +1,28 @@ +# Copyright 2024 The Fuchsia Authors +# +# Licensed under a BSD-style license , Apache License, Version 2.0 +# , or the MIT +# license , at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +[package] +name = "unsafe-fields" +version = "0.2.1" +edition = "2021" +description = "Make it unsafe to access or modify fields with safety invariants" +license = "BSD-2-Clause OR Apache-2.0 OR MIT" +repository = "https://github.com/google/zerocopy" +rust-version = { workspace = true } + +exclude = [".*"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"] + + [lints.rust] + unexpected_cfgs = { level = "allow", check-cfg = ['cfg(doc_cfg)'] } + +[dependencies] +zerocopy_0_8 = { package = "zerocopy", path = "..", optional = true } diff --git a/unsafe-fields/LICENSE-APACHE b/unsafe-fields/LICENSE-APACHE new file mode 120000 index 0000000000..965b606f33 --- /dev/null +++ b/unsafe-fields/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/unsafe-fields/LICENSE-BSD b/unsafe-fields/LICENSE-BSD new file mode 120000 index 0000000000..d37ba4277e --- /dev/null +++ b/unsafe-fields/LICENSE-BSD @@ -0,0 +1 @@ +../LICENSE-BSD \ No newline at end of file diff --git a/unsafe-fields/LICENSE-MIT b/unsafe-fields/LICENSE-MIT new file mode 120000 index 0000000000..76219eb72e --- /dev/null +++ b/unsafe-fields/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/unsafe-fields/README.md b/unsafe-fields/README.md new file mode 100644 index 0000000000..e004e263b2 --- /dev/null +++ b/unsafe-fields/README.md @@ -0,0 +1,112 @@ + + +# unsafe-fields + +Support for unsafe fields. + +This crate provides the `unsafe_fields!` macro, which can be used to mark +fields as unsafe. Unsafe fields automatically have their types wrapped using +the `Unsafe` wrapper type. An `Unsafe` is intended to be used to for +struct, enum, or union fields which carry safety invariants. All accessors +are `unsafe`, which requires any use of an `Unsafe` field to be inside an +`unsafe` block. One exception is `Unsafe::as_ref`, which is available when +the `zerocopy_0_8` feature is enabled. See its docs for more information. + +An unsafe field has the type `Unsafe`. `O` is +the enclosing type (struct, enum, or union), `F` is the type of the field, +and `NAME_HASH` is the hash of the field's name. `O` prevents swapping +unsafe fields of the same `F` type between different enclosing types, and +`NAME_HASH` prevents swapping different fields of the same `F` type within +the same enclosing type. Note that swapping the same field between instances +of the same type [cannot be prevented](crate#limitations). + +[immutable]: zerocopy_0_8::Immutable + +## Examples + +```rust +use unsafe_fields::{unsafe_fields, Unsafe}; + +unsafe_fields! { + /// A `usize` which is guaranteed to be even. + pub struct EvenUsize { + // INVARIANT: `n` is even. + #[unsafe] + n: usize, + } +} + +impl EvenUsize { + /// Constructs a new `EvenUsize`. + /// + /// Returns `None` if `n` is odd. + pub fn new(n: usize) -> Option { + if n % 2 != 0 { + return None; + } + // SAFETY: We just confirmed that `n` is even. + let n = unsafe { Unsafe::new(n) }; + Some(EvenUsize { n }) + } +} +``` + +Attempting to swap unsafe fields of the same type is prevented: + +```rust,compile_fail,E0308 +use unsafe_fields::{unsafe_fields, Unsafe}; + +unsafe_fields! { + /// A range. + pub struct Range { + // INVARIANT: `lo <= hi`. + #[unsafe] + lo: usize, + #[unsafe] + hi: usize, + } +} + +impl Range { + pub fn swap(&mut self) { + // ERROR: Mismatched types + core::mem::swap(&mut self.lo, &mut self.hi); + } +} +``` + +## Limitations + +Note that we cannot prevent `Unsafe`s from being swapped between the same +field in instances of the same type: + +```rust +use unsafe_fields::{unsafe_fields, Unsafe}; + +unsafe_fields! { + /// A `usize` which is guaranteed to be even. + pub struct EvenUsize { + // INVARIANT: `n` is even. + #[unsafe] + n: usize, + } +} + +pub fn swap(a: &mut EvenUsize, b: &mut EvenUsize) { + core::mem::swap(&mut a.n, &mut b.n); +} +``` + +## Disclaimer + +Disclaimer: This is not an officially supported Google product. diff --git a/unsafe-fields/src/lib.rs b/unsafe-fields/src/lib.rs new file mode 100644 index 0000000000..06566189e1 --- /dev/null +++ b/unsafe-fields/src/lib.rs @@ -0,0 +1,467 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +// After updating the following doc comment, make sure to run the following +// command to update `README.md` based on its contents: +// +// cargo -q run --manifest-path ../tools/Cargo.toml -p generate-readme > README.md + +//! Support for unsafe fields. +//! +//! This crate provides the [`unsafe_fields!`] macro, which can be used to mark +//! fields as unsafe. Unsafe fields automatically have their types wrapped using +//! the [`Unsafe`] wrapper type. An `Unsafe` is intended to be used to for +//! struct, enum, or union fields which carry safety invariants. All accessors +//! are `unsafe`, which requires any use of an `Unsafe` field to be inside an +//! `unsafe` block. One exception is [`Unsafe::as_ref`], which is available when +//! the `zerocopy_0_8` feature is enabled. See its docs for more information. +//! +//! An unsafe field has the type `Unsafe`. `O` is +//! the enclosing type (struct, enum, or union), `F` is the type of the field, +//! and `NAME_HASH` is the hash of the field's name. `O` prevents swapping +//! unsafe fields of the same `F` type between different enclosing types, and +//! `NAME_HASH` prevents swapping different fields of the same `F` type within +//! the same enclosing type. Note that swapping the same field between instances +//! of the same type [cannot be prevented](crate#limitations). +//! +//! [immutable]: zerocopy_0_8::Immutable +//! +//! # Examples +//! +//! ```rust +//! use unsafe_fields::{unsafe_fields, Unsafe}; +//! +//! unsafe_fields! { +//! /// A `usize` which is guaranteed to be even. +//! pub struct EvenUsize { +//! // INVARIANT: `n` is even. +//! #[unsafe] +//! n: usize, +//! } +//! } +//! +//! impl EvenUsize { +//! /// Constructs a new `EvenUsize`. +//! /// +//! /// Returns `None` if `n` is odd. +//! pub fn new(n: usize) -> Option { +//! if n % 2 != 0 { +//! return None; +//! } +//! // SAFETY: We just confirmed that `n` is even. +//! let n = unsafe { Unsafe::new(n) }; +//! Some(EvenUsize { n }) +//! } +//! } +//! ``` +//! +//! Attempting to swap unsafe fields of the same type is prevented: +//! +//! ```rust,compile_fail,E0308 +//! use unsafe_fields::{unsafe_fields, Unsafe}; +//! +//! unsafe_fields! { +//! /// A range. +//! pub struct Range { +//! // INVARIANT: `lo <= hi`. +//! #[unsafe] +//! lo: usize, +//! #[unsafe] +//! hi: usize, +//! } +//! } +//! +//! impl Range { +//! pub fn swap(&mut self) { +//! // ERROR: Mismatched types +//! core::mem::swap(&mut self.lo, &mut self.hi); +//! } +//! } +//! ``` +//! +//! # Limitations +//! +//! Note that we cannot prevent `Unsafe`s from being swapped between the same +//! field in instances of the same type: +//! +//! ```rust +//! use unsafe_fields::{unsafe_fields, Unsafe}; +//! +//! unsafe_fields! { +//! /// A `usize` which is guaranteed to be even. +//! pub struct EvenUsize { +//! // INVARIANT: `n` is even. +//! #[unsafe] +//! n: usize, +//! } +//! } +//! +//! pub fn swap(a: &mut EvenUsize, b: &mut EvenUsize) { +//! core::mem::swap(&mut a.n, &mut b.n); +//! } +//! ``` + +// Sometimes we want to use lints which were added after our MSRV. +// `unknown_lints` is `warn` by default and we deny warnings in CI, so without +// this attribute, any unknown lint would cause a CI failure when testing with +// our MSRV. +#![allow(unknown_lints, non_local_definitions, unreachable_patterns)] +#![deny(renamed_and_removed_lints)] +#![deny( + anonymous_parameters, + deprecated_in_future, + late_bound_lifetime_arguments, + missing_docs, + path_statements, + patterns_in_fns_without_body, + rust_2018_idioms, + trivial_numeric_casts, + unreachable_pub, + unsafe_op_in_unsafe_fn, + unused_extern_crates, + // We intentionally choose not to deny `unused_qualifications`. When items + // are added to the prelude (e.g., `core::mem::size_of`), this has the + // consequence of making some uses trigger this lint on the latest toolchain + // (e.g., `mem::size_of`), but fixing it (e.g. by replacing with `size_of`) + // does not work on older toolchains. + // + // We tested a more complicated fix in #1413, but ultimately decided that, + // since this lint is just a minor style lint, the complexity isn't worth it + // - it's fine to occasionally have unused qualifications slip through, + // especially since these do not affect our user-facing API in any way. + variant_size_differences +)] +#![deny( + clippy::all, + clippy::alloc_instead_of_core, + clippy::arithmetic_side_effects, + clippy::as_underscore, + clippy::assertions_on_result_states, + clippy::as_conversions, + clippy::correctness, + clippy::dbg_macro, + clippy::decimal_literal_representation, + clippy::double_must_use, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::missing_const_for_fn, + clippy::missing_inline_in_public_items, + clippy::missing_safety_doc, + clippy::must_use_candidate, + clippy::must_use_unit, + clippy::obfuscated_if_else, + clippy::perf, + clippy::print_stdout, + clippy::return_self_not_must_use, + clippy::std_instead_of_core, + clippy::style, + clippy::suspicious, + clippy::todo, + clippy::undocumented_unsafe_blocks, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unwrap_used, + clippy::use_debug +)] +#![allow(clippy::type_complexity)] +#![deny( + rustdoc::bare_urls, + rustdoc::broken_intra_doc_links, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_html_tags, + rustdoc::invalid_rust_codeblocks, + rustdoc::missing_crate_level_docs, + rustdoc::private_intra_doc_links +)] +#![cfg_attr(doc_cfg, feature(doc_cfg))] + +use core::marker::PhantomData; + +/// A field with safety invariants. +/// +/// `Unsafe` should not be named directly - instead, use [`unsafe_fields!`] to +/// declare a type with unsafe fields. +/// +/// See the [crate-level documentation](crate) for more information. +#[repr(transparent)] +pub struct Unsafe { + _marker: PhantomData, + // INVARIANT: `field` is only modified via public `unsafe` methods. User code is never + // invoked implicitly except via public `unsafe` methods. + field: F, +} + +// NOTE on design: It may seem counter-intuitive to offer an impl of traits that +// don't require `unsafe` to call. Unfortunately, this is a fundamental +// requirement if users want to be able to mark their types as `Copy`. Luckily, +// we can implement `Copy` (and its unavoidable super-trait, `Clone`) without +// invoking user code or opening up the possibility of modifying the field. We +// do this by only implementing `Copy` and `Clone` when `F: Copy`. For `Clone`, +// the user is still able to provide a manual impl, so this does not +// fundamentally restrict what behavior can be supported. +impl Copy for Unsafe {} +impl Clone for Unsafe { + #[inline(always)] + #[allow(clippy::non_canonical_clone_impl)] + fn clone(&self) -> Self { + // SAFETY: We don't call any user-defined code here (only make a + // bit-for-bit copy of `self.field`), so there's no way to accidentally + // invoke user-defined code or modify `self.field`. + Unsafe { _marker: PhantomData, field: self.field } + } +} + +impl Unsafe { + /// Gets a reference to the inner value. + /// + /// If [`F: Immutable`][immutable], prefer [`as_ref`], which is safe. + /// + /// [immutable]: zerocopy_0_8::Immutable + /// [`as_ref`]: Unsafe::as_ref + /// + /// # Safety + /// + /// The caller is responsible for upholding any safety invariants associated + /// with this field. + #[inline(always)] + pub const unsafe fn as_ref_unchecked(&self) -> &F { + // SAFETY: This method is unsafe to call. + &self.field + } + + /// Gets a reference to the inner value safely so long as the inner value is + /// immutable. + /// + /// If [`F: Immutable`][immutable], then `F` does not permit interior + /// mutation, and so it is safe to return a reference to it. + /// + /// [immutable]: zerocopy_0_8::Immutable + #[inline(always)] + #[cfg(feature = "zerocopy_0_8")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "zerocopy_0_8")))] + pub const fn as_ref(&self) -> &F + where + F: zerocopy_0_8::Immutable, + { + // SAFETY: `F: Immutable` guarantees that the returned `&F` cannot be + // used to mutate `self`, and so it cannot be used to violate any + // invariant. + unsafe { self.as_ref_unchecked() } + } + + /// Gets a mutable reference to the inner value. + /// + /// # Safety + /// + /// The caller is responsible for upholding any safety invariants associated + /// with this field. + #[inline(always)] + pub unsafe fn as_mut(&mut self) -> &mut F { + // SAFETY: This method is unsafe to call. + &mut self.field + } +} + +impl Unsafe { + /// Constructs a new `Unsafe`. + /// + /// # Safety + /// + /// The caller is responsible for upholding any safety invariants associated + /// with this field. + #[inline(always)] + pub const unsafe fn new(field: F) -> Unsafe { + // SAFETY: This method is unsafe to call. + Unsafe { _marker: PhantomData, field } + } + + /// Extracts the inner `F` from `self`. + #[inline(always)] + pub const fn into(self) -> F { + use core::mem::ManuallyDrop; + let slf = ManuallyDrop::new(self); + + #[repr(C)] + union Transmute { + src: ManuallyDrop, + dst: ManuallyDrop, + } + + // We'd like to just return `self.field` here, but Rust would drop + // `self` in doing that, which we don't want. Even destructuring (ie, + // `let Unsafe { field, .. } = self`) also causes a drop. We also can't + // use `mem::transmute` because that requires all types to be concrete, + // so a union transmute is our only option. + // + // SAFETY: `ManuallyDrop>` has the same size and bit + // validity as `Unsafe<_, F, _>`. [1] `Unsafe<_, F, _>` is + // `#[repr(transparent)]` and has no other fields, and so it has the + // same size and bit validity as `F`. + // + // [1] Per https://doc.rust-lang.org/1.81.0/core/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T` + let dst = unsafe { Transmute { src: slf }.dst }; + + ManuallyDrop::into_inner(dst) + } +} + +/// Defines a type with unsafe fields. +/// +/// See the [crate-level documentation](crate) for more information. +// TODO: Allow specifying *which* fields are unsafe. +#[macro_export] +macro_rules! unsafe_fields { + ($(#[$attr:meta])* $vis:vis struct $name:ident { + $($(#[$field_attr:tt])? $field:ident: $field_ty:ty),* $(,)? + }) => { + $(#[$attr])* + $vis struct $name { + $( + $field: unsafe_fields!(@field $(#[$field_attr])? $field: $field_ty), + )* + } + }; + (@field #[unsafe] $field:ident: $field_ty:ty) => { + $crate::Unsafe + }; + (@field $_field:ident: $field_ty:ty) => { + $field_ty + } +} + +#[doc(hidden)] +pub mod macro_util { + // TODO: Implement a stronger hash function so we can basically just ignore + // collisions. If users encounter collisions in practice, we can just deal + // with it then, publish a new version, and tell them to upgrade. + #[inline(always)] + #[must_use] + #[allow(clippy::as_conversions, clippy::indexing_slicing, clippy::arithmetic_side_effects)] + pub const fn hash_field_name(field_name: &str) -> u128 { + // An implementation of FxHasher, although returning a u128. Probably + // not as strong as it could be, but probably more collision resistant + // than normal 64-bit FxHasher. + let field_name = field_name.as_bytes(); + let mut hash = 0u128; + let mut i = 0; + while i < field_name.len() { + // This is just FxHasher's `0x517cc1b727220a95` constant + // concatenated back-to-back. + const K: u128 = 0x517cc1b727220a95517cc1b727220a95; + hash = (hash.rotate_left(5) ^ (field_name[i] as u128)).wrapping_mul(K); + i += 1; + } + hash + } +} + +#[cfg(test)] +#[allow(clippy::missing_const_for_fn)] +mod tests { + use super::*; + + unsafe_fields! { + /// A `Foo`. + #[allow(unused)] + struct Foo { + #[unsafe] + a: usize, + b: usize, + } + } + + unsafe_fields! { + /// A `Bar`. + #[allow(unused)] + struct Bar { + #[unsafe] + a: usize, + #[unsafe] + b: usize, + } + } + + #[test] + #[allow(clippy::undocumented_unsafe_blocks)] + fn test_unsafe_fieds() { + let mut _foo = Foo { a: unsafe { Unsafe::new(0) }, b: 0 }; + let mut _bar = Bar { a: unsafe { Unsafe::new(0) }, b: unsafe { Unsafe::new(0) } }; + } +} + +/// This module exists so that we can use rustdoc to perform compile-fail tests +/// rather than having to set up an entire trybuild set suite. +/// +/// ```compile_fail,E0308 +/// use unsafe_fields::*; +/// +/// unsafe_fields! { +/// struct Foo { +/// #[unsafe] +/// a: usize, +/// b: usize, +/// } +/// } +/// +/// impl Foo { +/// // Swapping an unsafe field with a non-unsafe field is a compile error. +/// fn swap(&mut self) { +/// core::mem::swap(&mut self.a, &mut self.b); +/// } +/// } +/// ``` +/// +/// ```compile_fail,E0308 +/// use unsafe_fields::*; +/// +/// unsafe_fields! { +/// struct Foo { +/// #[unsafe] +/// a: usize, +/// #[unsafe] +/// b: usize, +/// } +/// } +/// +/// impl Foo { +/// // Swapping an unsafe field with another unsafe field is a compile +/// // error. +/// fn swap(&mut self) { +/// core::mem::swap(&mut self.a, &mut self.b); +/// } +/// } +/// ``` +/// +/// ```compile_fail,E0308 +/// use unsafe_fields::*; +/// +/// unsafe_fields! { +/// struct Foo { +/// #[unsafe] +/// a: usize, +/// } +/// } +/// +/// unsafe_fields! { +/// struct Bar { +/// #[unsafe] +/// a: usize, +/// } +/// } +/// +/// // Swapping identically-named unsafe fields from different types is a +/// // compile error. +/// fn swap(foo: &mut Foo, bar: &mut Bar) { +/// core::mem::swap(&mut foo.a, &mut bar.a); +/// } +/// ``` +#[doc(hidden)] +pub mod compile_fail {} diff --git a/zerocopy-derive/Cargo.toml b/zerocopy-derive/Cargo.toml index 71d4b55dbb..d348ef482e 100644 --- a/zerocopy-derive/Cargo.toml +++ b/zerocopy-derive/Cargo.toml @@ -9,7 +9,7 @@ [package] edition = "2021" name = "zerocopy-derive" -version = "0.8.5" +version = "0.9.0-alpha.0" authors = ["Joshua Liebow-Feeser "] description = "Custom derive for traits from the zerocopy crate" license = "BSD-2-Clause OR Apache-2.0 OR MIT" @@ -32,23 +32,17 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.1" quote = "1.0.10" -syn = { version = "2.0.46", features = ["full"] } +syn = { version = "2.0.79", features = ["full"] } [dev-dependencies] dissimilar = "1.0.9" -# We don't use this directly, but trybuild does. On the MSRV toolchain, the -# version resolver fails to select any version for once_cell unless we -# depend on it directly. -once_cell = "=1.9" -# This is the latest version which is compatible with `syn` 2.0.46, which we pin -# to in CI for MSRV compatibility reasons. -prettyplease = "=0.2.17" -rustversion = "1.0" -static_assertions = "1.1" +prettyplease = "0.2.22" +rustversion = "1.0.17" +static_assertions = "1.1.0" testutil = { path = "../testutil" } # Pinned to a specific version so that the version used for local development # and the version used in CI are guaranteed to be the same. Future versions # sometimes change the output format slightly, so a version mismatch can cause # CI test failures. -trybuild = { version = "=1.0.89", features = ["diff"] } +trybuild = { version = "=1.0.90", features = ["diff"] } zerocopy = { path = "../", features = ["derive"] } diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index df531ea00d..2392919441 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -259,16 +259,12 @@ pub(crate) fn derive_is_bit_valid( // `UnsafeCell`s will have the same location as in the // original type. let variant = unsafe { - variants.cast_unsized( + variants.cast_unsized_unchecked( |p: *mut ___ZerocopyVariants #ty_generics| { p as *mut #variant_struct_ident #ty_generics } ) }; - // SAFETY: `cast_unsized` removes the initialization - // invariant from `p`, so we re-assert that all of the bytes - // are initialized. - let variant = unsafe { variant.assume_initialized() }; < #variant_struct_ident #ty_generics as #trait_path >::is_bit_valid(variant) @@ -286,8 +282,7 @@ pub(crate) fn derive_is_bit_valid( mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { use ::zerocopy::util::macro_util::core_reexport; @@ -322,15 +317,11 @@ pub(crate) fn derive_is_bit_valid( // - There are no `UnsafeCell`s in the tag because it is a // primitive integer. let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; - // SAFETY: `tag_ptr` is casted from `candidate`, whose referent - // is `Initialized`. Since we have not written uninitialized - // bytes into the referent, `tag_ptr` is also `Initialized`. - let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.bikeshed_recall_valid().read_unaligned() + tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; // SAFETY: @@ -344,13 +335,10 @@ pub(crate) fn derive_is_bit_valid( // original enum, and so preserves the locations of any // `UnsafeCell`s. let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum #ty_generics }) }; - // SAFETY: `cast_unsized` removes the initialization invariant from - // `p`, so we re-assert that all of the bytes are initialized. - let raw_enum = unsafe { raw_enum.assume_initialized() }; // SAFETY: // - This projection returns a subfield of `this` using // `addr_of_mut!`. diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 65414b51fa..5d2f3ef43f 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -422,8 +422,7 @@ fn derive_try_from_bytes_struct( mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true #(&& { // SAFETY: @@ -477,11 +476,10 @@ fn derive_try_from_bytes_union( // is guaranteed to be no more strict than this definition. See #696 // for a more in-depth discussion. fn is_bit_valid<___ZerocopyAliasing>( - mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing> + mut candidate: ::zerocopy::Maybe<'_, Self,___ZerocopyAliasing> ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { false #(|| { // SAFETY: @@ -553,6 +551,22 @@ fn derive_try_from_bytes_enum( /// Attempts to generate a `TryFromBytes::is_bit_valid` instance that /// unconditionally returns true. /// +/// This is possible when the `top_level` trait is `FromBytes` and there are no +/// generic type parameters. In this case, we know that compilation will succeed +/// only if the type is unconditionally `FromBytes`. Type parameters are not +/// supported because a type with type parameters could be `TryFromBytes` but +/// not `FromBytes` depending on its type parameters, and so deriving a trivial +/// `is_bit_valid` would be either unsound or, assuming we add a defensive +/// `Self: FromBytes` bound (as we currently do), overly restrictive. Consider, +/// for example, that `Foo` ought to be `TryFromBytes` but not `FromBytes` +/// in this example: +/// +/// ```rust,ignore +/// #[derive(FromBytes)] +/// #[repr(transparent)] +/// struct Foo(T); +/// ``` +/// /// This should be used where possible. Using this impl is faster to codegen, /// faster to compile, and is friendlier on the optimizer. fn try_gen_trivial_is_bit_valid( @@ -574,8 +588,7 @@ fn try_gen_trivial_is_bit_valid( _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { if false { fn assert_is_from_bytes() @@ -618,8 +631,7 @@ unsafe fn gen_trivial_is_bit_valid_unchecked() -> proc_macro2::TokenStream { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true } @@ -1349,25 +1361,3 @@ fn impl_block( } } } - -// A polyfill for `Option::then_some`, which was added after our MSRV. -// -// The `#[allow(unused)]` is necessary because, on sufficiently recent toolchain -// versions, `b.then_some(...)` resolves to the inherent method rather than to -// this trait, and so this trait is considered unused. -// -// TODO(#67): Remove this once our MSRV is >= 1.62. -#[allow(unused)] -trait BoolExt { - fn then_some(self, t: T) -> Option; -} - -impl BoolExt for bool { - fn then_some(self, t: T) -> Option { - if self { - Some(t) - } else { - None - } - } -} diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 32377e5ea3..3244747171 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -155,8 +155,7 @@ fn test_try_from_bytes() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true } @@ -179,8 +178,7 @@ fn test_from_zeros() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true } @@ -208,8 +206,7 @@ fn test_from_bytes_struct() { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { if false { fn assert_is_from_bytes() @@ -256,8 +253,7 @@ fn test_from_bytes_union() { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { if false { fn assert_is_from_bytes() @@ -377,8 +373,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { use ::zerocopy::util::macro_util::core_reexport; #[repr(u8)] @@ -434,8 +429,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -528,8 +522,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -596,15 +589,13 @@ fn test_try_from_bytes_enum() { } let tag = { let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; - let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.bikeshed_recall_valid().read_unaligned() + tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; - let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) @@ -615,21 +606,19 @@ fn test_try_from_bytes_enum() { ___ZEROCOPY_TAG_UnitLike => true, ___ZEROCOPY_TAG_StructLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_StructLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } ___ZEROCOPY_TAG_TupleLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } @@ -671,8 +660,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { use ::zerocopy::util::macro_util::core_reexport; #[repr(u32)] @@ -728,8 +716,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -822,8 +809,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -890,15 +876,13 @@ fn test_try_from_bytes_enum() { } let tag = { let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; - let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.bikeshed_recall_valid().read_unaligned() + tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; - let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) @@ -909,21 +893,19 @@ fn test_try_from_bytes_enum() { ___ZEROCOPY_TAG_UnitLike => true, ___ZEROCOPY_TAG_StructLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_StructLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } ___ZEROCOPY_TAG_TupleLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } @@ -965,8 +947,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { use ::zerocopy::util::macro_util::core_reexport; #[repr(C)] @@ -1022,8 +1003,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -1116,8 +1096,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -1184,15 +1163,13 @@ fn test_try_from_bytes_enum() { } let tag = { let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; - let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.bikeshed_recall_valid().read_unaligned() + tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; - let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) @@ -1203,21 +1180,19 @@ fn test_try_from_bytes_enum() { ___ZEROCOPY_TAG_UnitLike => true, ___ZEROCOPY_TAG_StructLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_StructLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } ___ZEROCOPY_TAG_TupleLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } @@ -1503,8 +1478,7 @@ fn test_from_bytes_enum() { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { if false { fn assert_is_from_bytes() @@ -1808,8 +1782,7 @@ fn test_try_from_bytes_trivial_is_bit_valid_enum() { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true } diff --git a/zerocopy-derive/tests/include.rs b/zerocopy-derive/tests/include.rs index 6c236a3cf9..964ff17fb9 100644 --- a/zerocopy-derive/tests/include.rs +++ b/zerocopy-derive/tests/include.rs @@ -26,7 +26,7 @@ mod imp { #[allow(unused)] pub use { ::core::{ - assert_eq, + self, assert_eq, cell::UnsafeCell, convert::TryFrom, marker::PhantomData, @@ -119,7 +119,7 @@ pub mod util { let ptr = super::imp::Ptr::from_ref(&buf); // SAFETY: `T` and `MaybeUninit` have the same layout, so this is a // size-preserving cast. It is also a provenance-preserving cast. - let ptr = unsafe { ptr.cast_unsized(|p| p as *mut T) }; + let ptr = unsafe { ptr.cast_unsized_unchecked(|p| p as *mut T) }; // SAFETY: This is intentionally unsound; see the preceding comment. let ptr = unsafe { ptr.assume_initialized() }; assert!(::is_bit_valid(ptr)); diff --git a/zerocopy-derive/tests/struct_try_from_bytes.rs b/zerocopy-derive/tests/struct_try_from_bytes.rs index d212187cfa..8a4c70536c 100644 --- a/zerocopy-derive/tests/struct_try_from_bytes.rs +++ b/zerocopy-derive/tests/struct_try_from_bytes.rs @@ -78,7 +78,7 @@ fn two_bad() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Two) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Two) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -108,7 +108,7 @@ fn un_sized() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Unsized) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Unsized) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -163,7 +163,7 @@ fn test_maybe_from_bytes() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut MaybeFromBytes) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut MaybeFromBytes) }; // SAFETY: `[u8]` consists entirely of initialized bytes. let candidate = unsafe { candidate.assume_initialized() }; @@ -171,7 +171,7 @@ fn test_maybe_from_bytes() { imp::assert!(!is_bit_valid); } -#[derive(Debug, PartialEq, Eq, imp::TryFromBytes, imp::Immutable, imp::KnownLayout)] +#[derive(imp::TryFromBytes, imp::Immutable, imp::KnownLayout)] #[repr(C, packed)] struct CPacked { a: u8, @@ -189,7 +189,9 @@ struct CPacked { fn c_packed() { let candidate = &[42u8, 0xFF, 0xFF, 0xFF, 0xFF]; let converted = ::try_ref_from_bytes(candidate); - imp::assert_eq!(converted, imp::Ok(&CPacked { a: 42, b: u32::MAX })); + // Can't derive `Debug` or `PartialEq` on a `#[repr(packed)]` type, so we + // can't use `assert_eq!` or `assert!(converted == ...)`. + imp::assert!(imp::core::matches!(converted, imp::Ok(&CPacked { a: 42, b: u32::MAX }))); } #[derive(imp::TryFromBytes, imp::KnownLayout, imp::Immutable)] diff --git a/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr b/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr index 20ebd03a16..6a4461aed4 100644 --- a/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr +++ b/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr @@ -1,10 +1,20 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:34:1 + --> tests/ui-msrv/derive_transparent.rs:34:23 | 34 | util_assert_impl_all!(TransparentStruct: TryFromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `zerocopy::TryFromBytes` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others +note: required for `TransparentStruct` to implement `zerocopy::TryFromBytes` --> tests/ui-msrv/derive_transparent.rs:24:21 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -13,16 +23,26 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:34:1 | 34 | util_assert_impl_all!(TransparentStruct: TryFromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:35:1 + --> tests/ui-msrv/derive_transparent.rs:35:23 | 35 | util_assert_impl_all!(TransparentStruct: FromZeros); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `FromZeros` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others +note: required for `TransparentStruct` to implement `FromZeros` --> tests/ui-msrv/derive_transparent.rs:24:21 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -31,16 +51,26 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:35:1 | 35 | util_assert_impl_all!(TransparentStruct: FromZeros); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:36:1 + --> tests/ui-msrv/derive_transparent.rs:36:23 | 36 | util_assert_impl_all!(TransparentStruct: FromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `zerocopy::FromBytes` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required for `TransparentStruct` to implement `zerocopy::FromBytes` --> tests/ui-msrv/derive_transparent.rs:24:21 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -49,16 +79,26 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:36:1 | 36 | util_assert_impl_all!(TransparentStruct: FromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:37:1 + --> tests/ui-msrv/derive_transparent.rs:37:23 | 37 | util_assert_impl_all!(TransparentStruct: IntoBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `zerocopy::IntoBytes` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required for `TransparentStruct` to implement `zerocopy::IntoBytes` --> tests/ui-msrv/derive_transparent.rs:24:10 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -67,16 +107,26 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:37:1 | 37 | util_assert_impl_all!(TransparentStruct: IntoBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `IntoBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:38:1 + --> tests/ui-msrv/derive_transparent.rs:38:23 | 38 | util_assert_impl_all!(TransparentStruct: Unaligned); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `Unaligned` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others +note: required for `TransparentStruct` to implement `Unaligned` --> tests/ui-msrv/derive_transparent.rs:24:32 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -85,5 +135,5 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:38:1 | 38 | util_assert_impl_all!(TransparentStruct: Unaligned); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/enum.stderr b/zerocopy-derive/tests/ui-msrv/enum.stderr index 938c8384e3..038682724f 100644 --- a/zerocopy-derive/tests/ui-msrv/enum.stderr +++ b/zerocopy-derive/tests/ui-msrv/enum.stderr @@ -83,7 +83,7 @@ error: FromZeros only supported on enums with a variant that has a discriminant | |_^ error: FromZeros only supported on enums with a variant that has a discriminant of `0` -help: This enum has discriminants which are not literal integers. One of those may define or imply which variant has a discriminant of zero. Use a literal integer to define or imply the variant with a discriminant of zero. + help: This enum has discriminants which are not literal integers. One of those may define or imply which variant has a discriminant of zero. Use a literal integer to define or imply the variant with a discriminant of zero. --> tests/ui-msrv/enum.rs:119:1 | 119 | / #[repr(i8)] @@ -294,6 +294,8 @@ error[E0552]: unrecognized representation hint | 25 | #[repr(foo)] | ^^^ + | + = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` error[E0566]: conflicting representation hints --> tests/ui-msrv/enum.rs:37:8 @@ -311,6 +313,16 @@ error[E0277]: the trait bound `UnsafeCell<()>: Immutable` is not satisfied 51 | #[derive(Immutable)] | ^^^^^^^^^ the trait `Immutable` is not implemented for `UnsafeCell<()>` | + = help: the following other types implement trait `Immutable`: + &T + &mut T + () + *const T + *mut T + F32 + F64 + I128 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -320,6 +332,16 @@ error[E0277]: the trait bound `UnsafeCell: Immutable` is not satisfied 59 | #[derive(Immutable)] | ^^^^^^^^^ the trait `Immutable` is not implemented for `UnsafeCell` | + = help: the following other types implement trait `Immutable`: + &T + &mut T + () + *const T + *mut T + F32 + F64 + I128 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -329,6 +351,16 @@ error[E0277]: the trait bound `NotTryFromBytes: TryFromBytes` is not satisfied 82 | #[derive(TryFromBytes)] | ^^^^^^^^^^^^ the trait `TryFromBytes` is not implemented for `NotTryFromBytes` | + = help: the following other types implement trait `TryFromBytes`: + () + *const T + *mut T + ::is_bit_valid::___ZerocopyVariantStruct_A + ::is_bit_valid::___ZerocopyVariantStruct_A + AtomicBool + AtomicI16 + AtomicI32 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `TryFromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -338,6 +370,16 @@ error[E0277]: the trait bound `NotFromZeros: TryFromBytes` is not satisfied 127 | #[derive(FromZeros)] | ^^^^^^^^^ the trait `TryFromBytes` is not implemented for `NotFromZeros` | + = help: the following other types implement trait `TryFromBytes`: + () + *const T + *mut T + ::is_bit_valid::___ZerocopyVariantStruct_A + ::is_bit_valid::___ZerocopyVariantStruct_A + AtomicBool + AtomicI16 + AtomicI32 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -347,6 +389,16 @@ error[E0277]: the trait bound `NotFromZeros: FromZeros` is not satisfied 127 | #[derive(FromZeros)] | ^^^^^^^^^ the trait `FromZeros` is not implemented for `NotFromZeros` | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -356,6 +408,16 @@ error[E0277]: the trait bound `bool: FromBytes` is not satisfied 191 | #[derive(FromBytes)] | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool` | + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -365,8 +427,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 538 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -376,8 +437,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 549 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -387,8 +447,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 555 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr b/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr index 0b57efc7d1..c52e355591 100644 --- a/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr @@ -12,6 +12,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 28 | #[derive(TryFromBytes)] | ^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `TryFromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -21,6 +31,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 37 | #[derive(FromZeros)] | ^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -30,6 +50,16 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied 37 | #[derive(FromZeros)] | ^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -39,6 +69,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 46 | #[derive(FromBytes)] | ^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -48,6 +88,16 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied 46 | #[derive(FromBytes)] | ^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -57,6 +107,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie 46 | #[derive(FromBytes)] | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -66,6 +126,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfie 55 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -75,6 +145,16 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied 65 | #[derive(Unaligned)] | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -84,6 +164,16 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied 73 | #[derive(Unaligned)] | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -93,5 +183,15 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied 80 | #[derive(Unaligned)] | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr index 1d6d22df3f..2538c9deb4 100644 --- a/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied 59 | fn test_kl13(t: T) -> impl KnownLayout { | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` | -note: required because of the requirements on the impl of `KnownLayout` for `KL13` +note: required for `KL13` to implement `KnownLayout` --> tests/ui-msrv/mid_compile_pass.rs:55:10 | 55 | #[derive(KnownLayout)] @@ -21,14 +21,16 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim 30 | fn test_kl04(kl: &KL04) { | - this type parameter needs to be `std::marker::Sized` 31 | assert_kl(kl); - | ^^ doesn't have a size known at compile-time + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required because it appears within the type `KL04` --> tests/ui-msrv/mid_compile_pass.rs:28:8 | 28 | struct KL04(u8, T); | ^^^^ -note: required because of the requirements on the impl of `KnownLayout` for `KL04` +note: required for `KL04` to implement `KnownLayout` --> tests/ui-msrv/mid_compile_pass.rs:27:10 | 27 | #[derive(KnownLayout)] @@ -51,14 +53,16 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim 39 | fn test_kl06(kl: &KL06) { | - this type parameter needs to be `std::marker::Sized` 40 | assert_kl(kl); - | ^^ doesn't have a size known at compile-time + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required because it appears within the type `KL06` --> tests/ui-msrv/mid_compile_pass.rs:37:8 | 37 | struct KL06(u8, T); | ^^^^ -note: required because of the requirements on the impl of `KnownLayout` for `KL06` +note: required for `KL06` to implement `KnownLayout` --> tests/ui-msrv/mid_compile_pass.rs:36:10 | 36 | #[derive(KnownLayout)] @@ -79,9 +83,11 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied --> tests/ui-msrv/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | ^^ the trait `KnownLayout` is not implemented for `T` + | --------- ^^ the trait `KnownLayout` is not implemented for `T` + | | + | required by a bound introduced by this call | -note: required because of the requirements on the impl of `KnownLayout` for `KL12` +note: required for `KL12` to implement `KnownLayout` --> tests/ui-msrv/mid_compile_pass.rs:45:10 | 45 | #[derive(KnownLayout)] diff --git a/zerocopy-derive/tests/ui-msrv/msrv_specific.stderr b/zerocopy-derive/tests/ui-msrv/msrv_specific.stderr index 027fd48507..82b8f08a2d 100644 --- a/zerocopy-derive/tests/ui-msrv/msrv_specific.stderr +++ b/zerocopy-derive/tests/ui-msrv/msrv_specific.stderr @@ -7,12 +7,22 @@ warning: unused `#[macro_use]` import = note: `#[warn(unused_imports)]` on by default error[E0277]: the trait bound `AU16: Unaligned` is not satisfied - --> tests/ui-msrv/msrv_specific.rs:35:9 + --> tests/ui-msrv/msrv_specific.rs:35:27 | 35 | is_into_bytes_1::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | ^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | -note: required because of the requirements on the impl of `zerocopy::IntoBytes` for `IntoBytes1` + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others +note: required for `IntoBytes1` to implement `zerocopy::IntoBytes` --> tests/ui-msrv/msrv_specific.rs:24:10 | 24 | #[derive(IntoBytes)] diff --git a/zerocopy-derive/tests/ui-msrv/struct.stderr b/zerocopy-derive/tests/ui-msrv/struct.stderr index 4fc4a581ff..ed72562beb 100644 --- a/zerocopy-derive/tests/ui-msrv/struct.stderr +++ b/zerocopy-derive/tests/ui-msrv/struct.stderr @@ -122,6 +122,16 @@ error[E0277]: the trait bound `NotKnownLayoutDst: zerocopy::KnownLayout` is not 41 | #[derive(KnownLayout)] | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotKnownLayoutDst` | + = help: the following other types implement trait `zerocopy::KnownLayout`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -131,6 +141,16 @@ error[E0277]: the trait bound `NotKnownLayout: zerocopy::KnownLayout` is not sat 47 | #[derive(KnownLayout)] | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotKnownLayout` | + = help: the following other types implement trait `zerocopy::KnownLayout`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -140,6 +160,16 @@ error[E0277]: the trait bound `UnsafeCell<()>: zerocopy::Immutable` is not satis 55 | #[derive(Immutable)] | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>` | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + F32 + F64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -149,7 +179,17 @@ error[E0277]: the trait bound `UnsafeCell: zerocopy::Immutable` is not satis 60 | #[derive(Immutable)] | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell` | - = note: required because of the requirements on the impl of `zerocopy::Immutable` for `[UnsafeCell; 0]` + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + F32 + F64 + and $N others + = note: required for `[UnsafeCell; 0]` to implement `zerocopy::Immutable` = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -159,6 +199,16 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied 100 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -168,8 +218,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 107 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -179,8 +228,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 114 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -201,7 +249,7 @@ note: required by a bound in `std::mem::size_of` | | pub const fn size_of() -> usize { | ^ required by this bound in `std::mem::size_of` - = note: this error originates in the macro `::zerocopy::struct_has_padding` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/struct.rs:129:8 diff --git a/zerocopy-derive/tests/ui-msrv/union.stderr b/zerocopy-derive/tests/ui-msrv/union.stderr index 88251941af..af55c57d29 100644 --- a/zerocopy-derive/tests/ui-msrv/union.stderr +++ b/zerocopy-derive/tests/ui-msrv/union.stderr @@ -68,7 +68,17 @@ error[E0277]: the trait bound `UnsafeCell<()>: zerocopy::Immutable` is not satis 24 | #[derive(Immutable)] | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>` | - = note: required because of the requirements on the impl of `zerocopy::Immutable` for `ManuallyDrop>` + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + F32 + F64 + and $N others + = note: required for `ManuallyDrop>` to implement `zerocopy::Immutable` = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -78,7 +88,6 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 39 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.stderr b/zerocopy-derive/tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.stderr index d25c238f6e..13d68fce49 100644 --- a/zerocopy-derive/tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.stderr +++ b/zerocopy-derive/tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.stderr @@ -1,5 +1,5 @@ error: requires --cfg zerocopy_derive_union_into_bytes; -please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802 + please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802 --> tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.rs:20:10 | 20 | #[derive(IntoBytes)] diff --git a/zerocopy-derive/tests/union_try_from_bytes.rs b/zerocopy-derive/tests/union_try_from_bytes.rs index 8c3183e5d8..f2bd84ee4e 100644 --- a/zerocopy-derive/tests/union_try_from_bytes.rs +++ b/zerocopy-derive/tests/union_try_from_bytes.rs @@ -73,7 +73,7 @@ fn two_bad() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Two) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Two) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -102,7 +102,7 @@ fn bool_and_zst() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut BoolAndZst) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut BoolAndZst) }; // SAFETY: `candidate`'s referent is fully initialized. let candidate = unsafe { candidate.assume_initialized() }; @@ -130,7 +130,7 @@ fn test_maybe_from_bytes() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut MaybeFromBytes) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut MaybeFromBytes) }; // SAFETY: `[u8]` consists entirely of initialized bytes. let candidate = unsafe { candidate.assume_initialized() };