diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 22b8600249..7940546975 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -8,12 +8,19 @@ name: Cache description: 'Caches cargo dependencies' +outputs: + cache-hit: + description: "Cache Hit" + value: ${{ steps.cache.outputs.cache-hit }} runs: using: composite steps: - uses: actions/cache@v4 + id: cache with: path: | ~/.cargo/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} + restore-keys: | + ${{ runner.os }}-cargo- diff --git a/.github/workflows/backport-pr.yml b/.github/workflows/backport-pr.yml new file mode 100644 index 0000000000..c663d55485 --- /dev/null +++ b/.github/workflows/backport-pr.yml @@ -0,0 +1,63 @@ +# 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. + +name: Backport PR +on: + workflow_dispatch: + inputs: + commit: + description: "Commit to backport" + required: true + target_branch: + description: "Target branch for the new PR" + required: true + default: 'main' + +permissions: read-all + +jobs: + release: + runs-on: ubuntu-latest + name: Backport PR + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ github.event.inputs.target_branch }} + # Check out the entire repository so that the target commit is checked + # out (by default, only fetches the single commit identified by the + # `ref` argument). + fetch-depth: 0 + persist-credentials: false + - name: Cherry-pick commit + run: | + set -eo pipefail + + AUTHOR_NAME="$(git log -1 --pretty='%an' ${{ github.event.inputs.commit }})" + AUTHOR_EMAIL="$(git log -1 --pretty='%ae' ${{ github.event.inputs.commit }})" + + git config --global user.name "$AUTHOR_NAME" + git config --global user.email "$AUTHOR_EMAIL" + + git cherry-pick ${{ github.event.inputs.commit }} + + PR_TITLE="$(git log -1 --pretty=%s)" + echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV + + AUTHOR="$AUTHOR_NAME <$AUTHOR_EMAIL>" + echo "AUTHOR=$AUTHOR" >> $GITHUB_ENV + + - name: Submit PR + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 + with: + author: "${{ env.AUTHOR }}" + committer: "${{ env.AUTHOR }}" + title: "${{ env.PR_TITLE }}" + branch: backport-${{ github.event.inputs.commit }} + push-to-fork: google-pr-creation-bot/zerocopy + token: ${{ secrets.GOOGLE_PR_CREATION_BOT_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b86152cbf6..cc1b722e95 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,35 +102,9 @@ 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" + # Exclude stable/wasm since wasm is no longer provided via rustup on + # stable. + - toolchain: "stable" target: "wasm32-wasi" # Exclude most targets targets from the `zerocopy-core-error` # toolchain since the `zerocopy-core-error` feature is unrelated to @@ -190,28 +149,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. @@ -243,7 +180,9 @@ jobs: name: Build & Test (${{ matrix.crate }} / ${{ matrix.toolchain }} / ${{ matrix.features }} / ${{ matrix.target }}) steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 2 - name: Populate cache uses: ./.github/actions/cache @@ -259,7 +198,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 +260,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 }}" @@ -482,6 +421,25 @@ jobs: 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 ${{ matrix.crate }} ${{ matrix.features }} + # If the commit message contains the line `SKIP_CARGO_SEMVER_CHECKS=1`, then + # skip the cargo-semver-checks step. + - name: Check whether to skip cargo-semver-checks + run: | + set -eo pipefail + + if [ "${{ github.event_name }}" == "pull_request" ]; then + # Invoked from a PR - get the PR body directly + MESSAGE="$(git log -1 --pretty=%B ${{ github.event.pull_request.head.sha }})" + else + # Invoked from the merge queue - get the commit message + MESSAGE="$(git log -1 --pretty=%B ${{ github.sha }})" + fi + + if echo "$MESSAGE" | grep '^\s*SKIP_CARGO_SEMVER_CHECKS=1\s*$' > /dev/null; then + echo "Found 'SKIP_CARGO_SEMVER_CHECKS=1' in commit message; skipping cargo-semver-checks..." | tee -a $GITHUB_STEP_SUMMARY + echo "ZC_SKIP_CARGO_SEMVER_CHECKS=1" >> $GITHUB_ENV + fi + # Check semver compatibility with the most recently-published version on # crates.io. We do this in the matrix rather than in its own job so that it # gets run on different targets. Some of our API is target-specific (e.g., @@ -511,7 +469,8 @@ jobs: matrix.crate == 'zerocopy' && matrix.features == '--features __internal_use_only_features_that_work_on_stable' && matrix.toolchain == 'stable' && - matrix.target != 'wasm32-wasi' + matrix.target != 'wasm32-wasi' && + env.ZC_SKIP_CARGO_SEMVER_CHECKS != '1' # TODO(#453): Doing this as a matrix step is a hack that allows us to depend # on the fact that toolchains have already been installed. We currently only @@ -543,7 +502,7 @@ jobs: matrix.target == 'x86_64-unknown-linux-gnu' - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: lcov.info @@ -557,7 +516,7 @@ jobs: runs-on: ubuntu-latest name: 'Run tests under Kani' steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: model-checking/kani-github-action@f838096619a707b0f6b2118cf435eaccfa33e51f # v1.1 with: # Use `--features __internal_use_only_features_that_work_on_stable` @@ -575,6 +534,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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - 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 @@ -585,7 +615,7 @@ jobs: runs-on: ubuntu-latest name: Build (zerocopy / nightly / --simd / aarch64_be-unknown-linux-gnu) steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Configure environment variables run: | set -eo pipefail @@ -594,7 +624,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' @@ -613,7 +643,7 @@ jobs: runs-on: ubuntu-latest name: Check Rust formatting steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Check Rust formatting run: ./ci/check_fmt.sh @@ -622,7 +652,7 @@ jobs: runs-on: ubuntu-latest name: Check README.md steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Populate cache uses: ./.github/actions/cache @@ -635,7 +665,7 @@ jobs: runs-on: ubuntu-latest name: Check crate versions match steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Populate cache uses: ./.github/actions/cache @@ -650,12 +680,13 @@ jobs: runs-on: ubuntu-latest name: Generate cache steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Populate cache + - id: populate-cache uses: ./.github/actions/cache - name: Download dependencies + if: steps.populate-cache.outputs.cache-hit != 'true' run: | # Ensure all dependencies are downloaded - both for our crates and for # tools we use in CI. We don't care about these tools succeeding for @@ -681,7 +712,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 & @@ -698,7 +729,7 @@ jobs: steps: - name: Install yq (for YAML parsing) run: go install github.com/mikefarah/yq/v4@latest - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run check run: ./ci/check_all_toolchains_tested.sh @@ -708,7 +739,7 @@ jobs: steps: - name: Install yq (for YAML parsing) run: go install github.com/mikefarah/yq/v4@latest - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run dependency check run: ./ci/check_job_dependencies.sh @@ -718,7 +749,7 @@ jobs: steps: - name: Install yq (for YAML parsing) run: go install github.com/mikefarah/yq/v4@latest - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run dependency check # Ensure that Git hooks execute successfully. # @@ -738,7 +769,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..3bb60c004e 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -25,11 +25,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit - name: 'Checkout Repository' - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: 'Dependency Review' - uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 + uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d30f3bf820..6e19289747 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,7 +27,7 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Configure environment variables run: | set -eo pipefail diff --git a/.github/workflows/release-crate-version.yml b/.github/workflows/release-crate-version.yml index 8d99ba07a5..99a5a4825b 100644 --- a/.github/workflows/release-crate-version.yml +++ b/.github/workflows/release-crate-version.yml @@ -16,7 +16,7 @@ on: branch: description: 'Branch to update' required: true - default: 'main' + default: 'v0.8.x' permissions: read-all @@ -26,7 +26,7 @@ jobs: name: Release new crate versions steps: - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.inputs.branch }} persist-credentials: false diff --git a/.github/workflows/roll-pinned-toolchain-versions.yml b/.github/workflows/roll-pinned-toolchain-versions.yml index 90de5927d1..1908beba11 100644 --- a/.github/workflows/roll-pinned-toolchain-versions.yml +++ b/.github/workflows/roll-pinned-toolchain-versions.yml @@ -35,11 +35,11 @@ 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 - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ matrix.branch }} persist-credentials: false @@ -148,7 +148,7 @@ jobs: name: Roll pinned Kani version steps: - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ matrix.branch }} persist-credentials: false diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b8fc853a0f..147801dea7 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -37,7 +37,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false @@ -58,7 +58,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: SARIF file path: results.sarif @@ -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@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 with: sarif_file: results.sarif diff --git a/Cargo.toml b/Cargo.toml index efc21f3e69..f851781483 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,17 +12,24 @@ # https://github.com/dtolnay/trybuild/issues/207#issuecomment-131227.594 [workspace] +members = ["unsafe-fields", "zerocopy-derive"] + +[workspace.package] +# Inherited by workspace members. +rust-version = "1.65.0" +authors = ["Joshua Liebow-Feeser ", "Jack Wrenn "] + [package] edition = "2021" name = "zerocopy" -version = "0.8.5" -authors = ["Joshua Liebow-Feeser "] +version = "0.9.0-alpha.0" +authors = { workspace = true } 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 +45,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.85.0" +pinned-nightly = "nightly-2024-11-06" [package.metadata.docs.rs] all-features = true @@ -70,6 +62,7 @@ alloc = [] derive = ["zerocopy-derive"] simd = [] simd-nightly = ["simd"] +float-nightly = [] std = ["alloc"] # This feature depends on all other features that work on the stable compiler. # We make no stability guarantees about this feature; it may be modified or @@ -77,26 +70,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..658879908f 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,10 @@ for network parsing. available on nightly. Since these types are unstable, support for any type may be removed at any point in the future. +- **`float-nightly`** + Adds support for the unstable `f16` and `f128` types. These types are + not yet fully implemented and may not be supported on all platforms. + [duplicate-import-errors]: https://github.com/google/zerocopy/issues/1587 [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html @@ -199,6 +203,14 @@ Zerocopy uses [GitHub Releases]. [GitHub Releases]: https://github.com/google/zerocopy/releases +## Thanks + +Zerocopy is maintained by engineers at Google and Amazon with help from +[many wonderful contributors][contributors]. Thank you to everyone who has +lent a hand in making Rust a little more secure! + +[contributors]: https://github.com/google/zerocopy/graphs/contributors + ## 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..8bfd4dd9d2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -298,11 +298,11 @@ impl AlignmentError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> AlignmentError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> AlignmentError { AlignmentError { src: f(self.src), dst: SendSyncPhantomData::default() } } - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Alignment(self) } @@ -453,7 +453,7 @@ impl SizeError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> SizeError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> SizeError { SizeError { src: f(self.src), dst: SendSyncPhantomData::default() } } @@ -463,7 +463,7 @@ impl SizeError { } /// Converts the error into a general [`ConvertError`]. - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Size(self) } @@ -590,12 +590,26 @@ impl ValidityError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> ValidityError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> ValidityError { ValidityError { src: f(self.src), dst: SendSyncPhantomData::default() } } + /// Changes the destination type. + /// + /// # Safety + /// + /// `NewDst` must have the same validity - as implemented by + /// [`TryFromBytes::is_bit_valid`] - as `Dst`. + pub(crate) unsafe fn with_dst(self) -> ValidityError { + // SAFETY: There is currently no invariant required of `dst`, so this + // method's safety precondition is unnecessary. However, we require it + // to be forwards-compatible with a point in time where we add an + // invariant to the `Dst` type. + ValidityError { src: self.src, dst: SendSyncPhantomData::default() } + } + /// Converts the error into a general [`ConvertError`]. - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Validity(self) } @@ -710,7 +724,7 @@ impl CastError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> CastError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> CastError { match self { Self::Alignment(e) => CastError::Alignment(e.map_src(f)), Self::Size(e) => CastError::Size(e.map_src(f)), @@ -831,7 +845,7 @@ impl TryCastError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> TryCastError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> TryCastError { match self { Self::Alignment(e) => TryCastError::Alignment(e.map_src(f)), Self::Size(e) => TryCastError::Size(e.map_src(f)), @@ -896,7 +910,7 @@ impl TryReadError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> TryReadError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> TryReadError { match self { Self::Alignment(i) => match i {}, Self::Size(e) => TryReadError::Size(e.map_src(f)), @@ -957,6 +971,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..c5b8694732 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -7,6 +7,8 @@ // This file may not be copied, modified, or distributed except according to // those terms. +use core::mem::MaybeUninit as CoreMaybeUninit; + use super::*; safety_comment! { @@ -72,6 +74,10 @@ safety_comment! { unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); + #[cfg(feature = "float-nightly")] + unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); + #[cfg(feature = "float-nightly")] + unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); } safety_comment! { @@ -180,7 +186,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 +296,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 +307,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 +438,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::*; @@ -627,14 +621,14 @@ safety_comment! { /// SAFETY: /// `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: /// `MaybeUninit` has no restrictions on its contents. - unsafe_impl!(T => TryFromBytes for MaybeUninit); - unsafe_impl!(T => FromZeros for MaybeUninit); - unsafe_impl!(T => FromBytes for MaybeUninit); + unsafe_impl!(T => TryFromBytes for CoreMaybeUninit); + unsafe_impl!(T => FromZeros for CoreMaybeUninit); + unsafe_impl!(T => FromBytes for CoreMaybeUninit); } -impl_for_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit); -impl_for_transparent_wrapper!(T: Unaligned => Unaligned for MaybeUninit); -assert_unaligned!(MaybeUninit<()>, MaybeUninit); +impl_for_transparent_wrapper!(T: Immutable => Immutable for CoreMaybeUninit); +impl_for_transparent_wrapper!(T: Unaligned => Unaligned for CoreMaybeUninit); +assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit); impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop); impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop); @@ -660,9 +654,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 +925,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 +947,7 @@ mod simd { #[cfg(test)] mod tests { use super::*; + use crate::pointer::invariant; #[test] fn test_impls() { @@ -1138,10 +1130,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 +1138,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 { @@ -1178,6 +1164,24 @@ mod tests { } } + pub(super) trait TestTryFromMut { + #[allow(clippy::needless_lifetimes)] + fn test_try_from_mut<'bytes>( + &self, + bytes: &'bytes mut [u8], + ) -> Option>; + } + + impl TestTryFromMut for AutorefWrapper { + #[allow(clippy::needless_lifetimes)] + fn test_try_from_mut<'bytes>( + &self, + bytes: &'bytes mut [u8], + ) -> Option> { + Some(T::try_mut_from_bytes(bytes).ok()) + } + } + pub(super) trait TestTryReadFrom { fn test_try_read_from(&self, bytes: &[u8]) -> Option>; } @@ -1242,7 +1246,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 { @@ -1251,8 +1255,8 @@ mod tests { ManuallyDrop>, ManuallyDrop<[UnsafeCell]>, ManuallyDrop<[UnsafeCell]>, - MaybeUninit, - MaybeUninit>, + CoreMaybeUninit, + CoreMaybeUninit>, Wrapping> ); @@ -1269,6 +1273,25 @@ mod tests { None } + #[allow(clippy::needless_lifetimes)] + fn test_try_from_mut<'bytes>(&mut self, _bytes: &'bytes mut [u8]) -> Option> { + assert_on_allowlist!( + test_try_from_mut($ty): + Option>>, + Option<&'static UnsafeCell>, + Option<&'static mut UnsafeCell>, + Option>>, + Option, + Option, + Option, + Option, + *const NotZerocopy, + *mut NotZerocopy + ); + + None + } + fn test_try_read_from(&mut self, _bytes: &[u8]) -> Option> { assert_on_allowlist!( test_try_read_from($ty): @@ -1294,9 +1317,9 @@ mod tests { Option, Option, Option, - MaybeUninit, - MaybeUninit, - MaybeUninit>, + CoreMaybeUninit, + CoreMaybeUninit, + CoreMaybeUninit>, ManuallyDrop>, ManuallyDrop<[UnsafeCell]>, ManuallyDrop<[UnsafeCell]>, @@ -1377,8 +1400,10 @@ mod tests { let bytes_mut = &mut vec.as_mut_slice()[offset..offset+size]; bytes_mut.copy_from_slice(bytes); - let res = <$ty as TryFromBytes>::try_mut_from_bytes(bytes_mut); - assert!(res.is_ok(), "{}::try_mut_from_bytes({:?}): got `Err`, expected `Ok`", stringify!($ty), val); + let res = ww.test_try_from_mut(bytes_mut); + if let Some(res) = res { + assert!(res.is_some(), "{}::try_mut_from_bytes({:?}): got `None`, expected `Some`", stringify!($ty), val); + } } let res = bytes.and_then(|bytes| ww.test_try_read_from(bytes)); @@ -1398,8 +1423,11 @@ mod tests { assert!(res.is_none(), "{}::try_ref_from_bytes({:?}): got Some, expected None", stringify!($ty), c); } - let res = <$ty as TryFromBytes>::try_mut_from_bytes(c); - assert!(res.is_err(), "{}::try_mut_from_bytes({:?}): got Ok, expected Err", stringify!($ty), c); + let res = w.test_try_from_mut(c); + if let Some(res) = res { + assert!(res.is_none(), "{}::try_mut_from_bytes({:?}): got Some, expected None", stringify!($ty), c); + } + let res = w.test_try_read_from(c); if let Some(res) = res { @@ -1552,6 +1580,16 @@ mod tests { IntoBytes, !Unaligned ); + #[cfg(feature = "float-nightly")] + assert_impls!( + f16: KnownLayout, + Immutable, + TryFromBytes, + FromZeros, + FromBytes, + IntoBytes, + !Unaligned + ); assert_impls!( f32: KnownLayout, Immutable, @@ -1570,7 +1608,16 @@ mod tests { IntoBytes, !Unaligned ); - + #[cfg(feature = "float-nightly")] + assert_impls!( + f128: KnownLayout, + Immutable, + TryFromBytes, + FromZeros, + FromBytes, + IntoBytes, + !Unaligned + ); assert_impls!( bool: KnownLayout, Immutable, @@ -1758,9 +1805,9 @@ mod tests { assert_impls!(ManuallyDrop<[UnsafeCell]>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable); assert_impls!(ManuallyDrop<[UnsafeCell]>: KnownLayout, TryFromBytes, FromZeros, IntoBytes, Unaligned, !Immutable, !FromBytes); - assert_impls!(MaybeUninit: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes); - assert_impls!(MaybeUninit: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned); - assert_impls!(MaybeUninit>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes); + assert_impls!(CoreMaybeUninit: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes); + assert_impls!(CoreMaybeUninit: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned); + assert_impls!(CoreMaybeUninit>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes); assert_impls!(Wrapping: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); // This test is important because it allows us to test our hand-rolled @@ -1882,7 +1929,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..2a505b20c1 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 } } @@ -451,6 +451,7 @@ impl DstLayout { /// rely on `validate_cast_and_convert_metadata` panicking in any particular /// condition, even if `debug_assertions` are enabled. #[allow(unused)] + #[inline(always)] pub(crate) const fn validate_cast_and_convert_metadata( &self, addr: usize, @@ -458,9 +459,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 +475,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 +528,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 +572,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 +589,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::*; @@ -812,16 +797,15 @@ mod tests { /// This macro accepts arguments in the form of: /// - /// layout(_, _, _).validate(_, _, _), Ok(Some((_, _))) - /// | | | | | | | | - /// base_size ----+ | | | | | | | - /// align -----------+ | | | | | | - /// trailing_size ------+ | | | | | - /// addr ---------------------------+ | | | | - /// bytes_len -------------------------+ | | | - /// cast_type ----------------------------+ | | - /// elems ---------------------------------------------+ | - /// split_at ---------------------------------------------+ + /// layout(_, _).validate(_, _, _), Ok(Some((_, _))) + /// | | | | | | | + /// size ---------+ | | | | | | + /// align -----------+ | | | | | + /// addr ------------------------+ | | | | + /// bytes_len ----------------------+ | | | + /// cast_type -------------------------+ | | + /// elems ------------------------------------------+ | + /// split_at ------------------------------------------+ /// /// `.validate` is shorthand for `.validate_cast_and_convert_metadata` /// for brevity. @@ -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 @@ -854,7 +838,7 @@ mod tests { /// `a..b`). In this case, wrap the expression in parentheses, and it /// will become valid `tt`. macro_rules! test { - ($(:$sizes:expr =>)? + ( layout($size:tt, $align:tt) .validate($addr:tt, $bytes_len:tt, $cast_type:tt), $expect:pat $(,)? ) => { @@ -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..81d62fb070 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -137,6 +137,10 @@ //! available on nightly. Since these types are unstable, support for any type //! may be removed at any point in the future. //! +//! - **`float-nightly`** +//! Adds support for the unstable `f16` and `f128` types. These types are +//! not yet fully implemented and may not be supported on all platforms. +//! //! [duplicate-import-errors]: https://github.com/google/zerocopy/issues/1587 //! [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html //! @@ -198,12 +202,20 @@ //! Zerocopy uses [GitHub Releases]. //! //! [GitHub Releases]: https://github.com/google/zerocopy/releases +//! +//! # Thanks +//! +//! Zerocopy is maintained by engineers at Google and Amazon with help from +//! [many wonderful contributors][contributors]. Thank you to everyone who has +//! lent a hand in making Rust a little more secure! +//! +//! [contributors]: https://github.com/google/zerocopy/graphs/contributors // 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, unreachable_patterns)] +#![allow(unknown_lints, non_local_definitions, unreachable_patterns)] #![deny(renamed_and_removed_lints)] #![deny( anonymous_parameters, @@ -248,6 +260,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, @@ -303,10 +316,11 @@ all(feature = "simd-nightly", any(target_arch = "powerpc", target_arch = "powerpc64")), feature(stdarch_powerpc) )] +#![cfg_attr(feature = "float-nightly", feature(f16, f128))] #![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, coverage_attribute, marker_trait_attr) )] // This is a hack to allow zerocopy-derive derives to work in this crate. They @@ -321,7 +335,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 @@ -349,7 +362,7 @@ use core::{ fmt::{self, Debug, Display, Formatter}, hash::Hasher, marker::PhantomData, - mem::{self, ManuallyDrop, MaybeUninit}, + mem::{self, ManuallyDrop, MaybeUninit as CoreMaybeUninit}, num::{ NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, @@ -359,7 +372,13 @@ use core::{ slice, }; -use crate::pointer::{invariant, BecauseExclusive, BecauseImmutable}; +#[cfg(feature = "std")] +use std::io; + +use crate::pointer::{ + invariant::{self, BecauseExclusive}, + transmute::BecauseRead, +}; #[cfg(any(feature = "alloc", test))] extern crate alloc; @@ -371,7 +390,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 +413,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 @@ -724,6 +722,15 @@ pub unsafe trait KnownLayout { /// This is `()` for sized types and `usize` for slice DSTs. type PointerMetadata: PointerMetadata; + /// A maybe-uninitialized analog of `Self` + /// + /// # Safety + /// + /// `Self::LAYOUT` and `Self::MaybeUninit::LAYOUT` are identical. + /// `Self::MaybeUninit` admits uninitialized bytes in all positions. + #[doc(hidden)] + type MaybeUninit: ?Sized + KnownLayout; + /// The layout of `Self`. /// /// # Safety @@ -856,6 +863,35 @@ unsafe impl KnownLayout for [T] { type PointerMetadata = usize; + // SAFETY: `CoreMaybeUninit::LAYOUT` and `T::LAYOUT` are identical + // because `CoreMaybeUninit` has the same size and alignment as `T` [1]. + // Consequently, `[CoreMaybeUninit]::LAYOUT` and `[T]::LAYOUT` are + // identical, because they both lack a fixed-sized prefix and because they + // inherit the alignments of their inner element type (which are identical) + // [2][3]. + // + // `[CoreMaybeUninit]` admits uninitialized bytes at all positions + // because `CoreMaybeUninit` admits uninitialized bytes at all positions + // and because the inner elements of `[CoreMaybeUninit]` are laid out + // back-to-back [2][3]. + // + // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as + // `T` + // + // [2] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#slice-layout: + // + // Slices have the same layout as the section of the array they slice. + // + // [3] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#array-layout: + // + // An array of `[T; N]` has a size of `size_of::() * N` and the same + // alignment of `T`. Arrays are laid out so that the zero-based `nth` + // element of the array is offset from the start of the array by `n * + // size_of::()` bytes. + type MaybeUninit = [CoreMaybeUninit]; + const LAYOUT: DstLayout = DstLayout::for_slice::(); // SAFETY: `.cast` preserves address and provenance. The returned pointer @@ -904,13 +940,23 @@ impl_known_layout!( NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize ); #[rustfmt::skip] +#[cfg(feature = "float-nightly")] +impl_known_layout!( + #[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] + f16, + #[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] + f128 +); +#[rustfmt::skip] impl_known_layout!( T => Option, T: ?Sized => PhantomData, T => Wrapping, - T => MaybeUninit, + T => CoreMaybeUninit, T: ?Sized => *const T, - T: ?Sized => *mut T + T: ?Sized => *mut T, + T: ?Sized => &'_ T, + T: ?Sized => &'_ mut T, ); impl_known_layout!(const N: usize, T => [T; N]); @@ -941,12 +987,27 @@ safety_comment! { unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] UnsafeCell); } +safety_comment! { + /// SAFETY: + /// - By consequence of the invariant on `T::MaybeUninit` that `T::LAYOUT` + /// and `T::MaybeUninit::LAYOUT` are equal, `T` and `T::MaybeUninit` + /// have the same: + /// - Fixed prefix size + /// - Alignment + /// - (For DSTs) trailing slice element size + /// - By consequence of the above, referents `T::MaybeUninit` and `T` have + /// the require the same kind of pointer metadata, and thus it is valid to + /// perform an `as` cast from `*mut T` and `*mut T::MaybeUninit`, and this + /// operation preserves referent size (ie, `size_of_val_raw`). + unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T::MaybeUninit)] MaybeUninit); +} + /// Analyzes whether a type is [`FromZeros`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies -/// the [safety conditions] of `FromZeros` and implements `FromZeros` if it is -/// sound to do so. This derive can be applied to structs, enums, and unions; -/// e.g.: +/// the [safety conditions] of `FromZeros` and implements `FromZeros` and its +/// supertraits if it is sound to do so. This derive can be applied to structs, +/// enums, and unions; e.g.: /// /// ``` /// # use zerocopy_derive::{FromZeros, Immutable}; @@ -1203,6 +1264,26 @@ pub unsafe trait Immutable { /// } /// ``` /// +/// # Portability +/// +/// To ensure consistent endianness for enums with multi-byte representations, +/// explicitly specify and convert each discriminant using `.to_le()` or +/// `.to_be()`; e.g.: +/// +/// ``` +/// # use zerocopy_derive::TryFromBytes; +/// // `DataStoreVersion` is encoded in little-endian. +/// #[derive(TryFromBytes)] +/// #[repr(u32)] +/// pub enum DataStoreVersion { +/// /// Version 1 of the data store. +/// V1 = 9u32.to_le(), +/// +/// /// Version 2 of the data store. +/// V2 = 10u32.to_le(), +/// } +/// ``` +/// /// [safety conditions]: trait@TryFromBytes#safety #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] @@ -1341,9 +1422,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`. /// @@ -1645,8 +1724,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], @@ -1663,17 +1742,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -1701,7 +1780,7 @@ pub unsafe trait TryFromBytes { #[inline] fn try_mut_from_bytes(bytes: &mut [u8]) -> Result<&mut Self, TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); match Ptr::from_mut(bytes).try_cast_into_no_leftover::(None) { @@ -1714,7 +1793,7 @@ pub unsafe trait TryFromBytes { // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. - match source.try_into_valid() { + match source.try_into_valid::<(pointer::transmute::BecauseRead, _)>() { Ok(source) => Ok(source.as_mut()), Err(e) => { Err(e.map_src(|src| src.as_bytes::().as_mut()).into()) @@ -1753,8 +1832,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], @@ -1771,17 +1850,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -1814,7 +1893,7 @@ pub unsafe trait TryFromBytes { source: &mut [u8], ) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); try_mut_from_prefix_suffix(source, CastType::Prefix, None) @@ -1848,8 +1927,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], @@ -1866,17 +1945,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -1909,7 +1988,7 @@ pub unsafe trait TryFromBytes { source: &mut [u8], ) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); try_mut_from_prefix_suffix(source, CastType::Suffix, None).map(swap) @@ -1983,7 +2062,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 +2169,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 +2258,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); /// ``` @@ -2218,17 +2297,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -2262,14 +2341,15 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// 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); /// ``` @@ -2282,7 +2362,7 @@ pub unsafe trait TryFromBytes { count: usize, ) -> Result<&mut Self, TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { match Ptr::from_mut(source).try_cast_into_no_leftover::(Some(count)) { @@ -2295,7 +2375,7 @@ pub unsafe trait TryFromBytes { // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. - match source.try_into_valid() { + match source.try_into_valid::<(BecauseRead, _)>() { Ok(source) => Ok(source.as_mut()), Err(e) => { Err(e.map_src(|src| src.as_bytes::().as_mut()).into()) @@ -2328,17 +2408,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -2374,14 +2454,15 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// 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); /// ``` @@ -2394,7 +2475,7 @@ pub unsafe trait TryFromBytes { count: usize, ) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { try_mut_from_prefix_suffix(source, CastType::Prefix, Some(count)) } @@ -2422,17 +2503,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -2468,14 +2549,15 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// 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); /// ``` @@ -2488,7 +2570,7 @@ pub unsafe trait TryFromBytes { count: usize, ) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { try_mut_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap) } @@ -2539,7 +2621,7 @@ pub unsafe trait TryFromBytes { where Self: Sized, { - let candidate = match MaybeUninit::::read_from_bytes(source) { + let candidate = match CoreMaybeUninit::::read_from_bytes(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); @@ -2600,7 +2682,7 @@ pub unsafe trait TryFromBytes { where Self: Sized, { - let (candidate, suffix) = match MaybeUninit::::read_from_prefix(source) { + let (candidate, suffix) = match CoreMaybeUninit::::read_from_prefix(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); @@ -2662,7 +2744,7 @@ pub unsafe trait TryFromBytes { where Self: Sized, { - let (prefix, candidate) = match MaybeUninit::::read_from_suffix(source) { + let (prefix, candidate) = match CoreMaybeUninit::::read_from_suffix(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); @@ -2700,7 +2782,7 @@ fn try_ref_from_prefix_suffix( +fn try_mut_from_prefix_suffix( candidate: &mut [u8], cast_type: CastType, meta: Option, @@ -2715,7 +2797,7 @@ fn try_mut_from_prefix_suffix( // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. - match candidate.try_into_valid() { + match candidate.try_into_valid::<(pointer::transmute::BecauseRead, _)>() { Ok(valid) => Ok((valid.as_mut(), prefix_suffix.as_mut())), Err(e) => Err(e.map_src(|src| src.as_bytes::().as_mut()).into()), } @@ -2735,7 +2817,7 @@ fn swap((t, u): (T, U)) -> (U, T) { #[inline(always)] unsafe fn try_read_from( source: S, - mut candidate: MaybeUninit, + mut candidate: CoreMaybeUninit, ) -> Result> { // We use `from_mut` despite not mutating via `c_ptr` so that we don't need // to add a `T: Immutable` bound. @@ -3024,88 +3106,11 @@ pub unsafe trait FromZeros: TryFromBytes { where Self: KnownLayout, { - let size = match count.size_for_metadata(Self::LAYOUT) { - Some(size) => size, - None => return Err(AllocError), - }; - - 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. - let layout = Layout::from_size_align(size, align).or(Err(AllocError))?; - - let ptr = if layout.size() != 0 { - // TODO(#429): Add a "SAFETY" comment and remove this `allow`. - #[allow(clippy::undocumented_unsafe_blocks)] - let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) }; - match NonNull::new(ptr) { - Some(ptr) => ptr, - 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 - // enough to realize that we're only executing this branch when - // we're constructing a zero-sized `Box`, which doesn't require - // provenance. - // - // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. - // All bits of a `usize` are initialized. - #[allow(clippy::useless_transmute)] - let dangling = unsafe { mem::transmute::(align) }; - // SAFETY: `dangling` is constructed from `Self::LAYOUT.align`, - // which is a `NonZeroUsize`, which is guaranteed to be non-zero. - // - // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` - // is zero, but it does require a non-null dangling pointer for its - // allocation. - // - // TODO(https://github.com/rust-lang/rust/issues/95228): Use - // `std::ptr::without_provenance` once it's stable. That may - // optimize better. As written, Rust may assume that this consumes - // "exposed" provenance, and thus Rust may have to assume that this - // may consume provenance from any pointer whose provenance has been - // exposed. - #[allow(fuzzy_provenance_casts)] - unsafe { - NonNull::new_unchecked(dangling) - } - }; - - let ptr = Self::raw_from_ptr_len(ptr, count); - - // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure - // to include a justification that `ptr.as_ptr()` is validly-aligned in - // the ZST case (in which we manually construct a dangling pointer). - #[allow(clippy::undocumented_unsafe_blocks)] - 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) + // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of + // `new_box`. The referent of the pointer returned by `alloc_zeroed` + // (and, consequently, the `Box` derived from it) is a valid instance of + // `Self`, because `Self` is `FromZeros`. + unsafe { crate::util::new_box(count, alloc::alloc::alloc_zeroed) } } /// Creates a `Vec` from zeroed bytes. @@ -3141,7 +3146,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 +3164,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] @@ -3201,8 +3204,9 @@ pub unsafe trait FromZeros: TryFromBytes { /// Analyzes whether a type is [`FromBytes`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies -/// the [safety conditions] of `FromBytes` and implements `FromBytes` if it is -/// sound to do so. This derive can be applied to structs, enums, and unions; +/// the [safety conditions] of `FromBytes` and implements `FromBytes` and its +/// supertraits if it is sound to do so. This derive can be applied to structs, +/// enums, and unions; /// e.g.: /// /// ``` @@ -3507,7 +3511,7 @@ pub unsafe trait FromBytes: FromZeros { { static_assert_dst_is_not_zst!(Self); match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) { - Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_ref()), + Ok(ptr) => Ok(ptr.transmute().as_ref()), Err(err) => Err(err.map_src(|src| src.as_ref())), } } @@ -3743,7 +3747,7 @@ pub unsafe trait FromBytes: FromZeros { { static_assert_dst_is_not_zst!(Self); match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) { - Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_mut()), + Ok(ptr) => Ok(ptr.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>().as_mut()), Err(err) => Err(err.map_src(|src| src.as_mut())), } } @@ -3982,7 +3986,7 @@ pub unsafe trait FromBytes: FromZeros { let source = Ptr::from_ref(source); let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); match maybe_slf { - Ok(slf) => Ok(slf.bikeshed_recall_valid().as_ref()), + Ok(slf) => Ok(slf.transmute().as_ref()), Err(err) => Err(err.map_src(|s| s.as_ref())), } } @@ -4181,8 +4185,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 +4204,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( @@ -4213,7 +4217,7 @@ pub unsafe trait FromBytes: FromZeros { let source = Ptr::from_mut(source); let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); match maybe_slf { - Ok(slf) => Ok(slf.bikeshed_recall_valid().as_mut()), + Ok(slf) => Ok(slf.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>().as_mut()), Err(err) => Err(err.map_src(|s| s.as_mut())), } } @@ -4522,103 +4526,54 @@ pub unsafe trait FromBytes: FromZeros { } } - #[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"] + /// Reads a copy of `self` from an `io::Read`. + /// + /// This is useful for interfacing with operating system byte sinks (files, + /// sockets, etc.). + /// + /// # Examples + /// + /// ```no_run + /// use zerocopy::{byteorder::big_endian::*, FromBytes}; + /// use std::fs::File; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromBytes)] + /// #[repr(C)] + /// struct BitmapFileHeader { + /// signature: [u8; 2], + /// size: U32, + /// reserved: U64, + /// offset: U64, + /// } + /// + /// let mut file = File::open("image.bin").unwrap(); + /// let header = BitmapFileHeader::read_from_io(&mut file).unwrap(); + /// ``` + #[cfg(feature = "std")] #[inline(always)] - fn read_from(source: &[u8]) -> Option + fn read_from_io(mut src: R) -> io::Result where Self: Sized, + R: io::Read, { - Self::read_from_bytes(source).ok() + // NOTE(#2319, #2320): We do `buf.zero()` separately rather than + // constructing `let buf = CoreMaybeUninit::zeroed()` because, if `Self` + // contains padding bytes, then a typed copy of `CoreMaybeUninit` + // will not necessarily preserve zeros written to those padding byte + // locations, and so `buf` could contain uninitialized bytes. + let mut buf = CoreMaybeUninit::::uninit(); + buf.zero(); + + let ptr = Ptr::from_mut(&mut buf); + // SAFETY: After `buf.zero()`, `buf` consists entirely of initialized, + // zeroed bytes. + let ptr = unsafe { ptr.assume_validity::() }; + let ptr = ptr.as_bytes::(); + src.read_exact(ptr.as_mut())?; + // SAFETY: `buf` entirely consists of initialized bytes, and `Self` is + // `FromBytes`. + Ok(unsafe { buf.assume_init() }) } } @@ -4638,7 +4593,7 @@ fn ref_from_prefix_suffix( let (slf, prefix_suffix) = Ptr::from_ref(source) .try_cast_into::<_, BecauseImmutable>(cast_type, meta) .map_err(|err| err.map_src(|s| s.as_ref()))?; - Ok((slf.bikeshed_recall_valid().as_ref(), prefix_suffix.as_ref())) + Ok((slf.transmute().as_ref(), prefix_suffix.as_ref())) } /// Interprets the given affix of the given bytes as a `&mut Self` without @@ -4650,7 +4605,7 @@ fn ref_from_prefix_suffix( /// If there are insufficient bytes, or if that affix of `source` is not /// appropriately aligned, this returns `Err`. #[inline(always)] -fn mut_from_prefix_suffix( +fn mut_from_prefix_suffix( source: &mut [u8], meta: Option, cast_type: CastType, @@ -4658,7 +4613,10 @@ fn mut_from_prefix_suffix( let (slf, prefix_suffix) = Ptr::from_mut(source) .try_cast_into::<_, BecauseExclusive>(cast_type, meta) .map_err(|err| err.map_src(|s| s.as_mut()))?; - Ok((slf.bikeshed_recall_valid().as_mut(), prefix_suffix.as_mut())) + Ok(( + slf.transmute::, _, (BecauseRead, _), _>().as_mut(), + prefix_suffix.as_mut(), + )) } /// Analyzes whether a type is [`IntoBytes`]. @@ -5207,14 +5165,53 @@ 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] + /// Writes a copy of `self` to an `io::Write`. + /// + /// This is a shorthand for `dst.write_all(self.as_bytes())`, and is useful + /// for interfacing with operating system byte sinks (files, sockets, etc.). + /// + /// # Examples + /// + /// ```no_run + /// use zerocopy::{byteorder::big_endian::U16, FromBytes, IntoBytes}; + /// use std::fs::File; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] + /// #[repr(C, packed)] + /// struct GrayscaleImage { + /// height: U16, + /// width: U16, + /// pixels: [U16], + /// } + /// + /// let image = GrayscaleImage::ref_from_bytes(&[0, 0, 0, 0][..]).unwrap(); + /// let mut file = File::create("image.bin").unwrap(); + /// image.write_to_io(&mut file).unwrap(); + /// ``` + /// + /// If the write fails, `write_to_io` returns `Err` and a partial write may + /// have occured; e.g.: + /// + /// ``` + /// # use zerocopy::IntoBytes; + /// + /// let src = u128::MAX; + /// let mut dst = [0u8; 2]; + /// + /// let write_result = src.write_to_io(&mut dst[..]); + /// + /// assert!(write_result.is_err()); + /// assert_eq!(dst, [255, 255]); + /// ``` + #[cfg(feature = "std")] + #[inline(always)] + fn write_to_io(&self, mut dst: W) -> io::Result<()> where - Self: FromBytes, + Self: Immutable, + W: io::Write, { - self.as_mut_bytes() + dst.write_all(self.as_bytes()) } } @@ -5360,51 +5357,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; @@ -5969,6 +5927,50 @@ mod tests { assert_eq!(bytes, want); } + #[test] + #[cfg(feature = "std")] + fn test_read_io_with_padding_soundness() { + // This test is designed to exhibit potential UB in + // `FromBytes::read_from_io`. (see #2319, #2320). + + // On most platforms (where `align_of::() == 2`), `WithPadding` + // will have inter-field padding between `x` and `y`. + #[derive(FromBytes)] + #[repr(C)] + struct WithPadding { + x: u8, + y: u16, + } + struct ReadsInRead; + impl std::io::Read for ReadsInRead { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + // This body branches on every byte of `buf`, ensuring that it + // exhibits UB if any byte of `buf` is uninitialized. + if buf.iter().all(|&x| x == 0) { + Ok(buf.len()) + } else { + buf.iter_mut().for_each(|x| *x = 0); + Ok(buf.len()) + } + } + } + assert!(matches!(WithPadding::read_from_io(ReadsInRead), Ok(WithPadding { x: 0, y: 0 }))); + } + + #[test] + #[cfg(feature = "std")] + fn test_read_write_io() { + let mut long_buffer = [0, 0, 0, 0]; + assert!(matches!(u16::MAX.write_to_io(&mut long_buffer[..]), Ok(()))); + assert_eq!(long_buffer, [255, 255, 0, 0]); + assert!(matches!(u16::read_from_io(&long_buffer[..]), Ok(u16::MAX))); + + let mut short_buffer = [0, 0]; + assert!(u32::MAX.write_to_io(&mut short_buffer[..]).is_err()); + assert_eq!(short_buffer, [255, 255]); + assert!(u32::read_from_io(&short_buffer[..]).is_err()); + } + #[test] fn test_try_from_bytes_try_read_from() { assert_eq!(::try_read_from_bytes(&[0]), Ok(false)); @@ -6262,7 +6264,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 +6281,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 +6297,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 +6328,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/macros.rs b/src/macros.rs index d1d32c81b4..51200bf54e 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -249,8 +249,8 @@ macro_rules! transmute_ref { /// const fn transmute_mut<'src, 'dst, Src, Dst>(src: &'src mut Src) -> &'dst mut Dst /// where /// 'src: 'dst, -/// Src: FromBytes + IntoBytes + Immutable, -/// Dst: FromBytes + IntoBytes + Immutable, +/// Src: FromBytes + IntoBytes, +/// Dst: FromBytes + IntoBytes, /// size_of::() == size_of::(), /// align_of::() >= align_of::(), /// { @@ -325,9 +325,9 @@ macro_rules! transmute_mut { #[allow(unused, clippy::diverging_sub_expression)] if false { // This branch, though never taken, ensures that the type of `e` is - // `&mut T` where `T: 't + Sized + FromBytes + IntoBytes + Immutable` - // and that the type of this macro expression is `&mut U` where `U: - // 'u + Sized + FromBytes + IntoBytes + Immutable`. + // `&mut T` where `T: 't + Sized + FromBytes + IntoBytes` and that + // the type of this macro expression is `&mut U` where `U: 'u + + // Sized + FromBytes + IntoBytes`. // We use immutable references here rather than mutable so that, if // this macro is used in a const context (in which, as of this @@ -577,8 +577,8 @@ macro_rules! try_transmute_ref { /// ```ignore /// fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> /// where -/// Src: IntoBytes, -/// Dst: TryFromBytes, +/// Src: FromBytes + IntoBytes, +/// Dst: TryFromBytes + IntoBytes, /// size_of::() == size_of::(), /// align_of::() >= align_of::(), /// { @@ -888,9 +888,9 @@ mod tests { #[test] fn test_try_transmute_mut() { // Test that memory is transmuted with `try_transmute_mut` as expected. - let array_of_bools = &mut [false, true, false, true, false, true, false, true]; + let array_of_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; - let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools); + let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_u8s); assert_eq!(x, Ok(array_of_arrays)); let array_of_bools = &mut [false, true, false, true, false, true, false, true]; @@ -903,8 +903,8 @@ mod tests { let array_of_bools = &mut [false, true, false, true, false, true, false, true]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; { - let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools); - assert_eq!(x, Ok(array_of_arrays)); + let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays); + assert_eq!(x, Ok(array_of_bools)); } // Test that `try_transmute_mut!` supports decreasing alignment. 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..ac0938424f --- /dev/null +++ b/src/pointer/inner.rs @@ -0,0 +1,540 @@ +// 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]. + /// + /// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `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`. + ptr: NonNull, + // SAFETY: `&'a UnsafeCell` is covariant in `'a` and invariant in `T` + // [1]. We use this construction rather than the equivalent `&mut T`, + // because our MSRV of 1.65 prohibits `&mut` types in const contexts. + // + // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance + _marker: PhantomData<&'a core::cell::UnsafeCell>, + } + + 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) 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) 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) 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) 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 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.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( + 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); + + // 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..06c2733ce2 --- /dev/null +++ b/src/pointer/invariant.rs @@ -0,0 +1,337 @@ +// 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]. +//! +//! A `Ptr` has the following invariants: +//! - [`V: Validity`][validity-trait] encodes the bit validity of `Ptr`'s +//! referent, which is of type [`V::Inner`][validity-inner] +//! - [`I: Invariants`][invariants-trait], where +//! [`I::Aliasing`][invariants-aliasing] and +//! [`I::Alignment`][invariants-alignment] encode the `Ptr`'s aliasing and +//! alignment invariants respectively +//! +//! [validity-trait]: Validity +//! [validity-inner]: Validity::Inner +//! [invariants-trait]: Invariants +//! [invariants-aliasing]: Invariants::Aliasing +//! [invariants-alignment]: Invariants::Alignment + +use core::marker::PhantomData; + +/// The aliasing and alignment invariants of a [`Ptr`][super::Ptr]. +pub trait Invariants: Sealed { + type Aliasing: Aliasing; + type Alignment: Alignment; + + /// Invariants identical to `Self` except with a different aliasing + /// invariant. + type WithAliasing: Invariants; + + /// Invariants identical to `Self` except with a different alignment + /// invariant. + type WithAlignment: Invariants; +} + +impl Invariants for (A, AA) { + type Aliasing = A; + type Alignment = AA; + + type WithAliasing = (AB, AA); + type WithAlignment = (A, AB); +} + +/// The aliasing invariant of a [`Ptr`][super::Ptr]. +/// +/// All aliasing invariants must permit reading from the bytes of a pointer's +/// referent which are not covered by [`UnsafeCell`]s. +/// +/// [`UnsafeCell`]: core::cell::UnsafeCell +pub trait Aliasing: Sealed { + /// Is `Self` [`Exclusive`]? + #[doc(hidden)] + const IS_EXCLUSIVE: bool; +} + +/// 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]. +/// +/// A `V: Validity` defines both the referent type of a `Ptr` +/// ([`V::Inner`](Validity::Inner)) and the bit validity of the referent value. +/// Bit validity specifies a set, `S`, of possible values which may exist at the +/// `Ptr`'s referent. Code operating on a `Ptr` may assume that bit validity +/// holds - namely, that it will only observe referent values in `S`. It must +/// also uphold bit validity - namely, it must only write values in `S` to the +/// referent. +/// +/// The specific definition of `S` for a given validity type (i.e., `V: +/// Validity`) is documented on that type. +/// +/// The available validities are [`Uninit`], [`AsInitialized`], [`Initialized`], +/// and [`Valid`]. +pub trait Validity: Sealed { + type Inner: ?Sized; + type WithInner: Validity; + + #[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; +} + +/// A validity which permits arbitrary bytes - including uninitialized bytes - +/// at any byte offset. +pub struct Uninit(PhantomData); + +impl Validity for Uninit { + type Inner = T; + type WithInner = Uninit; + + type MappedTo = M::FromUninit; +} + +/// 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; +} +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; +} +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 struct AsInitialized(PhantomData); +impl Validity for AsInitialized { + type Inner = T; + type WithInner = 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 struct Initialized(PhantomData); +impl Validity for Initialized { + type Inner = T; + type WithInner = Initialized; + type MappedTo = M::FromInitialized; +} + +/// The referent is bit-valid for `T`. +pub struct Valid(PhantomData); +impl Validity for Valid { + type Inner = T; + type WithInner = 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 Uninit {} + + 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) {} +} + +pub use mapping::*; +mod mapping { + use super::*; + + /// 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 FromUninit: Validity; + type FromAsInitialized: Validity; + type FromInitialized: Validity; + type FromValid: Validity; + } + + /// 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 = + as Validity>::WithInner; + + impl AlignmentMapping + for ((Unknown, FromUnknown), (Shared, FromAligned)) + { + type FromUnknown = FromUnknown; + type FromAligned = FromAligned; + } + + impl< + FromUninit: Validity, + FromAsInitialized: Validity, + FromInitialized: Validity, + FromValid: Validity, + > ValidityMapping + for ( + (Unknown, FromUninit), + (AsInitialized, FromAsInitialized), + (Initialized, FromInitialized), + (Valid, FromValid), + ) + { + type FromUninit = FromUninit::WithInner; + type FromAsInitialized = FromAsInitialized::WithInner; + type FromInitialized = FromInitialized::WithInner; + type FromValid = FromValid::WithInner; + } + + impl ValidityMapping for (Initialized, FromInitialized) { + type FromUninit = Uninit; + type FromAsInitialized = Uninit; + type FromInitialized = FromInitialized::WithInner; + type FromValid = Uninit; + } +} diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 1533eb9efd..ddaf1600f6 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -8,11 +8,16 @@ //! Abstractions over raw pointers. -mod aliasing_safety; +mod inner; +#[doc(hidden)] +pub mod invariant; mod ptr; +pub(crate) mod transmute; -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,38 +25,45 @@ 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> = - Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>; +pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = + Ptr<'a, invariant::Initialized, (Aliasing, Alignment)>; /// 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> = - Ptr<'a, T, (Aliasing, Alignment, invariant::Valid)>; +pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = + Ptr<'a, invariant::Valid, (Aliasing, Alignment)>; // These methods are defined on the type alias, `MaybeAligned`, so as to bring // them to the forefront of the rendered rustdoc for that type alias. 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`]. @@ -66,11 +78,11 @@ where } /// Checks if the referent is zeroed. -pub(crate) fn is_zeroed(ptr: Ptr<'_, T, I>) -> bool +pub(crate) fn is_zeroed(ptr: Ptr<'_, invariant::Initialized, I>) -> bool where T: crate::Immutable + crate::KnownLayout, - I: invariant::Invariants, - I::Aliasing: invariant::AtLeast, + I: invariant::Invariants, + 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..b676b2b6b9 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -6,78 +6,62 @@ // 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. /// - /// `Ptr` is similar to [`NonNull`], but it is more restrictive in the - /// following ways (note that these requirements only hold of non-zero-sized - /// referents): + /// `Ptr` where [`V: Validity`](Validity) is similar to + /// [`NonNull`], but it is more restrictive in the following ways + /// (note that these requirements only hold of non-zero-sized referents): /// - It must derive from a valid allocation. /// - It must reference a byte range which is contained inside the /// allocation from which it derives. /// - As a consequence, the byte range it references must have a size /// which does not overflow `isize`. /// - /// Depending on how `Ptr` is parameterized, it may have additional + /// Depending on how `Ptr` is parameterized, it may have additional /// invariants: + /// - `ptr` conforms to the validity invariant of [`V`](invariant::Validity) /// - `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). /// - `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// - `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). /// - /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. + /// `Ptr<'a, T>` is [covariant] in `'a` and invariant in `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html - pub struct Ptr<'a, T, I> + pub struct Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, + V::Inner: 'a, 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`'s referent conforms to the validity invariant of + /// [`V`](invariant::Validity) + /// 1. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 8. `ptr` conforms to the alignment invariant of + /// 2. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 9. `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 in `'a` and invariant in `T`. + ptr: PtrInner<'a, V::Inner>, + _invariants: PhantomData, } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { /// Constructs a `Ptr` from a [`NonNull`]. @@ -97,239 +81,74 @@ mod def { /// address space. /// 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to /// live for at least `'a`. - /// 6. `ptr` conforms to the aliasing invariant of + /// 6. `ptr` conforms to the validity invariant of + /// [`V`](invariant::Validity). + /// 7. `ptr` conforms to the aliasing invariant of + /// [`I::Aliasing`](invariant::Aliasing). + /// 8. `ptr` conforms to the alignment invariant of + /// [`I::Alignment`](invariant::Alignment). + pub(super) const unsafe fn new(ptr: NonNull) -> Ptr<'a, V, 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, _invariants: PhantomData } + } + + /// Constructs a new `Ptr` from a [`PtrInner`]. + /// + /// # Safety + /// + /// The caller promises that: + /// + /// 0. `ptr` conforms to the validity invariant of + /// [`V`](invariant::Validity). + /// 1. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 7. `ptr` conforms to the alignment invariant of + /// 2. `ptr` conforms to the alignment invariant of /// [`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 from_inner(ptr: PtrInner<'a, V::Inner>) -> Ptr<'a, V, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. Self { ptr, _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, V::Inner> { 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> + impl Copy for Ptr<'_, V, I> where - T: 'a + ?Sized, - I: Invariants, - Shared: AtLeast, + V: Validity, + 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> + impl Clone for Ptr<'_, V, I> where - T: 'a + ?Sized, - I: Invariants, - Shared: AtLeast, + V: Validity, + I: Invariants, { #[inline] fn clone(&self) -> Self { @@ -337,14 +156,14 @@ mod _external { } } - impl<'a, T, I> Debug for Ptr<'a, T, I> + impl Debug for Ptr<'_, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - self.as_non_null().fmt(f) + self.as_inner().as_non_null().fmt(f) } } } @@ -352,84 +171,51 @@ mod _external { /// Methods for converting to and from `Ptr` and Rust's safe reference types. mod _conversions { use super::*; - use crate::util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance}; + use crate::{ + pointer::transmute::{CastFrom, TransmuteFromAlignment, TransmuteFromPtr}, + util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance}, + }; /// `&'a T` → `Ptr<'a, T>` - impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Shared, Aligned)> { /// Constructs a `Ptr` from a shared reference. #[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 validity + // invariant of `Valid`. + // 1. `ptr`, by invariant on `&'a T`, conforms to the aliasing // invariant of `Shared`. - // 8. `ptr`, by invariant on `&'a T`, conforms to the alignment + // 2. `ptr`, by invariant on `&'a T`, conforms to the alignment // invariant of `Aligned`. - // 9. `ptr`, by invariant on `&'a T`, conforms to the validity - // invariant of `Valid`. - unsafe { Self::new(ptr) } + unsafe { Self::from_inner(inner) } } } /// `&'a mut T` → `Ptr<'a, T>` - impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Exclusive, Aligned)> { /// 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 validity + // invariant of `Valid`. + // 1. `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 + // 2. `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 - // invariant of `Valid`. - unsafe { Self::new(ptr) } + unsafe { Self::from_inner(inner) } } } /// `Ptr<'a, T>` → `&'a T` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, T: ?Sized, I> Ptr<'a, Valid, I> where - T: 'a + ?Sized, - I: Invariants, - I::Aliasing: AtLeast, + I: Invariants, + I::Aliasing: Reference, { /// Converts `self` to a shared reference. // This consumes `self`, not `&self`, because `self` is, logically, a @@ -438,7 +224,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 +239,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`. + // is ensured by-contract on `Ptr`, because the 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 @@ -471,11 +257,11 @@ mod _conversions { } } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, - I::Aliasing: AtLeast, + I::Aliasing: Reference, { /// Reborrows `self`, producing another `Ptr`. /// @@ -485,31 +271,20 @@ mod _conversions { #[doc(hidden)] #[inline] #[allow(clippy::needless_lifetimes)] // Allows us to name the lifetime in the safety comment below. - pub fn reborrow<'b>(&'b mut self) -> Ptr<'b, T, I> + pub fn reborrow<'b>(&'b mut self) -> Ptr<'b, V, I> where '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 - // [`I::Alignment`](invariant::Alignment). - // 8. `ptr` conforms to the validity invariant of - // [`I::Validity`](invariant::Validity). + // hold of `ptr = self.as_inner()`: + // 0. `ptr` conforms to the validity invariant of + // [`V`](invariant::Validity). + // 1. SEE BELOW. + // 2. `ptr` conforms to the alignment invariant of + // [`I::Alignment`](invariant::Alignment). // - // For aliasing (6 above), since `I::Aliasing: AtLeast`, - // there are two cases for `I::Aliasing`: + // For aliasing, 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 // longer than is possible via `self`. For shared aliasing, it is @@ -525,19 +300,16 @@ 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()) } } } /// `Ptr<'a, T>` → `&'a mut T` - impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Exclusive, Aligned)> { /// 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 +324,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 is + // `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because the `ALIASING_INVARIANT` is @@ -568,10 +340,59 @@ mod _conversions { } } + /// `Ptr<'a, T>` → `Ptr<'a, U>` + impl<'a, V, I> Ptr<'a, V, I> + where + V: Validity, + I: Invariants, + { + /// # Safety + /// - TODO: `UnsafeCell` agreement + /// - The caller promises that the returned `Ptr` satisfies alignment + /// `A` + /// - The caller promises that the returned `Ptr` satisfies validity `V` + pub(crate) unsafe fn transmute_unchecked(self) -> Ptr<'a, U, (I::Aliasing, A)> + where + A: Alignment, + U: Validity, + U::Inner: CastFrom, + { + // SAFETY: + // - By invariant on `CastFrom::cast_from`: + // - This cast preserves address and referent size, and thus the + // returned pointer addresses the same bytes as `p` + // - This cast preserves provenance + // - TODO: `UnsafeCell` agreement + let ptr = + unsafe { self.cast_unsized_unchecked::(|p| U::Inner::cast_from(p)) }; + // SAFETY: The caller promises that alignment is satisfied. + let ptr = unsafe { ptr.assume_alignment() }; + // SAFETY: The caller promises that validity is satisfied. + let ptr = unsafe { ptr.assume_validity::() }; + ptr.unify_validity() + } + + pub(crate) fn transmute(self) -> Ptr<'a, U, (I::Aliasing, A)> + where + A: Alignment, + U: TransmuteFromPtr, + U::Inner: TransmuteFromAlignment + CastFrom, + { + // SAFETY: + // - TODO: `UnsafeCell` agreement + // - By invariant on `TransmuteFromPtr`, it is sound to treat the + // resulting pointer as having alignment `A` + // - By invariant on `TransmuteFromPtr`, it is sound to treat the + // resulting pointer as having validity `V` + unsafe { self.transmute_unchecked() } + } + } + /// `Ptr<'a, T = Wrapper>` → `Ptr<'a, U>` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + TransparentWrapper + ?Sized, + V: 'a + Validity, + V::Inner: TransparentWrapper, I: Invariants, { /// Converts `self` to a transparent wrapper type into a `Ptr` to the @@ -580,11 +401,15 @@ mod _conversions { self, ) -> Ptr< 'a, - T::Inner, + <::ValidityVariance as ValidityVariance>::Applied< + V, + ::Inner, + >, ( I::Aliasing, - >::Applied, - >::Applied, + <::AlignmentVariance as AlignmentVariance>::Applied< + I::Alignment, + >, ), > { // SAFETY: @@ -597,33 +422,38 @@ 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(V::Inner::cast_into_inner) }; // SAFETY: By invariant on `TransparentWrapper`, since `self` // satisfies the alignment invariant `I::Alignment`, `c` (of type // `T::Inner`) satisfies the given "applied" alignment invariant. let c = unsafe { - c.assume_alignment::<>::Applied>() + c.assume_alignment::<<::AlignmentVariance as AlignmentVariance>::Applied::>() }; // SAFETY: By invariant on `TransparentWrapper`, since `self` - // satisfies the validity invariant `I::Validity`, `c` (of type - // `T::Inner`) satisfies the given "applied" validity invariant. + // satisfies the validity invariant `V`, `c` (of type + // `V::Inner::Inner`) satisfies the given "applied" validity + // invariant. let c = unsafe { - c.assume_validity::<>::Applied>() + c.assume_validity::<<::ValidityVariance as ValidityVariance>::Applied::Inner>>() }; - c + c.unify_validity() } } /// `Ptr<'a, T, (_, _, _)>` → `Ptr<'a, Unalign, (_, Aligned, _)>` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where + V: Validity, I: Invariants, { /// 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)> { + ) -> Ptr<'a, V::WithInner>, I::WithAlignment> + where + V::Inner: Sized, + { // SAFETY: // - This cast preserves provenance. // - This cast preserves address. `Unalign` promises to have the @@ -633,15 +463,15 @@ 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 V::Inner| p as *mut crate::Unalign) }; // SAFETY: `Unalign` promises to have the same bit validity as // `T`. - let ptr = unsafe { ptr.assume_validity::() }; + let ptr = unsafe { ptr.assume_validity::() }; // SAFETY: `Unalign` promises to have alignment 1, and so it is // trivially aligned. let ptr = unsafe { ptr.assume_alignment::() }; - ptr + ptr.unify_invariants() } } } @@ -649,11 +479,14 @@ mod _conversions { /// State transitions between invariants. mod _transitions { use super::*; - use crate::{AlignmentError, TryFromBytes, ValidityError}; + use crate::{ + pointer::transmute::{CastFrom, TransmuteFromPtr, TryTransmuteFromPtr}, + AlignmentError, TryFromBytes, ValidityError, + }; - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { /// Returns a `Ptr` with [`Exclusive`] aliasing if `self` already has @@ -662,78 +495,75 @@ 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, V, 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() } } - /// Assumes that `self` satisfies the invariants `H`. + /// Assumes that `self` satisfies the invariants `W` and `H`. /// /// # Safety /// - /// The caller promises that `self` satisfies the invariants `H`. - unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { + /// The caller promises that `self` satisfies the invariants `W` and + /// `H`. + const unsafe fn assume_invariants, H: Invariants>( + self, + ) -> Ptr<'a, W, 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< - H: Invariants, - >( - self, - ) -> Ptr<'a, T, H> { + pub(crate) const fn unify_invariants(self) -> Ptr<'a, V, H> + where + H: Invariants, + { // SAFETY: The associated type bounds on `H` ensure that the // invariants are unchanged. - unsafe { self.assume_invariants::() } + unsafe { self.assume_invariants::() } + } + + /// Helps the type system unify two distinct validity invariants which + /// are actually the same. + pub(crate) const fn unify_validity(self) -> Ptr<'a, W, I> + where + W: Validity = V>, + { + // SAFETY: The associated type bounds on `W` ensure that the + // validity invariant is unchanged. In particular, `Inner = + // V::Inner` ensures that the target types are the same, and + // `WithInner = V` ensures that `W` and `V` are the same + // type of validity (e.g., both `Initialized`). + unsafe { self.assume_invariants::() } } /// Assumes that `self` satisfies the aliasing requirement of `A`. @@ -743,9 +573,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, V, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `A`. unsafe { self.assume_invariants() } @@ -758,11 +588,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, V, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `Exclusive`. unsafe { self.assume_aliasing::() } @@ -776,9 +606,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, V, 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 +618,13 @@ mod _transitions { /// on success. pub(crate) fn bikeshed_try_into_aligned( self, - ) -> Result, AlignmentError> + ) -> Result>, AlignmentError> where - T: Sized, + V::Inner: Sized, { - if let Err(err) = crate::util::validate_aligned_to::<_, T>(self.as_non_null()) { + if let Err(err) = + crate::util::validate_aligned_to::<_, V::Inner>(self.as_inner().as_non_null()) + { return Err(err.with_src(self)); } @@ -804,11 +636,9 @@ 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, V, I::WithAlignment> where - T: crate::Unaligned, + V::Inner: crate::Unaligned, { // SAFETY: The bound `T: Unaligned` ensures that `T` has no // non-trivial alignment requirement. @@ -816,20 +646,20 @@ mod _transitions { } /// Assumes that `self`'s referent conforms to the validity requirement - /// of `V`. + /// of `W`. /// /// # Safety /// /// The caller promises that `self`'s referent conforms to the validity - /// requirement of `V`. + /// requirement of `W`. #[doc(hidden)] #[must_use] #[inline] - pub unsafe fn assume_validity( + pub const unsafe fn assume_validity( self, - ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)> { + ) -> Ptr<'a, W::WithInner, I> { // SAFETY: The caller promises that `self`'s referent conforms to - // the validity requirement of `V`. + // the validity requirement of `W`. unsafe { self.assume_invariants() } } @@ -842,12 +672,10 @@ 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, Initialized, I> { // SAFETY: The caller has promised to uphold the safety // preconditions. - unsafe { self.assume_validity::() } + unsafe { self.assume_validity::>() } } /// A shorthand for `self.assume_validity()`. @@ -859,28 +687,55 @@ 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, Valid, I> { // SAFETY: The caller has promised to uphold the safety // preconditions. - unsafe { self.assume_validity::() } + unsafe { self.assume_validity::>() } + } + + /// Forgets that `self`'s referent is validly-aligned for `T`. + #[doc(hidden)] + #[must_use] + #[inline] + pub const fn forget_aligned(self) -> Ptr<'a, V, I::WithAlignment> { + // SAFETY: `Unknown` is less restrictive than `Aligned`. + unsafe { self.assume_invariants() } + } + } + + impl<'a, V, I> Ptr<'a, V, I> + where + V: Validity, + I: Invariants, + I::Aliasing: Reference, + { + /// Forgets that `self` is an `Exclusive` pointer, downgrading it to a + /// `Shared` pointer. + #[doc(hidden)] + #[must_use] + #[inline] + pub const fn forget_exclusive(self) -> Ptr<'a, V, I::WithAliasing> { + unsafe { self.assume_invariants() } } + } + impl<'a, T, I> Ptr<'a, Initialized, I> + where + T: ?Sized, + I: Invariants, + { /// Recalls that `self`'s referent is bit-valid for `T`. #[doc(hidden)] #[must_use] #[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 fn bikeshed_recall_valid(self) -> Ptr<'a, Valid, I> where - T: crate::FromBytes, - I: Invariants, + Valid: TransmuteFromPtr, I::Aliasing, R>, + as Validity>::Inner: CastFrom, { - // SAFETY: The bound `T: FromBytes` ensures that any initialized - // sequence of bytes is bit-valid for `T`. `I: Invariants` ensures that all of the referent bytes - // are initialized. - unsafe { self.assume_valid() } + self.transmute().unify_invariants() } /// Checks that `self`'s referent is validly initialized for `T`, @@ -896,18 +751,22 @@ 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, I>, ValidityError> where - T: TryFromBytes, - I::Aliasing: AtLeast, - I: Invariants, + T: TryFromBytes, // + Read, + Valid: TryTransmuteFromPtr, I::Aliasing, R>, + // NOTE: This bound ought to be implied, but leaving it out causes + // Rust to infinite loop during trait solving. + as Validity>::Inner: + crate::pointer::transmute::CastFrom< as Validity>::Inner>, + I::Aliasing: Reference, { // 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() }) @@ -915,27 +774,56 @@ mod _transitions { Err(ValidityError::new(self)) } } + } - /// Forgets that `self`'s referent exclusively references `T`, - /// downgrading to a shared reference. - #[doc(hidden)] - #[must_use] + impl<'a, V, I> Ptr<'a, V, I> + where + V: Validity, + I: Invariants, + { + /// Attempts to transmute a `Ptr` into a `Ptr`. + /// + /// # Panics + /// + /// This method will panic if + /// [`U::is_bit_valid`][TryFromBytes::is_bit_valid] panics. + /// + /// # Safety + /// + /// On success, the returned `Ptr` addresses the same bytes as `self`. + /// + /// On error, unsafe code may rely on this method's returned + /// `ValidityError` containing `self`. #[inline] - pub fn forget_exclusive(self) -> Ptr<'a, T, (Shared, I::Alignment, I::Validity)> + pub(crate) fn try_transmute( + mut self, + ) -> Result>, ValidityError> where - I::Aliasing: AtLeast, + U: Validity + TryTransmuteFromPtr, + U::Inner: TryFromBytes + CastFrom, + Initialized: TransmuteFromPtr, + // TODO: The `Sized` bound here is only required in order to call + // `.bikeshed_try_into_aligned`. There are other ways of getting the + // alignment of a type, and we could use these if we need to drop + // this bound. + as Validity>::Inner: Sized + CastFrom, + I::Aliasing: Reference, { - // SAFETY: `I::Aliasing` is at least as restrictive as `Shared`. - unsafe { self.assume_invariants() } - } + let is_bit_valid = { + let ptr = self.reborrow(); + let ptr = ptr.transmute::, Unknown, _, _>(); + // 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. + ::is_bit_valid(ptr) + }; - /// 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`. - unsafe { self.assume_invariants() } + if is_bit_valid { + let ptr = unsafe { self.transmute_unchecked() }; + Ok(ptr.unify_invariants()) + } else { + Err(ValidityError::new(self)) + } } } } @@ -943,18 +831,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::{pointer::transmute::BecauseRead, CastError, SizeError}; - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, 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 +851,19 @@ 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 T>( self, cast: F, - ) -> Ptr<'a, U, (I::Aliasing, Any, Any)> { - let ptr = cast(self.as_non_null().as_ptr()); + ) -> Ptr<'a, MappedValidity, (I::Aliasing, Unknown)> + { + 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 +871,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 @@ -1001,7 +890,14 @@ mod _casts { // space. // 5. By invariant on `self`, if `self`'s referent is not zero // sized, then `A` is guaranteed to live for at least `'a`. - // 6. `ptr` conforms to the aliasing invariant of `I::Aliasing`: + // 6. If `V = Unknown`, `AsInitialized`, or `Valid`, the output + // validity invariant is `Unknown`. `ptr` trivially conforms to + // this invariant. If `V = 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. + // 7. `ptr` conforms to the aliasing invariant of `I::Aliasing`: // - `Exclusive`: `self` is the only `Ptr` or reference which is // permitted to read or modify the referent for the lifetime // `'a`. Since we consume `self` by value, the returned pointer @@ -1024,26 +920,55 @@ mod _casts { // pointer will permit mutation of this byte during `'a`, by // invariant on `self`, no other code assumes that this will // not happen. - // 7. `ptr`, trivially, conforms to the alignment invariant of - // `Any`. - // 8. `ptr`, trivially, conforms to the validity invariant of `Any`. + // - `Inaccessible`: There are no restrictions we need to uphold. + // 8. `ptr`, trivially, conforms to the alignment invariant of + // `Unknown`. 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, MappedValidity, (I::Aliasing, Unknown)> + where + V::Inner: Read, + T: 'a + ?Sized + Read, + F: FnOnce(*mut V::Inner) -> *mut T, + { + // SAFETY: Because `T::Inner` and `W` both implement + // `Read`, either: + // - `I::Aliasing` is `Exclusive` + // - `V::Inner` and `W` 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> + impl<'a, T, I> Ptr<'a, Initialized, I> where - T: 'a + KnownLayout + ?Sized, - I: Invariants, + T: ?Sized + KnownLayout, + I: Invariants, { /// Casts this pointer-to-initialized into a pointer-to-bytes. #[allow(clippy::wrong_self_convention)] - pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> + pub(crate) fn as_bytes(self) -> Ptr<'a, Valid<[u8]>, (I::Aliasing, Aligned)> 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,101 +983,57 @@ 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 { + let ptr: Ptr<'a, Initialized<[u8]>, _> = unsafe { self.cast_unsized(|p: *mut T| { #[allow(clippy::as_conversions)] core::ptr::slice_from_raw_parts_mut(p.cast::(), bytes) }) }; - 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::<(BecauseRead, _)>() } } - impl<'a, T, I, const N: usize> Ptr<'a, [T; N], I> + impl<'a, V, T, I, const N: usize> Ptr<'a, V, I> where - T: 'a, + V: Validity, I: Invariants, { /// 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. + pub(crate) fn as_slice(self) -> Ptr<'a, V::WithInner<[T]>, I> { + 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. - // 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. - // 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) } + // 6. By the above lemma, `slice` conforms to the validity invariant + // of `V` because `self` does. + // 7. Thus, `slice` conforms to the aliasing invariant of + // `I::Aliasing` because `self` does. + // 8. By the above lemma, `slice` conforms to the alignment + // invariant of `I::Alignment` because `self` does. + unsafe { Ptr::from_inner(slice) } } } /// For caller convenience, these methods are generic over alignment /// invariant. In practice, the referent is always well-aligned, because the /// alignment of `[u8]` is 1. - impl<'a, I> Ptr<'a, [u8], I> + impl<'a, I> Ptr<'a, Valid<[u8]>, I> where - I: Invariants, + I: Invariants, { - /// Attempts to cast `self` to a `U` using the given cast type. + /// Attempts to cast `self` to a `Ptr>` using the given + /// cast type. /// - /// If `U` is a slice DST and pointer metadata (`meta`) is provided, + /// If `T` 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`. + /// Returns `None` if the resulting `T` would be invalidly-aligned, if + /// no `T` can fit in `self`, or if the provided pointer metadata + /// describes an invalid instance of `T`. On success, returns a pointer + /// to the largest-possible `T` which fits in `self`. /// /// # Safety /// @@ -1165,122 +1046,65 @@ mod _casts { /// - 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) fn try_cast_into( + #[inline(always)] + pub(crate) fn try_cast_into( self, cast_type: CastType, - meta: Option, + meta: Option, ) -> Result< - (Ptr<'a, U, (I::Aliasing, Aligned, Initialized)>, Ptr<'a, [u8], I>), - CastError, + (Ptr<'a, Initialized, (I::Aliasing, Aligned)>, Ptr<'a, Valid<[u8]>, I>), + CastError, > where - R: AliasingSafeReason, - U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, + I::Aliasing: Reference, + T: KnownLayout + Read + ?Sized, { - 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. 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)) + // 1. Since `W: Read`, either: + // - `I::Aliasing` is `Exclusive`, in which case both `src` and + // `ptr` conform to `Exclusive` + // - `I::Aliasing` is `Shared` or `Inaccessible` and `W` is + // `Immutable` (we already know that `[u8]: Immutable`). In + // this case, neither `W` nor `[u8]` permit mutation, and so + // `Shared` aliasing is satisfied. `Inaccessible` is trivially + // satisfied since it imposes no requirements. + // 2. `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 `W`. + let res = unsafe { Ptr::from_inner(inner) }; + + // SAFETY: + // 0. `self` has validity `Valid` and has type `[u8]`. Since + // `remainder` references a subset of `self`'s referent, it is + // also bit-valid. + // 1. `self` and `remainder` both have the type `[u8]`. Thus, they + // have `UnsafeCell`s at the same locations. Type casting does + // not affect aliasing. + // 2. `[u8]` has no alignment requirement. + let remainder = unsafe { Ptr::from_inner(remainder) }; + + Ok((res, remainder)) } - /// Attempts to cast `self` into a `U`, failing if all of the bytes of - /// `self` cannot be treated as a `U`. + /// Attempts to cast `self` into a `Ptr>`, failing if all + /// of the bytes of `self`'s referent cannot be treated as a `T`. /// /// In particular, this method fails if `self` is not validly-aligned - /// for `U` or if `self`'s size is not a valid size for `U`. + /// for `T` or if `self`'s size is not a valid size for `T`. /// /// # Safety /// @@ -1288,17 +1112,14 @@ mod _casts { /// references the same byte range as `self`. #[allow(unused)] #[inline(always)] - pub(crate) fn try_cast_into_no_leftover( + pub(crate) fn try_cast_into_no_leftover( self, - meta: Option, - ) -> Result, CastError> + meta: Option, + ) -> Result, (I::Aliasing, Aligned)>, CastError> where - U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, - R: AliasingSafeReason, + I::Aliasing: Reference, + T: ?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 { @@ -1317,7 +1138,7 @@ mod _casts { // `slf`. let slf = unsafe { slf.assume_alignment::() }; let slf = slf.unify_invariants(); - Err(CastError::Size(SizeError::<_, U>::new(slf))) + Err(CastError::Size(SizeError::<_, T>::new(slf))) } } Err(err) => Err(err), @@ -1325,9 +1146,9 @@ mod _casts { } } - impl<'a, T, I> Ptr<'a, core::cell::UnsafeCell, I> + impl<'a, V, T: ?Sized, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity>, I: Invariants, { /// Converts this `Ptr` into a pointer to the underlying data. @@ -1340,12 +1161,9 @@ mod _casts { /// [`UnsafeCell::get_mut`]: core::cell::UnsafeCell::get_mut #[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. + pub fn get_mut(self) -> Ptr<'a, V::WithInner, I> { + // 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) }; @@ -1372,7 +1190,7 @@ mod _casts { // `UnsafeCell` has the same in-memory representation as its // inner type `T`. A consequence of this guarantee is that it is // possible to convert between `T` and `UnsafeCell`. - let ptr = unsafe { ptr.assume_validity::() }; + let ptr = unsafe { ptr.assume_validity::() }; ptr.unify_invariants() } } @@ -1380,294 +1198,58 @@ 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> - where - T: 'a + ?Sized, - I: Invariants, - { - /// Projects a field from `self`. - /// - /// # Safety - /// - /// `project` has the same safety preconditions as `cast_unsized`. - #[doc(hidden)] - #[inline] - pub unsafe fn project( - self, - projector: impl FnOnce(*mut T) -> *mut U, - ) -> Ptr<'a, U, (I::Aliasing, Any, 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::() } - } - } - - impl<'a, T, I> Ptr<'a, T, I> + impl Ptr<'_, V, I> where - T: 'a + KnownLayout + ?Sized, + V: Validity, 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() } } - impl<'a, T, I> Ptr<'a, [T], I> + impl<'a, V, T, I> Ptr<'a, V, I> where - T: 'a, + V: Validity, 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) } - }) + pub(crate) fn iter(&self) -> impl Iterator, I>> { + // SAFETY: + // 0. `elem`, conditionally, conforms to the validity invariant of + // `V`. If `elem` is projected from data valid for `[T]`, `elem` + // will be valid for `T`. + // 1. `elem` conforms to the aliasing invariant of `I::Aliasing` + // because projection does not impact the aliasing invariant. + // 2. `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`. + 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::*; + use crate::IntoBytes; // This test is designed so that if `Ptr::try_cast_into_xxx` are // buggy, it will manifest as unsoundness that Miri can detect. @@ -1707,8 +1289,10 @@ mod tests { }; // SAFETY: The bytes in `slf` must be initialized. - unsafe fn validate_and_get_len( - slf: Ptr<'_, T, (Shared, Aligned, Initialized)>, + unsafe fn validate_and_get_len< + T: ?Sized + KnownLayout + FromBytes + Immutable, + >( + slf: Ptr<'_, Initialized, (Shared, Aligned)>, ) -> usize { let t = slf.bikeshed_recall_valid().as_ref(); @@ -1751,7 +1335,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 +1346,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 +1362,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 +1423,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 +1434,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/pointer/transmute.rs b/src/pointer/transmute.rs new file mode 100644 index 0000000000..c6d266ca44 --- /dev/null +++ b/src/pointer/transmute.rs @@ -0,0 +1,505 @@ +// Copyright 2025 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::{ + cell::UnsafeCell, + mem::{ManuallyDrop, MaybeUninit}, + num::Wrapping, +}; + +use crate::{pointer::invariant::*, FromBytes, Immutable, IntoBytes, Unalign}; + +define_because!(pub(crate) BecauseBidirectional); +define_because!(pub(crate) BecauseRead); +define_because!(pub(crate) BecauseFoo); +define_because!(BecauseExclusive); +define_because!(BecauseUnchanged); +define_because!(BecauseUnaligned); + +// TODO: Confirm that we don't need to explicitly mention size (that should be +// handled automatically by impls, usually via a `TransmuteFrom` bound). + +/// # Safety +/// +/// ## Post-conditions +/// +/// Given `Dst: TryTransmuteFromPtr`, callers may assume the +/// following: +/// +/// Given `src: Ptr` where `SI: Invariants`, if the referent of `src` contains a `Dst` which conforms to the +/// validity `DV`, then it is sound to transmute `src` into `dst: Ptr` +/// whre `DI: Invariants`. +/// +/// TODO: Mention alignment +/// +/// ## Pre-conditions +/// +/// Given `src: Ptr`, `dst: Ptr`, `SI: Invariants`, and `DV: Invariants`, `Dst: +/// TryTransmuteFromPtr` is sound if all of the following +/// hold: +/// - Forwards transmutation: Any of the following hold: +/// - So long as `dst` is active, no mutation of `dst`'s referent is allowed +/// except via `dst` itself +/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid +/// `Src`s +/// - Reverse transmutation: Any of the following hold: +/// - `dst` does not permit mutation of its referent +/// - The set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid +/// `Src`s +/// - `UnsafeCell` agreement: TODO +/// +/// ## Proof +/// +/// TODO: Prove that the pre-conditions imply the post-conditions. +#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, marker)] +pub(crate) unsafe trait TryTransmuteFromPtr: + Validity +where + Self::Inner: CastFrom, +{ +} + +// SAFETY: +// - Forwards transmutation: Since `Src::Inner: Read`, one of the +// following holds: +// - `Src: Immutable`, so no mutation of `dst`'s referent is permitted via +// `src`. No other references to the same referent may exist which are typed +// using `T: !Immutable`, as this would permit violating `Src: Immutable`'s +// soundness precondition. +// - Aliasing `A` is `Exclusive`, so `dst` is the only reference permitted to +// mutate its referent. +// - Reverse transmutation: Since `Src: TransmuteFrom`, `Dst`'s validity +// set is a subset of `Src`'s validity set. +// - Since `Src::Inner: Read` and `Dst::Inner: Read`, one of the following +// holds: +// - Aliasing `A` is `Exclusive`, in which case `UnsafeCell`s do not need to +// agree +// - `Src::Inner: Immutable` and `Dst::Inner: Immutable`, in which case +// `UnsafeCell`s trivially agree +unsafe impl TryTransmuteFromPtr for Dst +where + Src: Validity + TransmuteFrom, + Dst: Validity, + Src::Inner: Read, + Dst::Inner: Read + CastFrom, + A: Aliasing, +{ +} + +unsafe impl TryTransmuteFromPtr for Dst +where + Src: Validity, + Dst: Validity, + Src::Inner: Immutable, + Dst::Inner: Immutable + CastFrom, +{ +} + +// SAFETY: +// - Forwards transmutation: `Dst: TransmuteFrom` guarantees that +// the set of `DV`-valid `Dst`s is a supserset of the set of `SV`-valid +// `Src`s. +// - Reverse transmutation: `Src: TransmuteFrom` guarantees that +// the set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s. +// - `UnsafeCell` agreement guaranteed by `Src: UnsafeCellsAgree + Dst: +// UnsafeCellsAgree`. +unsafe impl TryTransmuteFromPtr for Dst +where + A: Aliasing, + Src: Validity + TransmuteFrom, + Dst: Validity + TransmuteFrom, + Src::Inner: UnsafeCellsAgree, + Dst::Inner: UnsafeCellsAgree + CastFrom, +{ +} + +// SAFETY: +// - Forwards transmutation: `Src: Immutable` guarantees that no mutation of +// `dst`'s referent is possible via `src`. No other references to the same +// referent may exist which are typed using `T: !Immutable`, as this would +// permit violating `Src: Immutable`'s soundness precondition. +// - Reverse transmutation: `Src: TransmuteFrom` guarantees that +// the set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s. +// - `UnsafeCell` agreement guaranteed by `Src: Immutable + Dst: Immutable`. +unsafe impl TryTransmuteFromPtr for Dst +where + A: Aliasing, + Src: Validity + TransmuteFrom, + Dst: Validity, + Src::Inner: Immutable, + Dst::Inner: Immutable + CastFrom, +{ +} + +// TODO: Try to delete this impl and see if things still work + +// SAFETY: +// - Forwards transmutation: Because aliasing is `Exclusive`, `dst` is the only +// reference permitted to mutate its referent. +// - Reverse transmutation: `Src: TransmuteFrom` guarantees that +// the set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s. +// - `UnsafeCell` agreement is not necessary because aliasing is `Exclusive`. +unsafe impl TryTransmuteFromPtr for Dst +where + Src: Validity + TransmuteFrom, + Dst: Validity, + Dst::Inner: CastFrom, +{ +} + +#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, marker)] +pub(crate) unsafe trait TransmuteFromPtr: + TryTransmuteFromPtr + TransmuteFrom +where + Self::Inner: CastFrom, +{ +} + +unsafe impl TransmuteFromPtr for Dst +where + Dst::Inner: CastFrom, + Dst: TransmuteFrom + TryTransmuteFromPtr, +{ +} + +#[marker] +pub(crate) unsafe trait TransmuteFromAlignment {} + +pub(crate) unsafe trait CastFrom { + /// Casts a `*mut T` to a `*mut Self`. + /// + /// # Safety + /// + /// The resulting pointer has the same address and provenance as `ptr`, and + /// addresses the same number of bytes. + fn cast_from(ptr: *mut Src) -> *mut Self; +} + +/// Pairs of types which have `UnsafeCells` covering the same byte ranges. +/// +/// # Safety +/// +/// Let `t: &T` and `u: &U`. Let `len = min(size_of_val(t), size_of_val(u))`. If +/// `U: UnsafeCellsAgree`, then the first `len` bytes of `t` and the first +/// `len` bytes of `u` have `UnsafeCell`s covering the same byte ranges. This +/// condition must hold for all `t: &T` and for all `u: &U`. +/// +/// Note that this safety invariant supports either or both of `T` and `U` being +/// unsized. +pub(crate) unsafe trait UnsafeCellsAgree +where + T: UnsafeCellsAgree, +{ +} + +// SAFETY: `T` has `UnsafeCell`s covering the same byte ranges as itself by +// definition. +unsafe impl UnsafeCellsAgree for T {} + +#[marker] +pub(crate) unsafe trait TransmuteFrom {} + +unsafe impl CastFrom for Src { + fn cast_from(ptr: *mut Src) -> *mut Src { + // SAFETY: `ptr` trivially has the same address as, addresses the same + // number of bytes as, and has the same provenance as `ptr`. + ptr + } +} + +unsafe impl TransmuteFrom for Src {} + +unsafe impl TransmuteFromAlignment for Src {} +unsafe impl + TransmuteFromAlignment for Dst +{ +} + +// TODO: Make sure to clarify that, for unsized types, this specifically refers +// to a cast that does not perform a metadata fix-up operation. +pub(crate) unsafe trait SizeGtEq {} + +unsafe impl SizeGtEq for T {} + +unsafe impl TransmuteFrom> for Valid +where + Dst: FromBytes, + Src: SizeGtEq, +{ +} + +unsafe impl TransmuteFrom> for Valid +where + Src: IntoBytes, + Dst: FromBytes, + Src: SizeGtEq, +{ +} + +unsafe impl TransmuteFrom> for Initialized +where + Src: IntoBytes, + Src: SizeGtEq, +{ +} + +// SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges as +// `T`. This is not explicitly documented, but it can be inferred. Per [1] in +// the following safety comment, `MaybeUninit` has the same size as `T`. +// Further, note the signature of `MaybeUninit::assume_init_ref` [1]: +// +// pub unsafe fn assume_init_ref(&self) -> &T +// +// If the argument `&MaybeUninit` and the returned `&T` had `UnsafeCell`s at +// different offsets, this would be unsound. Its existence is proof that this is +// not the case. +// +// [1] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref +unsafe impl UnsafeCellsAgree for MaybeUninit {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + +unsafe impl TransmuteFrom for Valid> where + Src::Inner: Sized +{ +} +unsafe impl TransmuteFrom for AsInitialized> where + Src::Inner: Sized +{ +} + +unsafe impl TransmuteFrom> for Initialized> {} + +unsafe impl TransmuteFrom>> for Initialized {} + +unsafe impl TransmuteFromAlignment + for MaybeUninit +{ +} +unsafe impl TransmuteFromAlignment, A, A, BecauseUnchanged> + for Src +{ +} + +unsafe impl CastFrom for MaybeUninit { + fn cast_from(ptr: *mut Src) -> *mut MaybeUninit { + // SAFETY: `.cast()` preserves address and provenance. Since + // `MaybeUninit` has the same size as `Src` [1], it also preserves + // size. + // + // [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, + // and ABI as `T`. + ptr.cast() + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut MaybeUninit) -> *mut Src { + // SAFETY: `.cast()` preserves address and provenance. Since + // `MaybeUninit` has the same size as `Src` [1], it also preserves + // size. + // + // [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, + // and ABI as `T`. + ptr.cast() + } +} + +// SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: +// +// `ManuallyDrop` is guaranteed to have the same layout and bit validity as +// `T`, and is subject to the same layout optimizations as `T`. As a +// consequence, it has no effect on the assumptions that the compiler makes +// about its contents. +unsafe impl UnsafeCellsAgree for ManuallyDrop {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + +unsafe impl TransmuteFrom for Src::WithInner> {} +unsafe impl TransmuteFrom>> for Src {} + +unsafe impl TransmuteFromAlignment + for ManuallyDrop +{ +} +unsafe impl + TransmuteFromAlignment, A, A, BecauseUnchanged> for Src +{ +} + +unsafe impl CastFrom for ManuallyDrop { + fn cast_from(ptr: *mut Src) -> *mut ManuallyDrop { + // SAFETY: An `as` cast preserves address and provenance. Since + // `ManuallyDrop` has the same size as `Src` [1], it also preserves + // size. + // + // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T` + ptr as *mut ManuallyDrop + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut ManuallyDrop) -> *mut Src { + // SAFETY: An `as` cast preserves address and provenance. Since + // `ManuallyDrop` has the same size as `Src` [1], it also preserves + // size. + // + // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T` + ptr as *mut Src + } +} + +// SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its single +// field (of type `T`) is public, it would be a breaking change to add or remove +// fields. Thus, we know that `Wrapping` contains a `T` (as opposed to just +// having the same size and alignment as `T`) with no pre- or post-padding. +// Thus, `Wrapping` must have `UnsafeCell`s covering the same byte ranges as +// `Inner = T`. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: +// +// `Wrapping` is guaranteed to have the same layout and ABI as `T`. +unsafe impl UnsafeCellsAgree for Wrapping {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + +unsafe impl TransmuteFrom for Src::WithInner> where + Src::Inner: Sized +{ +} +unsafe impl TransmuteFrom>> for Src where + Src::Inner: Sized +{ +} + +unsafe impl TransmuteFromAlignment + for Wrapping +{ +} +unsafe impl TransmuteFromAlignment, A, A, BecauseUnchanged> + for Src +{ +} + +unsafe impl CastFrom for Wrapping { + fn cast_from(ptr: *mut Src) -> *mut Wrapping { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Wrapping` has the same size as `Src` [1], it also preserves size. + // + // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: + // + // `Wrapping` is guaranteed to have the same layout and ABI as `T`. + ptr.cast() + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut Wrapping) -> *mut Src { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Wrapping` has the same size as `Src` [1], it also preserves size. + // + // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: + // + // `Wrapping` is guaranteed to have the same layout and ABI as `T`. + ptr.cast() + } +} + +unsafe impl TransmuteFrom for Src::WithInner> {} +unsafe impl TransmuteFrom>> for Src {} + +unsafe impl TransmuteFromAlignment + for UnsafeCell +{ +} +unsafe impl + TransmuteFromAlignment, A, A, BecauseUnchanged> for Src +{ +} + +unsafe impl CastFrom for UnsafeCell { + fn cast_from(ptr: *mut Src) -> *mut UnsafeCell { + // SAFETY: An `as` cast preserves address and provenance. Since + // `UnsafeCell` has the same size as `Src`, it also preserves size. + // + // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: + // + // `UnsafeCell` has the same in-memory representation as its inner + // type `T`. + ptr as *mut UnsafeCell + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut UnsafeCell) -> *mut Src { + // SAFETY: An `as` cast preserves address and provenance. Since + // `UnsafeCell` has the same size as `Src`, it also preserves size. + // + // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: + // + // `UnsafeCell` has the same in-memory representation as its inner + // type `T`. + ptr as *mut Src + } +} + +// SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +unsafe impl UnsafeCellsAgree for Unalign {} +// SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +unsafe impl UnsafeCellsAgree> for T {} + +unsafe impl TransmuteFrom for Src::WithInner> where + Src::Inner: Sized +{ +} +unsafe impl TransmuteFrom>> for Src where + Src::Inner: Sized +{ +} + +unsafe impl TransmuteFromAlignment + for Unalign +{ +} +unsafe impl TransmuteFromAlignment, A, Unknown, BecauseUnchanged> + for Src +{ +} + +unsafe impl CastFrom for Unalign { + fn cast_from(ptr: *mut Src) -> *mut Unalign { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Unalign` has the same size as `T`, it also preserves size. + ptr.cast() + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut Unalign) -> *mut Src { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Unalign` has the same size as `T`, it also preserves size. + ptr.cast() + } +} diff --git a/src/ref.rs b/src/ref.rs index 0f4ce00214..153b4e1d3b 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) @@ -624,7 +624,7 @@ where let ptr = Ptr::from_ref(b.into_byte_slice()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: into_ref should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.transmute(); ptr.as_ref() } } @@ -658,7 +658,7 @@ where let ptr = Ptr::from_mut(b.into_byte_slice_mut()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: into_ref should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>(); ptr.as_mut() } } @@ -770,7 +770,7 @@ where let ptr = Ptr::from_ref(b.deref()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: Deref::deref should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.transmute(); ptr.as_ref() } } @@ -799,7 +799,7 @@ where let ptr = Ptr::from_mut(b.deref_mut()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: DerefMut::deref_mut should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>(); ptr.as_mut() } } diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index f7e66056d2..817dc36142 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -26,12 +26,26 @@ use core::ptr::{self, NonNull}; use crate::{ pointer::{ - invariant::{self, AtLeast, Invariants}, - AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable, + invariant::{self, Valid}, + transmute::{CastFrom, SizeGtEq, TransmuteFrom}, }, - Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, + FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, ValidityError, }; +/// Projects the type of the field at `Index` in `Self`. +/// +/// The `Index` parameter is any sort of handle that identifies the field; its +/// definition is the obligation of the implementer. +/// +/// # Safety +/// +/// Unsafe code may assume that this accurately reflects the definition of +/// `Self`. +pub unsafe trait Field { + /// The type of the field at `Index`. + type Type: ?Sized; +} + #[cfg_attr( zerocopy_diagnostic_on_unimplemented, diagnostic::on_unimplemented( @@ -424,7 +438,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 +483,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 @@ -506,83 +515,6 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( unsafe { &mut *dst } } -/// Is a given source a valid instance of `Dst`? -/// -/// If so, returns `src` casted to a `Ptr`. Otherwise returns `None`. -/// -/// # Safety -/// -/// Unsafe code may assume that, if `try_cast_or_pme(src)` returns `Some`, -/// `*src` is a bit-valid instance of `Dst`, and that the size of `Src` is -/// greater than or equal to the size of `Dst`. -/// -/// # Panics -/// -/// `try_cast_or_pme` may either produce a post-monomorphization error or a -/// panic if `Dst` not the same size as `Src`. Otherwise, `try_cast_or_pme` -/// panics under the same circumstances as [`is_bit_valid`]. -/// -/// [`is_bit_valid`]: TryFromBytes::is_bit_valid -#[doc(hidden)] -#[inline] -fn try_cast_or_pme( - src: Ptr<'_, Src, I>, -) -> Result< - Ptr<'_, Dst, (I::Aliasing, invariant::Any, invariant::Valid)>, - ValidityError, Dst>, -> -where - Src: IntoBytes, - Dst: TryFromBytes + AliasingSafe, - I: Invariants, - I::Aliasing: AtLeast, - R: AliasingSafeReason, -{ - static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); - - // SAFETY: This is a pointer cast, satisfying the following properties: - // - `p as *mut Dst` addresses a subset of the `bytes` addressed by `src`, - // 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) }; - - // SAFETY: `c_ptr` is derived from `src` which is `IntoBytes`. By - // invariant on `IntoByte`s, `c_ptr`'s referent consists entirely of - // initialized bytes. - let c_ptr = unsafe { c_ptr.assume_initialized() }; - - match c_ptr.try_into_valid() { - Ok(ptr) => Ok(ptr), - Err(err) => { - // Re-cast `Ptr` to `Ptr`. - let ptr = err.into_src(); - // SAFETY: This is a pointer cast, satisfying the following - // properties: - // - `p as *mut Src` addresses a subset of the `bytes` addressed by - // `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. - let ptr = unsafe { ptr.assume_alignment::() }; - // SAFETY: `ptr` is `src` and has the same validity invariant. - let ptr = unsafe { ptr.assume_validity::() }; - Err(ValidityError::new(ptr.unify_invariants())) - } - } -} - /// Attempts to transmute `Src` into `Dst`. /// /// A helper for `try_transmute!`. @@ -600,19 +532,30 @@ where Src: IntoBytes, Dst: TryFromBytes, { - let mut src = ManuallyDrop::new(src); - let ptr = Ptr::from_mut(&mut src); - // Wrapping `Dst` in `Unalign` ensures that this cast does not fail due to - // alignment requirements. - match try_cast_or_pme::<_, ManuallyDrop>, _, BecauseExclusive>(ptr) { - Ok(ptr) => { - let dst = ptr.bikeshed_recall_aligned().as_mut(); - // SAFETY: By shadowing `dst`, we ensure that `dst` is not re-used - // after taking its inner value. - let dst = unsafe { ManuallyDrop::take(dst) }; - Ok(dst.into_inner()) - } - Err(_) => Err(ValidityError::new(ManuallyDrop::into_inner(src))), + static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); + + let mu_src = mem::MaybeUninit::new(src); + let mu_src_copy = unsafe { core::ptr::read(&mu_src) }; + // SAFETY: `MaybeUninit` has no validity constraints. + let mut mu_dst: mem::MaybeUninit = + unsafe { crate::util::transmute_unchecked(mu_src_copy) }; + + let ptr = Ptr::from_mut(&mut mu_dst); + + // SAFETY: Since `Src: IntoBytes`, and since `size_of::() == + // size_of::()` by the preceding assertion, all of `mu_dst`'s bytes are + // initialized. + let ptr = unsafe { ptr.assume_validity::() }; + + let ptr = ptr + .transmute::, invariant::Aligned, (crate::BecauseRead, _), _>(); + + if Dst::is_bit_valid(ptr.forget_aligned()) { + Ok(unsafe { mu_dst.assume_init() }) + } else { + // SAFETY: `mu_src` was constructed from `src` and never modified, so it + // is still bit-valid. + Err(ValidityError::new(unsafe { mu_src.assume_init() })) } } @@ -632,17 +575,47 @@ where pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> where Src: IntoBytes + Immutable, - Dst: TryFromBytes + Immutable, + Dst: TryFromBytes + Immutable + CastFrom, { - match try_cast_or_pme::(Ptr::from_ref(src)) { + static_assert!(Src, Dst => mem::size_of::() <= mem::size_of::()); + + #[derive(IntoBytes, Immutable)] + #[repr(transparent)] + struct S(Src); + + #[derive(TryFromBytes, Immutable)] + #[repr(transparent)] + struct D(Dst); + + unsafe impl SizeGtEq> for S {} + + unsafe impl CastFrom> for D { + fn cast_from(ptr: *mut S) -> *mut D { + ptr.cast() + } + } + + let src: *const Src = src; + let src: &S = unsafe { &*src.cast() }; + + match Ptr::from_ref(src).try_transmute::>, _, _>() { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter - // alignment requirement than `Src`. + // alignment requirement than `Src`. Since `S` and `D` are + // `#[repr(transparent)]`, this also implies that `D` does not + // have a stricter alignment requirement than `S`. + // `Ptr::try_transmute` promises to return a pointer which addresses + // the same bytes as its receiver (`Ptr::from_ref(src)`), which was + // guaranteed to be validly-aligned for `S`, and thus its + // return value is validly-aligned for `D`. let ptr = unsafe { ptr.assume_alignment::() }; - Ok(ptr.as_ref()) + Ok(&ptr.as_ref().0) + } + Err(err) => { + let err = err.map_src(Ptr::as_ref).map_src(|src| &src.0); + Err(unsafe { err.with_dst::() }) } - Err(err) => Err(err.map_src(Ptr::as_ref)), } } @@ -661,18 +634,51 @@ where #[inline(always)] pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> where - Src: IntoBytes, - Dst: TryFromBytes, + Src: FromBytes + IntoBytes, + Dst: TryFromBytes + IntoBytes + CastFrom, { - match try_cast_or_pme::(Ptr::from_mut(src)) { + static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); + + #[derive(FromBytes, IntoBytes)] + #[repr(transparent)] + struct S(Src); + + #[derive(TryFromBytes, IntoBytes)] + #[repr(transparent)] + struct D(Dst); + + unsafe impl SizeGtEq> for D {} + unsafe impl SizeGtEq> for S {} + + unsafe impl CastFrom> for D { + fn cast_from(ptr: *mut S) -> *mut D { + ptr.cast() + } + } + + let src: *mut Src = src; + let src: &mut S = unsafe { &mut *src.cast() }; + + match Ptr::from_mut(src) + .try_transmute::>, (crate::BecauseRead, _), (crate::BecauseRead, _)>() + { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter - // alignment requirement than `Src`. + // alignment requirement than `Src`. Since `S` and `D` are + // `#[repr(transparent)]`, this also implies that `D` does not + // have a stricter alignment requirement than `S`. + // `Ptr::try_transmute` promises to return a pointer which addresses + // the same bytes as its receiver (`Ptr::from_ref(src)`), which was + // guaranteed to be validly-aligned for `S`, and thus its + // return value is validly-aligned for `D`. let ptr = unsafe { ptr.assume_alignment::() }; - Ok(ptr.as_mut()) + Ok(&mut ptr.as_mut().0) + } + Err(err) => { + let err = err.map_src(Ptr::as_mut).map_src(|src| &mut src.0); + Err(unsafe { err.with_dst::() }) } - Err(err) => Err(err.map_src(Ptr::as_mut)), } } diff --git a/src/util/macros.rs b/src/util/macros.rs index af751e7523..9717b8f7a0 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 { @@ -66,10 +62,37 @@ macro_rules! unsafe_impl { unsafe_impl!(@method $trait $(; |$candidate: MaybeAligned<$repr>| $is_bit_valid)?); } }; + // Implement all `$traits` for `$ty` with no bounds. - ($ty:ty: $($traits:ident),*) => { - $( unsafe_impl!($ty: $traits); )* + // + // The 2 arms under this one are there so we can apply + // N attributes for each one of M trait implementations. + // The simple solution of: + // + // ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => { + // $( unsafe_impl!( $(#[$attrs])* $ty: $traits ) );* + // } + // + // Won't work. The macro processor sees that the outer repetition + // contains both $attrs and $traits and expects them to match the same + // amount of fragments. + // + // To solve this we must: + // 1. Pack the attributes into a single token tree fragment we can match over. + // 2. Expand the traits. + // 3. Unpack and expand the attributes. + ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => { + unsafe_impl!(@impl_traits_with_packed_attrs { $(#[$attrs])* } $ty: $($traits),*) + }; + + (@impl_traits_with_packed_attrs $attrs:tt $ty:ty: $($traits:ident),*) => { + $( unsafe_impl!(@unpack_attrs $attrs $ty: $traits); )* + }; + + (@unpack_attrs { $(#[$attrs:meta])* } $ty:ty: $traits:ident) => { + unsafe_impl!($(#[$attrs])* $ty: $traits); }; + // This arm is identical to the following one, except it contains a // preceding `const`. If we attempt to handle these with a single arm, there // is an inherent ambiguity between `const` (the keyword) and `const` (the @@ -141,7 +164,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 +174,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::<(BecauseRead, _)>(); $is_bit_valid } }; @@ -165,7 +186,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 +196,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 +205,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)] @@ -250,13 +266,13 @@ macro_rules! impl_for_transparent_wrapper { #[allow(dead_code, clippy::missing_inline_in_public_items)] #[cfg_attr(coverage_nightly, coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() { - use crate::{pointer::invariant::Invariants, util::*}; + use crate::util::*; impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); #[cfg_attr(coverage_nightly, coverage(off))] - fn f() { - is_transparent_wrapper::(); + const fn f<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() { + is_transparent_wrapper::<$ty>(); } } @@ -327,7 +343,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 +357,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()) } }; @@ -516,12 +532,13 @@ macro_rules! impl_known_layout { ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => { $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)* }; - ($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* }; - (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => { + ($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_known_layout!(@inner , => $(#[$attrs])* $ty);)* }; + (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => { const _: () = { use core::ptr::NonNull; #[allow(non_local_definitions)] + $(#[$attrs])* // SAFETY: Delegates safety to `DstLayout::for_type`. unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> KnownLayout for $ty { #[allow(clippy::missing_inline_in_public_items)] @@ -530,6 +547,17 @@ macro_rules! impl_known_layout { type PointerMetadata = (); + // SAFETY: `CoreMaybeUninit::LAYOUT` and `T::LAYOUT` are + // identical because `CoreMaybeUninit` has the same size and + // alignment as `T` [1], and `CoreMaybeUninit` admits + // uninitialized bytes in all positions. + // + // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, + // alignment, and ABI as `T` + type MaybeUninit = core::mem::MaybeUninit; + const LAYOUT: crate::DstLayout = crate::DstLayout::for_type::<$ty>(); // SAFETY: `.cast` preserves address and provenance. @@ -572,6 +600,7 @@ macro_rules! unsafe_impl_known_layout { fn only_derive_is_allowed_to_implement_this_trait() {} type PointerMetadata = <$repr as KnownLayout>::PointerMetadata; + type MaybeUninit = <$repr as KnownLayout>::MaybeUninit; const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT; @@ -615,109 +644,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 +656,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 +670,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 +695,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..6cf924d9db 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -22,7 +22,7 @@ use core::{ use crate::{ error::AlignmentError, - pointer::invariant::{self, Invariants}, + pointer::invariant::{self, Validity}, Unalign, }; @@ -46,12 +46,12 @@ use crate::{ /// [`T::AlignmentVariance`]: TransparentWrapper::AlignmentVariance /// [`T::ValidityVariance`]: TransparentWrapper::ValidityVariance #[doc(hidden)] -pub unsafe trait TransparentWrapper { +pub unsafe trait TransparentWrapper { type Inner: ?Sized; type UnsafeCellVariance; - type AlignmentVariance: AlignmentVariance; - type ValidityVariance: ValidityVariance; + type AlignmentVariance: AlignmentVariance; + type ValidityVariance: ValidityVariance; /// Casts a wrapper pointer to an inner pointer. /// @@ -72,38 +72,38 @@ pub unsafe trait TransparentWrapper { #[allow(unreachable_pub)] #[doc(hidden)] -pub trait AlignmentVariance { - type Applied: invariant::Alignment; +pub trait AlignmentVariance { + type Applied: invariant::Alignment; } #[allow(unreachable_pub)] #[doc(hidden)] -pub trait ValidityVariance { - type Applied: invariant::Validity; +pub trait ValidityVariance { + type Applied: invariant::Validity; } #[doc(hidden)] #[allow(missing_copy_implementations, missing_debug_implementations)] pub enum Covariant {} -impl AlignmentVariance for Covariant { - type Applied = I; +impl AlignmentVariance for Covariant { + type Applied = A; } -impl ValidityVariance for Covariant { - type Applied = I; +impl ValidityVariance for Covariant { + type Applied = V::WithInner; } #[doc(hidden)] #[allow(missing_copy_implementations, missing_debug_implementations)] pub enum Invariant {} -impl AlignmentVariance for Invariant { - type Applied = invariant::Any; +impl AlignmentVariance for Invariant { + type Applied = invariant::Unknown; } -impl ValidityVariance for Invariant { - type Applied = invariant::Any; +impl ValidityVariance for Invariant { + type Applied = invariant::Uninit; } // SAFETY: @@ -114,7 +114,7 @@ impl ValidityVariance for Invariant { // // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as // `T` -unsafe impl TransparentWrapper for MaybeUninit { +unsafe impl TransparentWrapper for MaybeUninit { type Inner = T; // SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges @@ -170,7 +170,7 @@ unsafe impl TransparentWrapper for MaybeUninit { // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` -unsafe impl TransparentWrapper for ManuallyDrop { +unsafe impl TransparentWrapper for ManuallyDrop { type Inner = T; // SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same @@ -224,7 +224,7 @@ unsafe impl TransparentWrapper for ManuallyDrop // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: // // `Wrapping` is guaranteed to have the same layout and ABI as `T`. -unsafe impl TransparentWrapper for Wrapping { +unsafe impl TransparentWrapper for Wrapping { type Inner = T; // SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its @@ -287,7 +287,7 @@ unsafe impl TransparentWrapper for Wrapping { // // `UnsafeCell` has the same in-memory representation as its inner type // `T`. -unsafe impl TransparentWrapper for UnsafeCell { +unsafe impl TransparentWrapper for UnsafeCell { type Inner = T; // SAFETY: Since we set this to `Invariant`, we make no safety claims. @@ -333,7 +333,7 @@ unsafe impl TransparentWrapper for UnsafeCell { // SAFETY: `Unalign` promises to have the same size as `T`. // // See inline comments for other safety justifications. -unsafe impl TransparentWrapper for Unalign { +unsafe impl TransparentWrapper for Unalign { type Inner = T; // SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same @@ -373,22 +373,19 @@ 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])* $(,)?) => {}; ($(#[$attr:meta])* $atomic:ty [$native:ty], $($atomics:ty [$natives:ty]),* $(,)?) => { $(#[$attr])* // SAFETY: See safety comment in next match arm. - unsafe impl crate::util::TransparentWrapper for $atomic { + unsafe impl crate::util::TransparentWrapper for $atomic { unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); } unsafe_impl_transparent_wrapper_for_atomic!($(#[$attr])* $($atomics [$natives],)*); @@ -404,7 +401,7 @@ macro_rules! unsafe_impl_transparent_wrapper_for_atomic { // This type has the same size and bit validity as the underlying // integer type $(#[$attr])* - unsafe impl<$tyvar, I: crate::invariant::Invariants> crate::util::TransparentWrapper for $atomic { + unsafe impl<$tyvar> crate::util::TransparentWrapper for $atomic { unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); } }; @@ -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,134 @@ pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) { }; } +/// Unsafely transmutes the given `src` into a type `Dst`. +/// +/// # Safety +/// +/// The value `src` must be a valid instance of `Dst`. +#[inline(always)] +pub(crate) const unsafe fn transmute_unchecked(src: Src) -> Dst { + static_assert!(Src, Dst => core::mem::size_of::() == core::mem::size_of::()); + + #[repr(C)] + union Transmute { + src: ManuallyDrop, + dst: ManuallyDrop, + } + + // SAFETY: Since `Transmute` is `#[repr(C)]`, its `src` and `dst` + // fields both start at the same offset and the types of those fields are + // transparent wrappers around `Src` and `Dst` [1]. Consequently, + // initializng `Transmute` with with `src` and then reading out `dst` is + // equivalent to transmuting from `Src` to `Dst` [2]. Transmuting from `src` + // to `Dst` is valid because — by contract on the caller — `src` is a valid + // instance of `Dst`. + // + // [1] Per https://doc.rust-lang.org/1.82.0/std/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T`, and is subject to the same layout optimizations as + // `T`. + // + // [2] Per https://doc.rust-lang.org/1.82.0/reference/items/unions.html#reading-and-writing-union-fields: + // + // Effectively, writing to and then reading from a union with the C + // representation is analogous to a transmute from the type used for + // writing to the type used for reading. + unsafe { ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) } +} + +/// Uses `allocate` to create a `Box`. +/// +/// # Errors +/// +/// Returns an error on allocation failure. Allocation failure is guaranteed +/// never to cause a panic or an abort. +/// +/// # Safety +/// +/// `allocate` must be either `alloc::alloc::alloc` or +/// `alloc::alloc::alloc_zeroed`. The referent of the box returned by `new_box` +/// has the same bit-validity as the referent of the pointer returned by the +/// given `allocate` and sufficient size to store `T` with `meta`. +#[must_use = "has no side effects (other than allocation)"] +#[cfg(feature = "alloc")] +#[inline] +pub(crate) unsafe fn new_box( + meta: T::PointerMetadata, + allocate: unsafe fn(core::alloc::Layout) -> *mut u8, +) -> Result, crate::error::AllocError> +where + T: ?Sized + crate::KnownLayout, +{ + use crate::error::AllocError; + use crate::PointerMetadata; + use core::alloc::Layout; + + let size = match meta.size_for_metadata(T::LAYOUT) { + Some(size) => size, + None => return Err(AllocError), + }; + + let align = T::LAYOUT.align.get(); + + // TODO(https://github.com/rust-lang/rust/issues/55724): Use + // `Layout::repeat` once it's stabilized. + let layout = Layout::from_size_align(size, align).or(Err(AllocError))?; + + let ptr = if layout.size() != 0 { + // SAFETY: By contract on the caller, `allocate` is either + // `alloc::alloc::alloc` or `alloc::alloc::alloc_zeroed`. The above + // check ensures their shared safety precondition: that the supplied + // layout is not zero-sized type [1]. + // + // [1] Per https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#tymethod.alloc: + // + // This function is unsafe because undefined behavior can result if + // the caller does not ensure that layout has non-zero size. + let ptr = unsafe { allocate(layout) }; + match NonNull::new(ptr) { + Some(ptr) => ptr, + None => return Err(AllocError), + } + } else { + let align = T::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 enough to realize that + // we're only executing this branch when we're constructing a zero-sized + // `Box`, which doesn't require provenance. + // + // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. All + // bits of a `usize` are initialized. + #[allow(clippy::useless_transmute)] + let dangling = unsafe { mem::transmute::(align) }; + // SAFETY: `dangling` is constructed from `T::LAYOUT.align`, which is a + // `NonZeroUsize`, which is guaranteed to be non-zero. + // + // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` is + // zero, but it does require a non-null dangling pointer for its + // allocation. + // + // TODO(https://github.com/rust-lang/rust/issues/95228): Use + // `std::ptr::without_provenance` once it's stable. That may optimize + // better. As written, Rust may assume that this consumes "exposed" + // provenance, and thus Rust may have to assume that this may consume + // provenance from any pointer whose provenance has been exposed. + unsafe { NonNull::new_unchecked(dangling) } + }; + + let ptr = T::raw_from_ptr_len(ptr, meta); + + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure to + // include a justification that `ptr.as_ptr()` is validly-aligned in the ZST + // case (in which we manually construct a dangling pointer) and to justify + // why `Box` is safe to drop (it's because `allocate` uses the system + // allocator). + #[allow(clippy::undocumented_unsafe_blocks)] + Ok(unsafe { alloc::boxed::Box::from_raw(ptr.as_ptr()) }) +} + /// 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 +853,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 +884,7 @@ pub(crate) mod polyfills { } #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] pub(crate) mod testutil { use crate::*; @@ -849,6 +974,7 @@ pub(crate) mod testutil { } #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] mod tests { use super::*; @@ -869,10 +995,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..fb6b3047a6 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -6,7 +6,7 @@ // This file may not be copied, modified, or distributed except according to // those terms. -use core::hash::Hash; +use core::{fmt, hash::Hash}; use super::*; @@ -166,20 +166,8 @@ impl Unalign { /// Consumes `self`, returning the inner `T`. #[inline(always)] pub const fn into_inner(self) -> T { - // Use this instead of `mem::transmute` since the latter can't tell - // that `Unalign` and `T` have the same size. - #[repr(C)] - union Transmute { - u: ManuallyDrop>, - t: ManuallyDrop, - } - - // SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same - // layout as `T`. `ManuallyDrop` is guaranteed to have the same - // layout as `U`, and so `ManuallyDrop>` has the same layout - // as `ManuallyDrop`. Since `Transmute` is `#[repr(C)]`, its `t` - // and `u` fields both start at the same offset (namely, 0) within the - // union. + // SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same size + // and bit validity as `T`. // // We do this instead of just destructuring in order to prevent // `Unalign`'s `Drop::drop` from being run, since dropping is not @@ -187,7 +175,7 @@ impl Unalign { // // TODO(https://github.com/rust-lang/rust/issues/73255): Destructure // instead of using unsafe. - unsafe { ManuallyDrop::into_inner(Transmute { u: ManuallyDrop::new(self) }.t) } + unsafe { crate::util::transmute_unchecked(self) } } /// Attempts to return a reference to the wrapped `T`, failing if `self` is @@ -239,11 +227,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 +377,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 } @@ -464,6 +447,139 @@ impl Display for Unalign { } } +/// A wrapper type to construct uninitialized instances of `T`. +/// +/// `MaybeUninit` is identical to the [standard library +/// `MaybeUninit`][core-maybe-uninit] type except that it supports unsized +/// types. +/// +/// # Layout +/// +/// The same layout guarantees and caveats apply to `MaybeUninit` as apply to +/// the [standard library `MaybeUninit`][core-maybe-uninit] with one exception: +/// for `T: !Sized`, there is no single value for `T`'s size. Instead, for such +/// types, the following are guaranteed: +/// - Every [valid size][valid-size] for `T` is a valid size for +/// `MaybeUninit` and vice versa +/// - Given `t: *const T` and `m: *const MaybeUninit` with identical fat +/// pointer metadata, `t` and `m` address the same number of bytes (and +/// likewise for `*mut`) +/// +/// [core-maybe-uninit]: core::mem::MaybeUninit +/// [valid-size]: crate::KnownLayout#what-is-a-valid-size +#[repr(transparent)] +#[doc(hidden)] +pub struct MaybeUninit( + // SAFETY: `MaybeUninit` has the same size as `T`, because (by invariant + // on `T::MaybeUninit`) `T::MaybeUninit` has `T::LAYOUT` identical to `T`, + // and because (invariant on `T::LAYOUT`) we can trust that `LAYOUT` + // accurately reflects the layout of `T`. By invariant on `T::MaybeUninit`, + // it admits uninitialized bytes in all positions. Because `MabyeUninit` is + // marked `repr(transparent)`, these properties additionally hold true for + // `Self`. + T::MaybeUninit, +); + +#[doc(hidden)] +impl MaybeUninit { + /// Constructs a `MaybeUninit` initialized with the given value. + #[inline(always)] + pub const fn new(val: T) -> Self + where + T: Sized, + Self: Sized, + { + // SAFETY: It is valid to transmute `val` to `MaybeUninit` because it + // is both valid to transmute `val` to `T::MaybeUninit`, and it is valid + // to transmute from `T::MaybeUninit` to `MaybeUninit`. + // + // First, it is valid to transmute `val` to `T::MaybeUninit` because, by + // invariant on `T::MaybeUninit`: + // - For `T: Sized`, `T` and `T::MaybeUninit` have the same size. + // - All byte sequences of the correct size are valid values of + // `T::MaybeUninit`. + // + // Second, it is additionally valid to transmute from `T::MaybeUninit` + // to `MaybeUninit`, because `MaybeUninit` is a + // `repr(transparent)` wrapper around `T::MaybeUninit`. + // + // These two transmutes are collapsed into one so we don't need to add a + // `T::MaybeUninit: Sized` bound to this function's `where` clause. + unsafe { crate::util::transmute_unchecked(val) } + } + + /// Constructs an uninitialized `MaybeUninit`. + #[must_use] + #[inline(always)] + pub const fn uninit() -> Self + where + T: Sized, + Self: Sized, + { + let uninit = CoreMaybeUninit::::uninit(); + // SAFETY: It is valid to transmute from `CoreMaybeUninit` to + // `MaybeUninit` since they both admit uninitialized bytes in all + // positions, and they have the same size (i.e., that of `T`). + // + // `MaybeUninit` has the same size as `T`, because (by invariant on + // `T::MaybeUninit`) `T::MaybeUninit` has `T::LAYOUT` identical to `T`, + // and because (invariant on `T::LAYOUT`) we can trust that `LAYOUT` + // accurately reflects the layout of `T`. + // + // `CoreMaybeUninit` has the same size as `T` [1] and admits + // uninitialized bytes in all positions. + // + // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, + // and ABI as `T` + unsafe { crate::util::transmute_unchecked(uninit) } + } + + /// Creates a `Box>`. + /// + /// This function is useful for allocating large, uninit values on the heap + /// without ever creating a temporary instance of `Self` on the stack. + /// + /// # Errors + /// + /// Returns an error on allocation failure. Allocation failure is guaranteed + /// never to cause a panic or an abort. + #[cfg(feature = "alloc")] + #[inline] + pub fn new_boxed_uninit(meta: T::PointerMetadata) -> Result, AllocError> { + // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of + // `new_box`. The referent of the pointer returned by `alloc` (and, + // consequently, the `Box` derived from it) is a valid instance of + // `Self`, because `Self` is `MaybeUninit` and thus admits arbitrary + // (un)initialized bytes. + unsafe { crate::util::new_box(meta, alloc::alloc::alloc) } + } + + /// Extracts the value from the `MaybeUninit` container. + /// + /// # Safety + /// + /// The caller must ensure that `self` is in an bit-valid state. Depending + /// on subsequent use, it may also need to be in a library-valid state. + #[inline(always)] + pub const unsafe fn assume_init(self) -> T + where + T: Sized, + Self: Sized, + { + // SAFETY: The caller guarantees that `self` is in an bit-valid state. + unsafe { crate::util::transmute_unchecked(self) } + } +} + +impl fmt::Debug for MaybeUninit { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad(core::any::type_name::()) + } +} + #[cfg(test)] mod tests { use core::panic::AssertUnwindSafe; @@ -525,7 +641,7 @@ mod tests { let au64 = unsafe { x.t.deref_unchecked() }; match au64 { AU64(123) => {} - _ => const_unreachable!(), + _ => unreachable!(), } }; } @@ -558,7 +674,7 @@ mod tests { } #[test] - fn test_copy_clone() { + fn test_unalign_copy_clone() { // Test that `Copy` and `Clone` do not cause soundness issues. This test // is mainly meant to exercise UB that would be caught by Miri. @@ -573,7 +689,7 @@ mod tests { } #[test] - fn test_trait_impls() { + fn test_unalign_trait_impls() { let zero = Unalign::new(0u8); let one = Unalign::new(1u8); @@ -600,4 +716,37 @@ mod tests { assert_eq!(format!("{}", zero), format!("{}", 0u8)); assert_eq!(format!("{}", one), format!("{}", 1u8)); } + + #[test] + #[allow(clippy::as_conversions)] + fn test_maybe_uninit() { + // int + { + let input = 42; + let uninit = MaybeUninit::new(input); + // SAFETY: `uninit` is in an initialized state + let output = unsafe { uninit.assume_init() }; + assert_eq!(input, output); + } + + // thin ref + { + let input = 42; + let uninit = MaybeUninit::new(&input); + // SAFETY: `uninit` is in an initialized state + let output = unsafe { uninit.assume_init() }; + assert_eq!(&input as *const _, output as *const _); + assert_eq!(input, *output); + } + + // wide ref + { + let input = [1, 2, 3, 4]; + let uninit = MaybeUninit::new(&input[..]); + // SAFETY: `uninit` is in an initialized state + let output = unsafe { uninit.assume_init() }; + assert_eq!(&input[..] as *const _, output as *const _); + assert_eq!(input, *output); + } + } } 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..0d6ea1ceaa 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`: + &T + &mut T + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + 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/ptr-is-invariant-over-v.rs b/tests/ui-msrv/ptr-is-invariant-over-v.rs new file mode 120000 index 0000000000..d29c80df7b --- /dev/null +++ b/tests/ui-msrv/ptr-is-invariant-over-v.rs @@ -0,0 +1 @@ +../ui-nightly/ptr-is-invariant-over-v.rs \ No newline at end of file diff --git a/tests/ui-msrv/ptr-is-invariant-over-v.stderr b/tests/ui-msrv/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..792e45aa5e --- /dev/null +++ b/tests/ui-msrv/ptr-is-invariant-over-v.stderr @@ -0,0 +1,31 @@ +error: lifetime may not live long enough + --> tests/ui-msrv/ptr-is-invariant-over-v.rs:10:5 + | +6 | fn _when_exclusive<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +10 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance + +error: lifetime may not live long enough + --> tests/ui-msrv/ptr-is-invariant-over-v.rs:17:5 + | +13 | fn _when_shared<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +17 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance 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..0879aff9e5 100644 --- a/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr +++ b/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr @@ -4,19 +4,62 @@ 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 | - | Dst: TryFromBytes, + | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (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/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 + | +20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ 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 `try_transmute_mut` + --> src/util/macro_util.rs + | + | Dst: TryFromBytes + IntoBytes, + | ^^^^^^^^^ required by this bound in `try_transmute_mut` + = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.rs:20:33 | 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 +72,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-frombytes.rs b/tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs new file mode 120000 index 0000000000..b0e1ecf000 --- /dev/null +++ b/tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs @@ -0,0 +1 @@ +../ui-nightly/try_transmute_mut-src-not-frombytes.rs \ No newline at end of file diff --git a/tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr b/tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..5d47d0122f --- /dev/null +++ b/tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr @@ -0,0 +1,100 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = 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/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let 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 + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let 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/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let 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 `Dst: FromBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = 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/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_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) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = 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/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_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/try_transmute_mut-src-not-intobytes.stderr b/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr index 170c63f9d2..5afba09b9f 100644 --- a/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr +++ b/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr @@ -1,12 +1,100 @@ -error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied - --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:19:52 +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 | -19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by a bound in `try_transmute_mut` - --> src/util/macro_util.rs + = 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/try_transmute_mut-src-not-intobytes.rs:23:40 | - | Src: IntoBytes, - | ^^^^^^^^^ required by this bound in `try_transmute_mut` - = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +23 | let src_not_from_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 + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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 `Dst: FromBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = 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/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_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) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = 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/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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/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-nightly/diagnostic-not-implemented-known-layout.stderr b/tests/ui-nightly/diagnostic-not-implemented-known-layout.stderr index 2509defb7b..812547839d 100644 --- a/tests/ui-nightly/diagnostic-not-implemented-known-layout.stderr +++ b/tests/ui-nightly/diagnostic-not-implemented-known-layout.stderr @@ -6,14 +6,14 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisf | = note: Consider adding `#[derive(KnownLayout)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others note: required by a bound in `takes_known_layout` --> tests/ui-nightly/diagnostic-not-implemented-known-layout.rs:21:26 diff --git a/tests/ui-nightly/invalid-impls/invalid-impls.stderr b/tests/ui-nightly/invalid-impls/invalid-impls.stderr index ed76b4df2b..f3a11a0e2d 100644 --- a/tests/ui-nightly/invalid-impls/invalid-impls.stderr +++ b/tests/ui-nightly/invalid-impls/invalid-impls.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:26:39 | 26 | impl_or_verify!(T => TryFromBytes for Foo); - | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T`, which is required by `Foo: zerocopy::TryFromBytes` + | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T` | = note: Consider adding `#[derive(TryFromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::TryFromBytes` @@ -30,7 +30,7 @@ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:27:36 | 27 | impl_or_verify!(T => FromZeros for Foo); - | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T`, which is required by `Foo: zerocopy::FromZeros` + | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T` | = note: Consider adding `#[derive(FromZeros)]` to `T` note: required for `Foo` to implement `zerocopy::FromZeros` @@ -58,7 +58,7 @@ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:28:36 | 28 | impl_or_verify!(T => FromBytes for Foo); - | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T`, which is required by `Foo: zerocopy::FromBytes` + | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` | = note: Consider adding `#[derive(FromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::FromBytes` @@ -86,7 +86,7 @@ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:29:36 | 29 | impl_or_verify!(T => IntoBytes for Foo); - | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T`, which is required by `Foo: zerocopy::IntoBytes` + | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T` | = note: Consider adding `#[derive(IntoBytes)]` to `T` note: required for `Foo` to implement `zerocopy::IntoBytes` @@ -114,7 +114,7 @@ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:30:36 | 30 | impl_or_verify!(T => Unaligned for Foo); - | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T`, which is required by `Foo: zerocopy::Unaligned` + | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` | = note: Consider adding `#[derive(Unaligned)]` to `T` note: required for `Foo` to implement `zerocopy::Unaligned` diff --git a/tests/ui-nightly/ptr-is-invariant-over-v.rs b/tests/ui-nightly/ptr-is-invariant-over-v.rs new file mode 100644 index 0000000000..cc6b6985c4 --- /dev/null +++ b/tests/ui-nightly/ptr-is-invariant-over-v.rs @@ -0,0 +1,20 @@ +use zerocopy::pointer::{ + invariant::{Aligned, Exclusive, Shared, Valid}, + Ptr, +}; + +fn _when_exclusive<'big: 'small, 'small>( + big: Ptr<'small, Valid<&'big u32>, (Exclusive, Aligned)>, + mut _small: Ptr<'small, Valid<&'small u32>, (Exclusive, Aligned)>, +) { + _small = big; +} + +fn _when_shared<'big: 'small, 'small>( + big: Ptr<'small, Valid<&'big u32>, (Shared, Aligned)>, + mut _small: Ptr<'small, Valid<&'small u32>, (Shared, Aligned)>, +) { + _small = big; +} + +fn main() {} diff --git a/tests/ui-nightly/ptr-is-invariant-over-v.stderr b/tests/ui-nightly/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..180e764976 --- /dev/null +++ b/tests/ui-nightly/ptr-is-invariant-over-v.stderr @@ -0,0 +1,31 @@ +error: lifetime may not live long enough + --> tests/ui-nightly/ptr-is-invariant-over-v.rs:10:5 + | +6 | fn _when_exclusive<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +10 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance + +error: lifetime may not live long enough + --> tests/ui-nightly/ptr-is-invariant-over-v.rs:17:5 + | +13 | fn _when_shared<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +17 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance diff --git a/tests/ui-nightly/transmute-mut-dst-unsized.stderr b/tests/ui-nightly/transmute-mut-dst-unsized.stderr index 74e58f7ad8..615be547eb 100644 --- a/tests/ui-nightly/transmute-mut-dst-unsized.stderr +++ b/tests/ui-nightly/transmute-mut-dst-unsized.stderr @@ -50,8 +50,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = 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 diff --git a/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr b/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr index bdd3f423ef..b66985f93e 100644 --- a/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr +++ b/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-mut-src-dst-not-references.rs:17:44 diff --git a/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr b/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr index 1cff579d97..9a17cf51c8 100644 --- a/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr +++ b/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr @@ -147,8 +147,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = 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 diff --git a/tests/ui-nightly/transmute-mut-src-immutable.stderr b/tests/ui-nightly/transmute-mut-src-immutable.stderr index abaac99588..7f60c95c0e 100644 --- a/tests/ui-nightly/transmute-mut-src-immutable.stderr +++ b/tests/ui-nightly/transmute-mut-src-immutable.stderr @@ -26,6 +26,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-mut-src-immutable.rs:17:22 diff --git a/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr b/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr index 8fc4476d1e..491983e408 100644 --- a/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr +++ b/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-mut-src-not-a-reference.rs:17:38 diff --git a/tests/ui-nightly/transmute-ref-dst-unsized.stderr b/tests/ui-nightly/transmute-ref-dst-unsized.stderr index 3eb5ad5087..34a9fff9ed 100644 --- a/tests/ui-nightly/transmute-ref-dst-unsized.stderr +++ b/tests/ui-nightly/transmute-ref-dst-unsized.stderr @@ -50,8 +50,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = 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 diff --git a/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr b/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr index 18ecbbdd74..adb3a17d39 100644 --- a/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr +++ b/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr @@ -93,6 +93,11 @@ note: in edition 2024, the requirement `!: IntoBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &() = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39 diff --git a/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr b/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr index 251e58c5d1..5cdec56f25 100644 --- a/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr +++ b/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr @@ -147,8 +147,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = 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 diff --git a/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr b/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr index 3a55b4c612..866f695ee4 100644 --- a/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr +++ b/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: IntoBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &() = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:34 diff --git a/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr b/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr index ae0d3114af..29b392ef80 100644 --- a/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr +++ b/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr @@ -44,10 +44,37 @@ note: required by a bound in `try_transmute_mut` | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> | ----------------- required by a bound in this function ... - | Dst: TryFromBytes, + | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 + | +20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | + = note: Consider adding `#[derive(IntoBytes)]` to `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 `try_transmute_mut` + --> src/util/macro_util.rs + | + | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> + | ----------------- required by a bound in this function +... + | Dst: TryFromBytes + IntoBytes, + | ^^^^^^^^^ required by this bound in `try_transmute_mut` + = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | diff --git a/tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs b/tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs new file mode 100644 index 0000000000..12b2e0d328 --- /dev/null +++ b/tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs @@ -0,0 +1,24 @@ +// 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. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +#[derive(zerocopy::IntoBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::TryFromBytes)] +#[repr(C)] +struct Dst; + +fn main() { + // `try_transmute_mut` requires that the source type implements `FromBytes` + let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); +} diff --git a/tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr b/tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..5a55338881 --- /dev/null +++ b/tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr @@ -0,0 +1,104 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `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-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let 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 + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | + = note: Consider adding `#[derive(FromBytes)]` to `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-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let 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 `Dst: FromBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Dst` + = 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-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_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) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(IntoBytes)]` to `Dst` + = 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-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_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-nightly/try_transmute_mut-src-not-intobytes.rs b/tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs index 1987bf15b2..fa3b7032d0 100644 --- a/tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs +++ b/tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs @@ -6,15 +6,19 @@ // This file may not be copied, modified, or distributed except according to // those terms. -include!("../../zerocopy-derive/tests/include.rs"); - extern crate zerocopy; -use util::{NotZerocopy, AU16}; -use zerocopy::try_transmute_mut; +use zerocopy::transmute_mut; + +#[derive(zerocopy::FromBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::TryFromBytes)] +#[repr(C)] +struct Dst; fn main() { // `try_transmute_mut` requires that the source type implements `IntoBytes` - let src = &mut NotZerocopy(AU16(0)); - let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); + let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); } diff --git a/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr b/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr index 44b7e66233..66868266d2 100644 --- a/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr +++ b/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr @@ -1,26 +1,104 @@ -error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied - --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:19:52 +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 | -19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | - = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` - = help: the following other types implement trait `zerocopy::IntoBytes`: + = note: Consider adding `#[derive(IntoBytes)]` to `Src` + = help: the following other types implement trait `IntoBytes`: () - AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize + AtomicU16 and $N others -note: required by a bound in `try_transmute_mut` - --> src/util/macro_util.rs - | - | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> - | ----------------- required by a bound in this function - | where - | Src: IntoBytes, - | ^^^^^^^^^ required by this bound in `try_transmute_mut` - = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AssertSrcIsIntoBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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 + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` + | + = note: Consider adding `#[derive(IntoBytes)]` to `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-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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 `Dst: FromBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Dst` + = 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-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_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) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(IntoBytes)]` to `Dst` + = 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-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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-stable/diagnostic-not-implemented-known-layout.stderr b/tests/ui-stable/diagnostic-not-implemented-known-layout.stderr index bfeec2263d..af5564c89f 100644 --- a/tests/ui-stable/diagnostic-not-implemented-known-layout.stderr +++ b/tests/ui-stable/diagnostic-not-implemented-known-layout.stderr @@ -6,14 +6,14 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisf | = note: Consider adding `#[derive(KnownLayout)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others note: required by a bound in `takes_known_layout` --> tests/ui-stable/diagnostic-not-implemented-known-layout.rs:21:26 diff --git a/tests/ui-stable/invalid-impls/invalid-impls.stderr b/tests/ui-stable/invalid-impls/invalid-impls.stderr index e3d9429d9a..532cb326f3 100644 --- a/tests/ui-stable/invalid-impls/invalid-impls.stderr +++ b/tests/ui-stable/invalid-impls/invalid-impls.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:26:39 | 26 | impl_or_verify!(T => TryFromBytes for Foo); - | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T`, which is required by `Foo: zerocopy::TryFromBytes` + | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T` | = note: Consider adding `#[derive(TryFromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::TryFromBytes` @@ -21,7 +21,7 @@ note: required by a bound in `_::Subtrait` 26 | impl_or_verify!(T => TryFromBytes for Foo); | --------------------------------------------- in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `TryFromBytes` | 26 | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); | ++++++++++++++++++++++++ @@ -30,7 +30,7 @@ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:27:36 | 27 | impl_or_verify!(T => FromZeros for Foo); - | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T`, which is required by `Foo: zerocopy::FromZeros` + | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T` | = note: Consider adding `#[derive(FromZeros)]` to `T` note: required for `Foo` to implement `zerocopy::FromZeros` @@ -49,7 +49,7 @@ note: required by a bound in `_::Subtrait` 27 | impl_or_verify!(T => FromZeros for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `FromZeros` | 27 | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); | +++++++++++++++++++++ @@ -58,7 +58,7 @@ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:28:36 | 28 | impl_or_verify!(T => FromBytes for Foo); - | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T`, which is required by `Foo: zerocopy::FromBytes` + | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` | = note: Consider adding `#[derive(FromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::FromBytes` @@ -77,7 +77,7 @@ note: required by a bound in `_::Subtrait` 28 | impl_or_verify!(T => FromBytes for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `FromBytes` | 28 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); | +++++++++++++++++++++ @@ -86,7 +86,7 @@ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:29:36 | 29 | impl_or_verify!(T => IntoBytes for Foo); - | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T`, which is required by `Foo: zerocopy::IntoBytes` + | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T` | = note: Consider adding `#[derive(IntoBytes)]` to `T` note: required for `Foo` to implement `zerocopy::IntoBytes` @@ -105,7 +105,7 @@ note: required by a bound in `_::Subtrait` 29 | impl_or_verify!(T => IntoBytes for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `IntoBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `IntoBytes` | 29 | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); | +++++++++++++++++++++ @@ -114,7 +114,7 @@ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:30:36 | 30 | impl_or_verify!(T => Unaligned for Foo); - | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T`, which is required by `Foo: zerocopy::Unaligned` + | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` | = note: Consider adding `#[derive(Unaligned)]` to `T` note: required for `Foo` to implement `zerocopy::Unaligned` @@ -133,7 +133,7 @@ note: required by a bound in `_::Subtrait` 30 | impl_or_verify!(T => Unaligned for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `Unaligned` | 30 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); | +++++++++++++++++++++ diff --git a/tests/ui-stable/ptr-is-invariant-over-v.rs b/tests/ui-stable/ptr-is-invariant-over-v.rs new file mode 120000 index 0000000000..d29c80df7b --- /dev/null +++ b/tests/ui-stable/ptr-is-invariant-over-v.rs @@ -0,0 +1 @@ +../ui-nightly/ptr-is-invariant-over-v.rs \ No newline at end of file diff --git a/tests/ui-stable/ptr-is-invariant-over-v.stderr b/tests/ui-stable/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..ff1d040488 --- /dev/null +++ b/tests/ui-stable/ptr-is-invariant-over-v.stderr @@ -0,0 +1,31 @@ +error: lifetime may not live long enough + --> tests/ui-stable/ptr-is-invariant-over-v.rs:10:5 + | +6 | fn _when_exclusive<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +10 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance + +error: lifetime may not live long enough + --> tests/ui-stable/ptr-is-invariant-over-v.rs:17:5 + | +13 | fn _when_shared<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +17 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance diff --git a/tests/ui-stable/transmute-mut-const.stderr b/tests/ui-stable/transmute-mut-const.stderr index 076dcf54ac..2a3388e0d2 100644 --- a/tests/ui-stable/transmute-mut-const.stderr +++ b/tests/ui-stable/transmute-mut-const.stderr @@ -13,15 +13,7 @@ note: `const` item defined here | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default -error[E0658]: mutable references are not allowed in constants - --> tests/ui-stable/transmute-mut-const.rs:20:52 - | -20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - -error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants +error[E0015]: cannot call non-const function `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants --> tests/ui-stable/transmute-mut-const.rs:20:37 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); diff --git a/tests/ui-stable/transmute-mut-dst-unsized.stderr b/tests/ui-stable/transmute-mut-dst-unsized.stderr index 8042fef016..c1114a9b8f 100644 --- a/tests/ui-stable/transmute-mut-dst-unsized.stderr +++ b/tests/ui-stable/transmute-mut-dst-unsized.stderr @@ -47,11 +47,11 @@ 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` - --> $RUST/core/src/intrinsics.rs +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` + --> $RUST/core/src/intrinsics/mod.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = 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 diff --git a/tests/ui-stable/transmute-mut-src-dst-not-references.stderr b/tests/ui-stable/transmute-mut-src-dst-not-references.stderr index e84fd72ceb..35eac70b26 100644 --- a/tests/ui-stable/transmute-mut-src-dst-not-references.stderr +++ b/tests/ui-stable/transmute-mut-src-dst-not-references.stderr @@ -20,8 +20,8 @@ warning: this function depends on never type fallback being `()` 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail --> tests/ui-stable/transmute-mut-src-dst-not-references.rs:17:44 @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-mut-src-dst-not-references.rs:17:44 @@ -37,8 +42,8 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #123748 + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning 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-stable/transmute-mut-src-dst-unsized.stderr b/tests/ui-stable/transmute-mut-src-dst-unsized.stderr index 68ef6efd22..2e18b12fac 100644 --- a/tests/ui-stable/transmute-mut-src-dst-unsized.stderr +++ b/tests/ui-stable/transmute-mut-src-dst-unsized.stderr @@ -144,11 +144,11 @@ 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` - --> $RUST/core/src/intrinsics.rs +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` + --> $RUST/core/src/intrinsics/mod.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = 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 diff --git a/tests/ui-stable/transmute-mut-src-immutable.stderr b/tests/ui-stable/transmute-mut-src-immutable.stderr index 1d1f58951a..e839777aa8 100644 --- a/tests/ui-stable/transmute-mut-src-immutable.stderr +++ b/tests/ui-stable/transmute-mut-src-immutable.stderr @@ -16,8 +16,8 @@ warning: this function depends on never type fallback being `()` 15 | fn ref_src_immutable() { | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail --> tests/ui-stable/transmute-mut-src-immutable.rs:17:22 @@ -26,6 +26,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-mut-src-immutable.rs:17:22 @@ -33,8 +38,8 @@ warning: never type fallback affects this call to an `unsafe` function 17 | let _: &mut u8 = transmute_mut!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #123748 + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning 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-stable/transmute-mut-src-not-a-reference.stderr b/tests/ui-stable/transmute-mut-src-not-a-reference.stderr index c927ada929..ea715472cb 100644 --- a/tests/ui-stable/transmute-mut-src-not-a-reference.stderr +++ b/tests/ui-stable/transmute-mut-src-not-a-reference.stderr @@ -20,8 +20,8 @@ warning: this function depends on never type fallback being `()` 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail --> tests/ui-stable/transmute-mut-src-not-a-reference.rs:17:38 @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-mut-src-not-a-reference.rs:17:38 @@ -37,8 +42,8 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #123748 + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning 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-stable/transmute-ref-dst-unsized.stderr b/tests/ui-stable/transmute-ref-dst-unsized.stderr index 3361707c11..62a31bae90 100644 --- a/tests/ui-stable/transmute-ref-dst-unsized.stderr +++ b/tests/ui-stable/transmute-ref-dst-unsized.stderr @@ -47,11 +47,11 @@ 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` - --> $RUST/core/src/intrinsics.rs +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` + --> $RUST/core/src/intrinsics/mod.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = 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 diff --git a/tests/ui-stable/transmute-ref-src-dst-not-references.stderr b/tests/ui-stable/transmute-ref-src-dst-not-references.stderr index 0a8ecb4648..de4df6bf98 100644 --- a/tests/ui-stable/transmute-ref-src-dst-not-references.stderr +++ b/tests/ui-stable/transmute-ref-src-dst-not-references.stderr @@ -83,8 +83,8 @@ warning: this function depends on never type fallback being `()` 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: IntoBytes` will fail --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 @@ -93,6 +93,11 @@ note: in edition 2024, the requirement `!: IntoBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &() = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 @@ -100,8 +105,8 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #123748 + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning 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) @@ -112,7 +117,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #123748 + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the type explicitly = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/transmute-ref-src-dst-unsized.stderr b/tests/ui-stable/transmute-ref-src-dst-unsized.stderr index 3d6765cc3a..1e84a9ec65 100644 --- a/tests/ui-stable/transmute-ref-src-dst-unsized.stderr +++ b/tests/ui-stable/transmute-ref-src-dst-unsized.stderr @@ -144,11 +144,11 @@ 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` - --> $RUST/core/src/intrinsics.rs +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` + --> $RUST/core/src/intrinsics/mod.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = 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 diff --git a/tests/ui-stable/transmute-ref-src-not-a-reference.stderr b/tests/ui-stable/transmute-ref-src-not-a-reference.stderr index 5914621d1c..a9b2745bca 100644 --- a/tests/ui-stable/transmute-ref-src-not-a-reference.stderr +++ b/tests/ui-stable/transmute-ref-src-not-a-reference.stderr @@ -20,8 +20,8 @@ warning: this function depends on never type fallback being `()` 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: IntoBytes` will fail --> tests/ui-stable/transmute-ref-src-not-a-reference.rs:17:34 @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: IntoBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &() = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-ref-src-not-a-reference.rs:17:34 @@ -37,8 +42,8 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #123748 + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning 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) @@ -49,7 +54,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #123748 + = warning: this changes meaning in Rust 2024 and in a future release in all editions! + = note: for more information, see = help: specify the type explicitly = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr b/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr index 7f608de647..0fc9f2b51e 100644 --- a/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr +++ b/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr @@ -44,10 +44,37 @@ note: required by a bound in `try_transmute_mut` | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> | ----------------- required by a bound in this function ... - | Dst: TryFromBytes, + | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 + | +20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | + = note: Consider adding `#[derive(IntoBytes)]` to `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 `try_transmute_mut` + --> src/util/macro_util.rs + | + | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> + | ----------------- required by a bound in this function +... + | Dst: TryFromBytes + IntoBytes, + | ^^^^^^^^^ required by this bound in `try_transmute_mut` + = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | diff --git a/tests/ui-stable/try_transmute_mut-src-not-frombytes.rs b/tests/ui-stable/try_transmute_mut-src-not-frombytes.rs new file mode 120000 index 0000000000..b0e1ecf000 --- /dev/null +++ b/tests/ui-stable/try_transmute_mut-src-not-frombytes.rs @@ -0,0 +1 @@ +../ui-nightly/try_transmute_mut-src-not-frombytes.rs \ No newline at end of file diff --git a/tests/ui-stable/try_transmute_mut-src-not-frombytes.stderr b/tests/ui-stable/try_transmute_mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..9c60ac19b3 --- /dev/null +++ b/tests/ui-stable/try_transmute_mut-src-not-frombytes.stderr @@ -0,0 +1,104 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `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-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let 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 + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | + = note: Consider adding `#[derive(FromBytes)]` to `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-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let 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 `Dst: FromBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Dst` + = 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-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_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) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(IntoBytes)]` to `Dst` + = 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-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_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-stable/try_transmute_mut-src-not-intobytes.stderr b/tests/ui-stable/try_transmute_mut-src-not-intobytes.stderr index a5185e12ef..371917bbbb 100644 --- a/tests/ui-stable/try_transmute_mut-src-not-intobytes.stderr +++ b/tests/ui-stable/try_transmute_mut-src-not-intobytes.stderr @@ -1,26 +1,104 @@ -error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied - --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:19:52 +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 | -19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | - = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` - = help: the following other types implement trait `zerocopy::IntoBytes`: + = note: Consider adding `#[derive(IntoBytes)]` to `Src` + = help: the following other types implement trait `IntoBytes`: () - AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize + AtomicU16 and $N others -note: required by a bound in `try_transmute_mut` - --> src/util/macro_util.rs - | - | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> - | ----------------- required by a bound in this function - | where - | Src: IntoBytes, - | ^^^^^^^^^ required by this bound in `try_transmute_mut` - = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AssertSrcIsIntoBytes` + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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 + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` + | + = note: Consider adding `#[derive(IntoBytes)]` to `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-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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 `Dst: FromBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Dst` + = 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-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_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) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(IntoBytes)]` to `Dst` + = 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-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_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/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..b9aff0bf0c 100644 --- a/zerocopy-derive/Cargo.toml +++ b/zerocopy-derive/Cargo.toml @@ -9,8 +9,8 @@ [package] edition = "2021" name = "zerocopy-derive" -version = "0.8.5" -authors = ["Joshua Liebow-Feeser "] +version = "0.9.0-alpha.0" +authors = { workspace = true } description = "Custom derive for traits from the zerocopy crate" license = "BSD-2-Clause OR Apache-2.0 OR MIT" repository = "https://github.com/google/zerocopy" @@ -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..75a91895bf 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -35,7 +35,7 @@ pub(crate) fn generate_tag_enum(repr: &EnumRepr, data: &DataEnum) -> TokenStream quote! { #repr - #[allow(dead_code)] + #[allow(dead_code, non_camel_case_types)] enum ___ZerocopyTag { #(#variants,)* } @@ -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!`. @@ -361,7 +349,7 @@ pub(crate) fn derive_is_bit_valid( // subfield pointer just points to a smaller portion of the // overall struct. let variants = unsafe { - raw_enum.project(|p: *mut ___ZerocopyRawEnum #ty_generics| { + raw_enum.cast_unsized_unchecked(|p: *mut ___ZerocopyRawEnum #ty_generics| { core_reexport::ptr::addr_of_mut!((*p).variants) }) }; diff --git a/zerocopy-derive/src/ext.rs b/zerocopy-derive/src/ext.rs index 9b446f53a9..d1be8cf373 100644 --- a/zerocopy-derive/src/ext.rs +++ b/zerocopy-derive/src/ext.rs @@ -8,7 +8,7 @@ use proc_macro2::{Span, TokenStream}; use quote::ToTokens; -use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Ident, Index, Type}; +use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Ident, Index, Type, Visibility}; pub(crate) trait DataExt { /// Extracts the names and types of all fields. For enums, extracts the names @@ -19,15 +19,15 @@ pub(crate) trait DataExt { /// makes sense because we don't care about where they live - we just care /// about transitive ownership. But for field names, we'd only use them when /// generating is_bit_valid, which cares about where they live. - fn fields(&self) -> Vec<(TokenStream, &Type)>; + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>; - fn variants(&self) -> Vec>; + fn variants(&self) -> Vec>; fn tag(&self) -> Option; } impl DataExt for Data { - fn fields(&self) -> Vec<(TokenStream, &Type)> { + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> { match self { Data::Struct(strc) => strc.fields(), Data::Enum(enm) => enm.fields(), @@ -35,7 +35,7 @@ impl DataExt for Data { } } - fn variants(&self) -> Vec> { + fn variants(&self) -> Vec> { match self { Data::Struct(strc) => strc.variants(), Data::Enum(enm) => enm.variants(), @@ -53,11 +53,11 @@ impl DataExt for Data { } impl DataExt for DataStruct { - fn fields(&self) -> Vec<(TokenStream, &Type)> { + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> { map_fields(&self.fields) } - fn variants(&self) -> Vec> { + fn variants(&self) -> Vec> { vec![self.fields()] } @@ -67,11 +67,11 @@ impl DataExt for DataStruct { } impl DataExt for DataEnum { - fn fields(&self) -> Vec<(TokenStream, &Type)> { + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> { map_fields(self.variants.iter().flat_map(|var| &var.fields)) } - fn variants(&self) -> Vec> { + fn variants(&self) -> Vec> { self.variants.iter().map(|var| map_fields(&var.fields)).collect() } @@ -81,11 +81,11 @@ impl DataExt for DataEnum { } impl DataExt for DataUnion { - fn fields(&self) -> Vec<(TokenStream, &Type)> { + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> { map_fields(&self.fields.named) } - fn variants(&self) -> Vec> { + fn variants(&self) -> Vec> { vec![self.fields()] } @@ -96,12 +96,13 @@ impl DataExt for DataUnion { fn map_fields<'a>( fields: impl 'a + IntoIterator, -) -> Vec<(TokenStream, &'a Type)> { +) -> Vec<(&'a Visibility, TokenStream, &'a Type)> { fields .into_iter() .enumerate() .map(|(idx, f)| { ( + &f.vis, f.ident .as_ref() .map(ToTokens::to_token_stream) diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 65414b51fa..4f139f1aa0 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -139,11 +139,13 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result Result::PointerMetadata; - - // SAFETY: `LAYOUT` accurately describes the layout of `Self`. - // The layout of `Self` is reflected using a sequence of - // invocations of `DstLayout::{new_zst,extend,pad_to_align}`. - // The documentation of these items vows that invocations in - // this manner will acurately describe a type, so long as: - // - // - that type is `repr(C)`, - // - its fields are enumerated in the order they appear, - // - the presence of `repr_align` and `repr_packed` are correctly accounted for. - // - // We respect all three of these preconditions here. This - // expansion is only used if `is_repr_c_struct`, we enumerate - // the fields in order, and we extract the values of `align(N)` - // and `packed(N)`. - const LAYOUT: ::zerocopy::DstLayout = { - use ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize; - use ::zerocopy::{DstLayout, KnownLayout}; - - let repr_align = #repr_align; - let repr_packed = #repr_packed; - - DstLayout::new_zst(repr_align) - #(.extend(DstLayout::for_type::<#leading_fields_tys>(), repr_packed))* - .extend(<#trailing_field_ty as KnownLayout>::LAYOUT, repr_packed) - .pad_to_align() - }; - + let make_methods = |trailing_field_ty| { + quote! { // SAFETY: // - The returned pointer has the same address and provenance as // `bytes`: @@ -238,8 +210,162 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result Self::PointerMetadata { <#trailing_field_ty>::pointer_to_metadata(ptr as *mut _) } - ), - ) + } + }; + + let inner_extras = { + let leading_fields_tys = leading_fields_tys.clone(); + let methods = make_methods(*trailing_field_ty); + let (_, ty_generics, _) = ast.generics.split_for_impl(); + + quote!( + type PointerMetadata = <#trailing_field_ty as ::zerocopy::KnownLayout>::PointerMetadata; + + type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit #ty_generics; + + // SAFETY: `LAYOUT` accurately describes the layout of `Self`. + // The layout of `Self` is reflected using a sequence of + // invocations of `DstLayout::{new_zst,extend,pad_to_align}`. + // The documentation of these items vows that invocations in + // this manner will acurately describe a type, so long as: + // + // - that type is `repr(C)`, + // - its fields are enumerated in the order they appear, + // - the presence of `repr_align` and `repr_packed` are correctly accounted for. + // + // We respect all three of these preconditions here. This + // expansion is only used if `is_repr_c_struct`, we enumerate + // the fields in order, and we extract the values of `align(N)` + // and `packed(N)`. + const LAYOUT: ::zerocopy::DstLayout = { + use ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize; + use ::zerocopy::{DstLayout, KnownLayout}; + + let repr_align = #repr_align; + let repr_packed = #repr_packed; + + DstLayout::new_zst(repr_align) + #(.extend(DstLayout::for_type::<#leading_fields_tys>(), repr_packed))* + .extend(<#trailing_field_ty as KnownLayout>::LAYOUT, repr_packed) + .pad_to_align() + }; + + #methods + ) + }; + + let outer_extras = { + let ident = &ast.ident; + let vis = &ast.vis; + let params = &ast.generics.params; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + + let predicates = if let Some(where_clause) = where_clause { + where_clause.predicates.clone() + } else { + Default::default() + }; + + // Generate a valid ident for a type-level handle to a field of a + // given `name`. + let field_index = + |name| Ident::new(&format!("__Zerocopy_Field_{}", name), ident.span()); + + let field_indices: Vec<_> = + fields.iter().map(|(_vis, name, _ty)| field_index(name)).collect(); + + // Define the collection of type-level field handles. + let field_defs = field_indices.iter().zip(&fields).map(|(idx, (vis, _, _))| { + quote! { + #[allow(non_camel_case_types)] + #vis struct #idx; + } + }); + + let field_impls = field_indices.iter().zip(&fields).map(|(idx, (_, _, ty))| quote! { + // SAFETY: `#ty` is the type of `#ident`'s field at `#idx`. + unsafe impl #impl_generics ::zerocopy::util::macro_util::Field<#idx> for #ident #ty_generics + where + #predicates + { + type Type = #ty; + } + }); + + let trailing_field_index = field_index(trailing_field_name); + let leading_field_indices = + leading_fields.iter().map(|(_vis, name, _ty)| field_index(name)); + + let trailing_field_ty = quote! { + <#ident #ty_generics as + ::zerocopy::util::macro_util::Field<#trailing_field_index> + >::Type + }; + + let methods = make_methods(&parse_quote! { + <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit + }); + + quote! { + #(#field_defs)* + + #(#field_impls)* + + // SAFETY: This has the same layout as the derive target type, + // except that it admits uninit bytes. This is ensured by using + // the same repr as the target type, and by using field types + // which have the same layout as the target type's fields, + // except that they admit uninit bytes. We indirect through + // `Field` to ensure that occurrences of `Self` resolve to + // `#ty`, not `__ZerocopyKnownLayoutMaybeUninit` (see #2116). + #repr + #[doc(hidden)] + #vis struct __ZerocopyKnownLayoutMaybeUninit<#params> ( + #(::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit< + <#ident #ty_generics as + ::zerocopy::util::macro_util::Field<#leading_field_indices> + >::Type + >,)* + // NOTE(#2302): We wrap in `ManuallyDrop` here in case the + // type we're operating on is both generic and + // `repr(packed)`. In that case, Rust needs to know that the + // type is *either* `Sized` or has a trivial `Drop`. + // `ManuallyDrop` has a trivial `Drop`, and so satisfies + // this requirement. + ::zerocopy::util::macro_util::core_reexport::mem::ManuallyDrop< + <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit + > + ) + where + #trailing_field_ty: ::zerocopy::KnownLayout, + #predicates; + + // SAFETY: We largely defer to the `KnownLayout` implementation on + // the derive target type (both by using the same tokens, and by + // deferring to impl via type-level indirection). This is sound, + // since `__ZerocopyKnownLayoutMaybeUninit` is guaranteed to + // have the same layout as the derive target type, except that + // `__ZerocopyKnownLayoutMaybeUninit` admits uninit bytes. + unsafe impl #impl_generics ::zerocopy::KnownLayout for __ZerocopyKnownLayoutMaybeUninit #ty_generics + where + #trailing_field_ty: ::zerocopy::KnownLayout, + #predicates + { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + + type PointerMetadata = <#ident #ty_generics as ::zerocopy::KnownLayout>::PointerMetadata; + + type MaybeUninit = Self; + + const LAYOUT: ::zerocopy::DstLayout = <#ident #ty_generics as ::zerocopy::KnownLayout>::LAYOUT; + + #methods + } + } + }; + + (SelfBounds::None, inner_extras, Some(outer_extras)) } else { // For enums, unions, and non-`repr(C)` structs, we require that // `Self` is sized, and as a result don't need to reason about the @@ -248,6 +374,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result; // SAFETY: `LAYOUT` is guaranteed to accurately describe the // layout of `Self`, because that is the documented safety @@ -270,6 +398,7 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result () {} ), + None, ) }; @@ -292,7 +421,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result { @@ -305,7 +435,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result { @@ -318,7 +449,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result TokenStream { SelfBounds::None, None, None, + None, ), Data::Enum(enm) => impl_block( ast, @@ -343,6 +476,7 @@ fn derive_no_cell_inner(ast: &DeriveInput, _top_level: Trait) -> TokenStream { SelfBounds::None, None, None, + None, ), Data::Union(unn) => impl_block( ast, @@ -352,6 +486,7 @@ fn derive_no_cell_inner(ast: &DeriveInput, _top_level: Trait) -> TokenStream { SelfBounds::None, None, None, + None, ), } } @@ -410,8 +545,8 @@ fn derive_try_from_bytes_struct( ) -> Result { let extras = try_gen_trivial_is_bit_valid(ast, top_level).unwrap_or_else(|| { let fields = strct.fields(); - let field_names = fields.iter().map(|(name, _ty)| name); - let field_tys = fields.iter().map(|(_name, ty)| ty); + let field_names = fields.iter().map(|(_vis, name, _ty)| name); + let field_tys = fields.iter().map(|(_vis, _name, ty)| ty); quote!( // SAFETY: We use `is_bit_valid` to validate that each field is // bit-valid, and only return `true` if all of them are. The bit @@ -422,8 +557,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: @@ -437,7 +571,7 @@ fn derive_try_from_bytes_struct( let project = |slf: *mut Self| ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).#field_names); - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <#field_tys as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) @@ -453,6 +587,7 @@ fn derive_try_from_bytes_struct( SelfBounds::None, None, Some(extras), + None, )) } @@ -468,8 +603,8 @@ fn derive_try_from_bytes_union( FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]); let extras = try_gen_trivial_is_bit_valid(ast, top_level).unwrap_or_else(|| { let fields = unn.fields(); - let field_names = fields.iter().map(|(name, _ty)| name); - let field_tys = fields.iter().map(|(_name, ty)| ty); + let field_names = fields.iter().map(|(_vis, name, _ty)| name); + let field_tys = fields.iter().map(|(_vis, _name, ty)| ty); quote!( // SAFETY: We use `is_bit_valid` to validate that any field is // bit-valid; we only return `true` if at least one of them is. The @@ -477,11 +612,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: @@ -495,7 +629,7 @@ fn derive_try_from_bytes_union( let project = |slf: *mut Self| ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).#field_names); - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <#field_tys as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) @@ -511,6 +645,7 @@ fn derive_try_from_bytes_union( SelfBounds::None, None, Some(extras), + None, ) } @@ -547,12 +682,29 @@ fn derive_try_from_bytes_enum( SelfBounds::None, None, Some(extra), + None, )) } /// 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 +726,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 +769,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 } @@ -629,7 +779,16 @@ unsafe fn gen_trivial_is_bit_valid_unchecked() -> proc_macro2::TokenStream { /// A struct is `FromZeros` if: /// - all fields are `FromZeros` fn derive_from_zeros_struct(ast: &DeriveInput, strct: &DataStruct) -> TokenStream { - impl_block(ast, strct, Trait::FromZeros, FieldBounds::ALL_SELF, SelfBounds::None, None, None) + impl_block( + ast, + strct, + Trait::FromZeros, + FieldBounds::ALL_SELF, + SelfBounds::None, + None, + None, + None, + ) } /// Returns `Ok(index)` if variant `index` of the enum has a discriminant of @@ -765,6 +924,7 @@ fn derive_from_zeros_enum(ast: &DeriveInput, enm: &DataEnum) -> Result TokenStream { // compatibility with `derive(TryFromBytes)` on unions; not for soundness. let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]); - impl_block(ast, unn, Trait::FromZeros, field_type_trait_bounds, SelfBounds::None, None, None) + impl_block( + ast, + unn, + Trait::FromZeros, + field_type_trait_bounds, + SelfBounds::None, + None, + None, + None, + ) } /// A struct is `FromBytes` if: /// - all fields are `FromBytes` fn derive_from_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> TokenStream { - impl_block(ast, strct, Trait::FromBytes, FieldBounds::ALL_SELF, SelfBounds::None, None, None) + impl_block( + ast, + strct, + Trait::FromBytes, + FieldBounds::ALL_SELF, + SelfBounds::None, + None, + None, + None, + ) } /// An enum is `FromBytes` if: @@ -813,7 +991,16 @@ fn derive_from_bytes_enum(ast: &DeriveInput, enm: &DataEnum) -> Result TokenStream { // compatibility with `derive(TryFromBytes)` on unions; not for soundness. let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]); - impl_block(ast, unn, Trait::FromBytes, field_type_trait_bounds, SelfBounds::None, None, None) + impl_block( + ast, + unn, + Trait::FromBytes, + field_type_trait_bounds, + SelfBounds::None, + None, + None, + None, + ) } fn derive_into_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> Result { @@ -913,6 +1109,7 @@ fn derive_into_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> Result Result Result Result Result impl '_ + Iterator( input: &DeriveInput, data: &D, @@ -1188,7 +1398,8 @@ fn impl_block( field_type_trait_bounds: FieldBounds, self_type_trait_bounds: SelfBounds, padding_check: Option, - extras: Option, + inner_extras: Option, + outer_extras: Option, ) -> TokenStream { // In this documentation, we will refer to this hypothetical struct: // @@ -1259,12 +1470,13 @@ fn impl_block( parse_quote!(#ty: #(#traits)+*) } let field_type_bounds: Vec<_> = match (field_type_trait_bounds, &fields[..]) { - (FieldBounds::All(traits), _) => { - fields.iter().map(|(_name, ty)| bound_tt(ty, normalize_bounds(trt, traits))).collect() - } + (FieldBounds::All(traits), _) => fields + .iter() + .map(|(_vis, _name, ty)| bound_tt(ty, normalize_bounds(trt, traits))) + .collect(), (FieldBounds::None, _) | (FieldBounds::Trailing(..), []) => vec![], (FieldBounds::Trailing(traits), [.., last]) => { - vec![bound_tt(last.1, normalize_bounds(trt, traits))] + vec![bound_tt(last.2, normalize_bounds(trt, traits))] } (FieldBounds::Explicit(bounds), _) => bounds, }; @@ -1276,7 +1488,7 @@ fn impl_block( let padding_check_bound = padding_check.and_then(|check| (!fields.is_empty()).then_some(check)).map(|check| { let variant_types = variants.iter().map(|var| { - let types = var.iter().map(|(_name, ty)| ty); + let types = var.iter().map(|(_vis, _name, ty)| ty); quote!([#(#types),*]) }); let validator_context = check.validator_macro_context(); @@ -1335,39 +1547,34 @@ fn impl_block( } }); - quote! { + let impl_tokens = quote! { // TODO(#553): Add a test that generates a warning when // `#[allow(deprecated)]` isn't present. #[allow(deprecated)] + // While there are not currently any warnings that this suppresses (that + // we're aware of), it's good future-proofing hygiene. + #[automatically_derived] unsafe impl < #(#params),* > #trait_path for #type_ident < #(#param_idents),* > where #(#bounds,)* { fn only_derive_is_allowed_to_implement_this_trait() {} - #extras + #inner_extras } - } -} + }; -// 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; -} + if let Some(outer_extras) = outer_extras { + // So that any items defined in `#outer_extras` don't conflict with + // existing names defined in this scope. + quote! { + const _: () = { + #impl_tokens -impl BoolExt for bool { - fn then_some(self, t: T) -> Option { - if self { - Some(t) - } else { - None + #outer_extras + }; } + } else { + impl_tokens } } diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 32377e5ea3..4c8be6d2e3 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -102,6 +102,7 @@ fn test_known_layout() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::KnownLayout for Foo where Self: ::zerocopy::util::macro_util::core_reexport::marker::Sized, @@ -110,6 +111,8 @@ fn test_known_layout() { type PointerMetadata = (); + type MaybeUninit = ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit; + const LAYOUT: ::zerocopy::DstLayout = ::zerocopy::DstLayout::for_type::(); #[inline(always)] @@ -125,6 +128,143 @@ fn test_known_layout() { } } no_build } + + test! { + KnownLayout { + #[repr(C, align(2))] + struct Foo(T, U); + } + expands to { + const _: () = { + #[allow(deprecated)] + #[automatically_derived] + unsafe impl ::zerocopy::KnownLayout for Foo + where + U: ::zerocopy::KnownLayout, + { + fn only_derive_is_allowed_to_implement_this_trait() {} + type PointerMetadata = ::PointerMetadata; + type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit; + const LAYOUT: ::zerocopy::DstLayout = { + use ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize; + use ::zerocopy::{DstLayout, KnownLayout}; + let repr_align = ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize::new( + 2u32 as usize, + ); + let repr_packed = ::zerocopy::util::macro_util::core_reexport::option::Option::None; + DstLayout::new_zst(repr_align) + .extend(DstLayout::for_type::(), repr_packed) + .extend(::LAYOUT, repr_packed) + .pad_to_align() + }; + #[inline(always)] + fn raw_from_ptr_len( + bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull, + meta: Self::PointerMetadata, + ) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull { + use ::zerocopy::KnownLayout; + let trailing = ::raw_from_ptr_len(bytes, meta); + let slf = trailing.as_ptr() as *mut Self; + unsafe { + ::zerocopy::util::macro_util::core_reexport::ptr::NonNull::new_unchecked( + slf, + ) + } + } + #[inline(always)] + fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata { + ::pointer_to_metadata(ptr as *mut _) + } + } + #[allow(non_camel_case_types)] + struct __Zerocopy_Field_0; + #[allow(non_camel_case_types)] + struct __Zerocopy_Field_1; + unsafe impl ::zerocopy::util::macro_util::Field<__Zerocopy_Field_0> + for Foo { + type Type = T; + } + unsafe impl ::zerocopy::util::macro_util::Field<__Zerocopy_Field_1> + for Foo { + type Type = U; + } + #[repr(C)] + #[repr(align(2))] + #[doc(hidden)] + struct __ZerocopyKnownLayoutMaybeUninit( + ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit< + as ::zerocopy::util::macro_util::Field<__Zerocopy_Field_0>>::Type, + >, + ::zerocopy::util::macro_util::core_reexport::mem::ManuallyDrop< + < as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type as ::zerocopy::KnownLayout>::MaybeUninit + >, + ) + where + as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type: ::zerocopy::KnownLayout; + unsafe impl ::zerocopy::KnownLayout for __ZerocopyKnownLayoutMaybeUninit + where + as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type: ::zerocopy::KnownLayout, + { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + type PointerMetadata = as ::zerocopy::KnownLayout>::PointerMetadata; + type MaybeUninit = Self; + const LAYOUT: ::zerocopy::DstLayout = as ::zerocopy::KnownLayout>::LAYOUT; + #[inline(always)] + fn raw_from_ptr_len( + bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull, + meta: Self::PointerMetadata, + ) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull { + use ::zerocopy::KnownLayout; + let trailing = << as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type as ::zerocopy::KnownLayout>::MaybeUninit as KnownLayout>::raw_from_ptr_len( + bytes, + meta, + ); + let slf = trailing.as_ptr() as *mut Self; + unsafe { + ::zerocopy::util::macro_util::core_reexport::ptr::NonNull::new_unchecked( + slf, + ) + } + } + #[inline(always)] + fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata { + << as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type as ::zerocopy::KnownLayout>::MaybeUninit>::pointer_to_metadata( + ptr as *mut _, + ) + } + } + }; + } no_build + } } #[test] @@ -134,6 +274,7 @@ fn test_immutable() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::Immutable for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -148,6 +289,7 @@ fn test_try_from_bytes() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -155,8 +297,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 } @@ -172,6 +313,7 @@ fn test_from_zeros() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -179,14 +321,14 @@ 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 } } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromZeros for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -201,6 +343,7 @@ fn test_from_bytes_struct() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -208,8 +351,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() @@ -225,11 +367,13 @@ fn test_from_bytes_struct() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromZeros for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -246,6 +390,7 @@ fn test_from_bytes_union() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo where u8: ::zerocopy::TryFromBytes + ::zerocopy::Immutable, @@ -256,8 +401,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() @@ -273,6 +417,7 @@ fn test_from_bytes_union() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromZeros for Foo where u8: ::zerocopy::FromZeros + ::zerocopy::Immutable, @@ -281,6 +426,7 @@ fn test_from_bytes_union() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromBytes for Foo where u8: ::zerocopy::FromBytes + ::zerocopy::Immutable, @@ -299,6 +445,7 @@ fn test_into_bytes() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::IntoBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -314,6 +461,7 @@ fn test_into_bytes() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::IntoBytes for Foo where u8: ::zerocopy::IntoBytes, @@ -337,6 +485,7 @@ fn test_unaligned() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::Unaligned for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -359,6 +508,7 @@ fn test_try_from_bytes_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ComplexWithGenerics<'a, { N }, X, Y> where @@ -377,12 +527,11 @@ 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)] - #[allow(dead_code)] + #[allow(dead_code, non_camel_case_types)] enum ___ZerocopyTag { UnitLike, StructLike, @@ -416,6 +565,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_StructLike<'a, { N }, X, Y> where @@ -434,15 +584,14 @@ 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 { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -460,7 +609,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -468,7 +617,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -476,7 +625,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -484,7 +633,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).5) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <[(X, Y); N] as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) } && { @@ -492,7 +641,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).6) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -512,6 +661,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_TupleLike<'a, { N }, X, Y> where @@ -528,15 +678,14 @@ 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 { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -554,7 +703,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -562,7 +711,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; as ::zerocopy::TryFromBytes>::is_bit_valid( field_candidate, @@ -572,7 +721,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -596,17 +745,15 @@ 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>| { + raw_enum.cast_unsized_unchecked(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) }) }; @@ -615,21 +762,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) } @@ -653,6 +798,7 @@ fn test_try_from_bytes_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ComplexWithGenerics<'a, { N }, X, Y> where @@ -671,12 +817,11 @@ 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)] - #[allow(dead_code)] + #[allow(dead_code, non_camel_case_types)] enum ___ZerocopyTag { UnitLike, StructLike, @@ -710,6 +855,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_StructLike<'a, { N }, X, Y> where @@ -728,15 +874,14 @@ 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 { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -754,7 +899,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -762,7 +907,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -770,7 +915,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -778,7 +923,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).5) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <[(X, Y); N] as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) } && { @@ -786,7 +931,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).6) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -806,6 +951,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_TupleLike<'a, { N }, X, Y> where @@ -822,15 +968,14 @@ 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 { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -848,7 +993,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -856,7 +1001,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; as ::zerocopy::TryFromBytes>::is_bit_valid( field_candidate, @@ -866,7 +1011,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -890,17 +1035,15 @@ 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>| { + raw_enum.cast_unsized_unchecked(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) }) }; @@ -909,21 +1052,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) } @@ -947,6 +1088,7 @@ fn test_try_from_bytes_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ComplexWithGenerics<'a, { N }, X, Y> where @@ -965,12 +1107,11 @@ 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)] - #[allow(dead_code)] + #[allow(dead_code, non_camel_case_types)] enum ___ZerocopyTag { UnitLike, StructLike, @@ -1004,6 +1145,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_StructLike<'a, { N }, X, Y> where @@ -1022,15 +1164,14 @@ 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 { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1048,7 +1189,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1056,7 +1197,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1064,7 +1205,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1072,7 +1213,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).5) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <[(X, Y); N] as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) } && { @@ -1080,7 +1221,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).6) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -1100,6 +1241,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_TupleLike<'a, { N }, X, Y> where @@ -1116,15 +1258,14 @@ 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 { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1142,7 +1283,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1150,7 +1291,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; as ::zerocopy::TryFromBytes>::is_bit_valid( field_candidate, @@ -1160,7 +1301,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -1184,17 +1325,15 @@ 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>| { + raw_enum.cast_unsized_unchecked(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) }) }; @@ -1203,21 +1342,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) } @@ -1496,6 +1633,7 @@ fn test_from_bytes_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -1503,8 +1641,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() @@ -1520,11 +1657,13 @@ fn test_from_bytes_enum() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromZeros for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -1801,6 +1940,7 @@ fn test_try_from_bytes_trivial_is_bit_valid_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -1808,8 +1948,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/enum_try_from_bytes.rs b/zerocopy-derive/tests/enum_try_from_bytes.rs index 8b866c411b..b3f5884281 100644 --- a/zerocopy-derive/tests/enum_try_from_bytes.rs +++ b/zerocopy-derive/tests/enum_try_from_bytes.rs @@ -626,3 +626,19 @@ fn test_trivial_is_bit_valid() { util_assert_not_impl_any!(FooU8: imp::FromBytes); util::test_trivial_is_bit_valid::(); } + +#[deny(non_camel_case_types)] +mod issue_2051 { + use super::*; + + // Test that the `non_camel_case_types` lint isn't triggered by generated code. + // Prevents regressions of #2051. + #[repr(u32)] + #[derive(imp::TryFromBytes)] + #[allow(non_camel_case_types)] + pub enum Code { + I32_ADD, + I32_SUB, + I32_MUL, + } +} 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/issue_2117.rs b/zerocopy-derive/tests/issue_2117.rs new file mode 100644 index 0000000000..1ee809ae70 --- /dev/null +++ b/zerocopy-derive/tests/issue_2117.rs @@ -0,0 +1,20 @@ +// 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. + +// See comment in `include.rs` for why we disable the prelude. +#![no_implicit_prelude] +#![allow(warnings)] +#![forbid(unexpected_cfgs)] + +include!("include.rs"); + +// Make sure no unexpected `cfg`s are emitted by our derives (see #2117). + +#[derive(imp::KnownLayout)] +#[repr(C)] +pub struct Test(pub [u8; 32]); diff --git a/zerocopy-derive/tests/struct_known_layout.rs b/zerocopy-derive/tests/struct_known_layout.rs index 1cfc584099..a316818fdf 100644 --- a/zerocopy-derive/tests/struct_known_layout.rs +++ b/zerocopy-derive/tests/struct_known_layout.rs @@ -10,6 +10,8 @@ #![no_implicit_prelude] #![allow(warnings)] +extern crate rustversion; + include!("include.rs"); #[derive(imp::KnownLayout)] @@ -46,16 +48,67 @@ util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::KnownLayo util_assert_impl_all!(TypeParams<'static, util::AU16, imp::IntoIter<()>>: imp::KnownLayout); // Deriving `KnownLayout` should work if the struct has bounded parameters. +// +// N.B. We limit this test to rustc >= 1.62, since earlier versions of rustc ICE +// when `KnownLayout` is derived on a `repr(C)` struct whose trailing field +// contains non-static lifetimes. +#[rustversion::since(1.62)] +const _: () = { + #[derive(imp::KnownLayout)] + #[repr(C)] + struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>( + [T; N], + imp::PhantomData<&'a &'b ()>, + ) + where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + imp::KnownLayout; + + util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout); +}; + +const _: () = { + // Similar to the previous test, except that the trailing field contains + // only static lifetimes. This is exercisable on all supported toolchains. + + #[derive(imp::KnownLayout)] + #[repr(C)] + struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>( + &'a &'b [T; N], + imp::PhantomData<&'static ()>, + ) + where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + imp::KnownLayout; + + util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout); +}; + +// Deriving `KnownLayout` should work if the struct references `Self`. See +// #2116. #[derive(imp::KnownLayout)] #[repr(C)] -struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>( - [T; N], - imp::PhantomData<&'a &'b ()>, -) -where - 'a: 'b, - 'b: 'a, - T: 'a + 'b + imp::KnownLayout; - -util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout); +struct WithSelfReference { + leading: [u8; Self::N], + trailing: [[u8; Self::N]], +} + +impl WithSelfReference { + const N: usize = 42; +} + +util_assert_impl_all!(WithSelfReference: imp::KnownLayout); + +// Deriving `KnownLayout` should work with generic `repr(packed)` types. See +// #2302. + +#[derive(imp::KnownLayout)] +#[repr(C, packed)] +struct Packet

{ + payload: P, +} + +util_assert_impl_all!(Packet: imp::KnownLayout); 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..8908ba21f9 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)] @@ -75,13 +79,15 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` 39 + fn test_kl06(kl: &KL06) { | -error[E0277]: the trait bound `T: KnownLayout` is not satisfied +error[E0277]: the trait bound `KL12: 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 `KL12` + | | + | 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)] @@ -92,7 +98,9 @@ note: required by a bound in `assert_kl` 23 | fn assert_kl(_: &T) {} | ^^^^^^^^^^^ required by this bound in `assert_kl` = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider further restricting this bound +help: consider borrowing here | -49 | fn test_kl12(kl: &KL12) { - | +++++++++++++++++++++++ +50 | assert_kl(&kl) + | + +50 | assert_kl(&mut kl) + | ++++ 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..41aefa9711 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`: + &T + &mut T + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + 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`: + &T + &mut T + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + 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/ui-nightly/derive_transparent.stderr b/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr index be89f5180e..d64855dc95 100644 --- a/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr +++ b/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis --> tests/ui-nightly/derive_transparent.rs:34:23 | 34 | util_assert_impl_all!(TransparentStruct: TryFromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::TryFromBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: @@ -31,7 +31,7 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied --> tests/ui-nightly/derive_transparent.rs:35:23 | 35 | util_assert_impl_all!(TransparentStruct: FromZeros); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: FromZeros` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromZeros)]` to `NotZerocopy` = help: the following other types implement trait `FromZeros`: @@ -60,7 +60,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-nightly/derive_transparent.rs:36:23 | 36 | util_assert_impl_all!(TransparentStruct: FromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::FromBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: @@ -89,7 +89,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfie --> tests/ui-nightly/derive_transparent.rs:37:23 | 37 | util_assert_impl_all!(TransparentStruct: IntoBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::IntoBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: @@ -118,7 +118,7 @@ error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied --> tests/ui-nightly/derive_transparent.rs:38:23 | 38 | util_assert_impl_all!(TransparentStruct: Unaligned); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: Unaligned` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Unaligned)]` to `NotZerocopy` = help: the following other types implement trait `Unaligned`: diff --git a/zerocopy-derive/tests/ui-nightly/enum.stderr b/zerocopy-derive/tests/ui-nightly/enum.stderr index e395a0c908..a60591a05a 100644 --- a/zerocopy-derive/tests/ui-nightly/enum.stderr +++ b/zerocopy-derive/tests/ui-nightly/enum.stderr @@ -448,11 +448,11 @@ error[E0277]: `IntoBytes1` has inter-field padding 538 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -466,11 +466,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 549 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -484,11 +484,11 @@ error[E0277]: `IntoBytes3` has inter-field padding 555 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -513,7 +513,7 @@ error[E0277]: the trait bound `bool: FromBytes` is not satisfied --> tests/ui-nightly/enum.rs:191:10 | 191 | #[derive(FromBytes)] - | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`, which is required by `FooU8: FromBytes` + | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool` | = note: Consider adding `#[derive(FromBytes)]` to `bool` = help: the following other types implement trait `FromBytes`: diff --git a/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr b/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr index 99f22d741a..d748d60039 100644 --- a/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr @@ -250,7 +250,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-nightly/late_compile_pass.rs:46:10 | 46 | #[derive(FromBytes)] - | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy`, which is required by `FromBytes1: zerocopy::FromBytes` + | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: diff --git a/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr index df63b508f4..7793e88745 100644 --- a/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr @@ -2,7 +2,9 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied --> tests/ui-nightly/mid_compile_pass.rs:59:26 | 59 | fn test_kl13(t: T) -> impl KnownLayout { - | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL13: KnownLayout` + | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` +60 | KL13(0u8, t) + | ------------ return type was inferred to be `KL13` here | = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL13` to implement `KnownLayout` @@ -80,15 +82,14 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` 39 + fn test_kl06(kl: &KL06) { | -error[E0277]: the trait bound `T: KnownLayout` is not satisfied +error[E0277]: the trait bound `KL12: KnownLayout` is not satisfied --> tests/ui-nightly/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | --------- ^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL12: KnownLayout` + | --------- ^^ the trait `KnownLayout` is not implemented for `KL12` | | | required by a bound introduced by this call | - = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL12` to implement `KnownLayout` --> tests/ui-nightly/mid_compile_pass.rs:45:10 | @@ -100,7 +101,9 @@ note: required by a bound in `assert_kl` 23 | fn assert_kl(_: &T) {} | ^^^^^^^^^^^ required by this bound in `assert_kl` = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider further restricting this bound +help: consider borrowing here | -49 | fn test_kl12(kl: &KL12) { - | +++++++++++++++++++++++ +50 | assert_kl(&kl) + | + +50 | assert_kl(&mut kl) + | ++++ diff --git a/zerocopy-derive/tests/ui-nightly/struct.stderr b/zerocopy-derive/tests/ui-nightly/struct.stderr index bc9e0a8b7b..8952da8ddd 100644 --- a/zerocopy-derive/tests/ui-nightly/struct.stderr +++ b/zerocopy-derive/tests/ui-nightly/struct.stderr @@ -95,7 +95,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 31 | #[derive(KnownLayout)] | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `KL00`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL00: Sized` + = help: within `KL00`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `KL00` --> tests/ui-nightly/struct.rs:32:8 | @@ -114,7 +114,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 36 | #[derive(KnownLayout)] | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `KL02`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL02: Sized` + = help: within `KL02`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `KL02` --> tests/ui-nightly/struct.rs:37:8 | @@ -135,14 +135,14 @@ error[E0277]: the trait bound `NotKnownLayoutDst: zerocopy::KnownLayout` is not | = note: Consider adding `#[derive(KnownLayout)]` to `NotKnownLayoutDst` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *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) @@ -159,14 +159,14 @@ error[E0277]: the trait bound `NotKnownLayout: zerocopy::KnownLayout` is not sat | = note: Consider adding `#[derive(KnownLayout)]` to `NotKnownLayout` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *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) @@ -203,7 +203,7 @@ error[E0277]: the trait bound `UnsafeCell: zerocopy::Immutable` is not satis --> tests/ui-nightly/struct.rs:60:10 | 60 | #[derive(Immutable)] - | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell`, which is required by `[UnsafeCell; 0]: zerocopy::Immutable` + | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell` | = note: Consider adding `#[derive(Immutable)]` to `UnsafeCell` = help: the following other types implement trait `zerocopy::Immutable`: @@ -302,11 +302,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 107 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -320,11 +320,11 @@ error[E0277]: `IntoBytes3` has inter-field padding 114 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -338,7 +338,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 125 | #[derive(IntoBytes)] | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]`, which is required by `IntoBytes4: macro_util::__size_of::Sized` + = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `IntoBytes4` --> tests/ui-nightly/struct.rs:127:8 | @@ -358,7 +358,7 @@ error[E0277]: `[u8]` is unsized 129 | b: [u8], | ^^^^ `IntoBytes` needs all field types to be `Sized` in order to determine whether there is inter-field padding | - = help: the trait `Sized` is not implemented for `[u8]`, which is required by `[u8]: macro_util::__size_of::Sized` + = help: the trait `Sized` is not implemented for `[u8]` = note: consider using `#[repr(packed)]` to remove inter-field padding = note: `IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized` = note: required for `[u8]` to implement `macro_util::__size_of::Sized` @@ -378,7 +378,7 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied --> tests/ui-nightly/struct.rs:161:28 | 161 | is_into_bytes_11::>(); - | ^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`, which is required by `IntoBytes11: zerocopy::IntoBytes` + | ^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | = note: Consider adding `#[derive(Unaligned)]` to `AU16` = help: the following other types implement trait `Unaligned`: diff --git a/zerocopy-derive/tests/ui-nightly/union.stderr b/zerocopy-derive/tests/ui-nightly/union.stderr index 9060b9947b..a88c311b73 100644 --- a/zerocopy-derive/tests/ui-nightly/union.stderr +++ b/zerocopy-derive/tests/ui-nightly/union.stderr @@ -66,7 +66,7 @@ error[E0277]: the trait bound `UnsafeCell<()>: zerocopy::Immutable` is not satis --> tests/ui-nightly/union.rs:24:10 | 24 | #[derive(Immutable)] - | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>`, which is required by `ManuallyDrop>: zerocopy::Immutable` + | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>` | = note: Consider adding `#[derive(Immutable)]` to `UnsafeCell<()>` = help: the following other types implement trait `zerocopy::Immutable`: @@ -93,11 +93,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 39 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable diff --git a/zerocopy-derive/tests/ui-stable/derive_transparent.stderr b/zerocopy-derive/tests/ui-stable/derive_transparent.stderr index b274b65433..989336f4f6 100644 --- a/zerocopy-derive/tests/ui-stable/derive_transparent.stderr +++ b/zerocopy-derive/tests/ui-stable/derive_transparent.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis --> tests/ui-stable/derive_transparent.rs:34:23 | 34 | util_assert_impl_all!(TransparentStruct: TryFromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::TryFromBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: @@ -31,7 +31,7 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied --> tests/ui-stable/derive_transparent.rs:35:23 | 35 | util_assert_impl_all!(TransparentStruct: FromZeros); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: FromZeros` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromZeros)]` to `NotZerocopy` = help: the following other types implement trait `FromZeros`: @@ -60,7 +60,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-stable/derive_transparent.rs:36:23 | 36 | util_assert_impl_all!(TransparentStruct: FromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::FromBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: @@ -89,7 +89,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfie --> tests/ui-stable/derive_transparent.rs:37:23 | 37 | util_assert_impl_all!(TransparentStruct: IntoBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::IntoBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: @@ -118,7 +118,7 @@ error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied --> tests/ui-stable/derive_transparent.rs:38:23 | 38 | util_assert_impl_all!(TransparentStruct: Unaligned); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: Unaligned` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Unaligned)]` to `NotZerocopy` = help: the following other types implement trait `Unaligned`: diff --git a/zerocopy-derive/tests/ui-stable/enum.stderr b/zerocopy-derive/tests/ui-stable/enum.stderr index 95bb47e651..0ed978f913 100644 --- a/zerocopy-derive/tests/ui-stable/enum.stderr +++ b/zerocopy-derive/tests/ui-stable/enum.stderr @@ -423,11 +423,11 @@ error[E0277]: `IntoBytes1` has inter-field padding 538 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -437,11 +437,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 549 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -451,11 +451,11 @@ error[E0277]: `IntoBytes3` has inter-field padding 555 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -476,7 +476,7 @@ error[E0277]: the trait bound `bool: FromBytes` is not satisfied --> tests/ui-stable/enum.rs:191:10 | 191 | #[derive(FromBytes)] - | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`, which is required by `FooU8: FromBytes` + | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool` | = note: Consider adding `#[derive(FromBytes)]` to `bool` = help: the following other types implement trait `FromBytes`: diff --git a/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr b/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr index b6dbb04980..32f1ed8844 100644 --- a/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr @@ -210,7 +210,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-stable/late_compile_pass.rs:46:10 | 46 | #[derive(FromBytes)] - | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy`, which is required by `FromBytes1: zerocopy::FromBytes` + | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: diff --git a/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr index 6b1875b036..3a937f8fdf 100644 --- a/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr @@ -2,7 +2,9 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied --> tests/ui-stable/mid_compile_pass.rs:59:26 | 59 | fn test_kl13(t: T) -> impl KnownLayout { - | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL13: KnownLayout` + | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` +60 | KL13(0u8, t) + | ------------ return type was inferred to be `KL13` here | = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL13` to implement `KnownLayout` @@ -11,7 +13,7 @@ note: required for `KL13` to implement `KnownLayout` 55 | #[derive(KnownLayout)] | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `KnownLayout` | 59 | fn test_kl13(t: T) -> impl KnownLayout { | +++++++++++++++++++++++ @@ -80,15 +82,14 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` 39 + fn test_kl06(kl: &KL06) { | -error[E0277]: the trait bound `T: KnownLayout` is not satisfied +error[E0277]: the trait bound `KL12: KnownLayout` is not satisfied --> tests/ui-stable/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | --------- ^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL12: KnownLayout` + | --------- ^^ the trait `KnownLayout` is not implemented for `KL12` | | | required by a bound introduced by this call | - = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL12` to implement `KnownLayout` --> tests/ui-stable/mid_compile_pass.rs:45:10 | @@ -100,7 +101,9 @@ note: required by a bound in `assert_kl` 23 | fn assert_kl(_: &T) {} | ^^^^^^^^^^^ required by this bound in `assert_kl` = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider further restricting this bound +help: consider borrowing here | -49 | fn test_kl12(kl: &KL12) { - | +++++++++++++++++++++++ +50 | assert_kl(&kl) + | + +50 | assert_kl(&mut kl) + | ++++ diff --git a/zerocopy-derive/tests/ui-stable/struct.stderr b/zerocopy-derive/tests/ui-stable/struct.stderr index 789d291606..30d0902e8d 100644 --- a/zerocopy-derive/tests/ui-stable/struct.stderr +++ b/zerocopy-derive/tests/ui-stable/struct.stderr @@ -92,7 +92,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 31 | #[derive(KnownLayout)] | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `KL00`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL00: Sized` + = help: within `KL00`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `KL00` --> tests/ui-stable/struct.rs:32:8 | @@ -107,7 +107,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 36 | #[derive(KnownLayout)] | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `KL02`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL02: Sized` + = help: within `KL02`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `KL02` --> tests/ui-stable/struct.rs:37:8 | @@ -124,14 +124,14 @@ error[E0277]: the trait bound `NotKnownLayoutDst: zerocopy::KnownLayout` is not | = note: Consider adding `#[derive(KnownLayout)]` to `NotKnownLayoutDst` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *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) @@ -144,14 +144,14 @@ error[E0277]: the trait bound `NotKnownLayout: zerocopy::KnownLayout` is not sat | = note: Consider adding `#[derive(KnownLayout)]` to `NotKnownLayout` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *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) @@ -180,7 +180,7 @@ error[E0277]: the trait bound `UnsafeCell: zerocopy::Immutable` is not satis --> tests/ui-stable/struct.rs:60:10 | 60 | #[derive(Immutable)] - | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell`, which is required by `[UnsafeCell; 0]: zerocopy::Immutable` + | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell` | = note: Consider adding `#[derive(Immutable)]` to `UnsafeCell` = help: the following other types implement trait `zerocopy::Immutable`: @@ -271,11 +271,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 107 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -285,11 +285,11 @@ error[E0277]: `IntoBytes3` has inter-field padding 114 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -299,7 +299,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 125 | #[derive(IntoBytes)] | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]`, which is required by `IntoBytes4: macro_util::__size_of::Sized` + = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `IntoBytes4` --> tests/ui-stable/struct.rs:127:8 | @@ -319,7 +319,7 @@ error[E0277]: `[u8]` is unsized 129 | b: [u8], | ^^^^ `IntoBytes` needs all field types to be `Sized` in order to determine whether there is inter-field padding | - = help: the trait `Sized` is not implemented for `[u8]`, which is required by `[u8]: macro_util::__size_of::Sized` + = help: the trait `Sized` is not implemented for `[u8]` = note: consider using `#[repr(packed)]` to remove inter-field padding = note: `IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized` = note: required for `[u8]` to implement `macro_util::__size_of::Sized` @@ -339,7 +339,7 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied --> tests/ui-stable/struct.rs:161:28 | 161 | is_into_bytes_11::>(); - | ^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`, which is required by `IntoBytes11: zerocopy::IntoBytes` + | ^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | = note: Consider adding `#[derive(Unaligned)]` to `AU16` = help: the following other types implement trait `Unaligned`: diff --git a/zerocopy-derive/tests/ui-stable/union.stderr b/zerocopy-derive/tests/ui-stable/union.stderr index 141929e115..b1486a74af 100644 --- a/zerocopy-derive/tests/ui-stable/union.stderr +++ b/zerocopy-derive/tests/ui-stable/union.stderr @@ -62,11 +62,25 @@ error: must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute | = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) +warning: unexpected `cfg` condition name: `zerocopy_derive_union_into_bytes` + --> tests/ui-stable/union.rs:39:10 + | +39 | #[derive(IntoBytes)] + | ^^^^^^^^^ + | + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` + = note: using a cfg inside a derive macro will use the cfgs from the destination crate and not the ones from the defining crate + = help: try referring to `IntoBytes` crate for guidance on how handle this unexpected cfg + = help: the derive macro `IntoBytes` may come from an old version of the `zerocopy_derive` crate, try updating your dependency with `cargo update -p zerocopy_derive` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + = note: this warning originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `UnsafeCell<()>: zerocopy::Immutable` is not satisfied --> tests/ui-stable/union.rs:24:10 | 24 | #[derive(Immutable)] - | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>`, which is required by `ManuallyDrop>: zerocopy::Immutable` + | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>` | = note: Consider adding `#[derive(Immutable)]` to `UnsafeCell<()>` = help: the following other types implement trait `zerocopy::Immutable`: @@ -89,11 +103,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 39 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = 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-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr b/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr index e4e35d6256..71a6b57e4f 100644 --- a/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr +++ b/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr @@ -6,3 +6,17 @@ error: requires --cfg zerocopy_derive_union_into_bytes; | ^^^^^^^^^ | = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unexpected `cfg` condition name: `zerocopy_derive_union_into_bytes` + --> tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.rs:20:10 + | +20 | #[derive(IntoBytes)] + | ^^^^^^^^^ + | + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` + = note: using a cfg inside a derive macro will use the cfgs from the destination crate and not the ones from the defining crate + = help: try referring to `IntoBytes` crate for guidance on how handle this unexpected cfg + = help: the derive macro `IntoBytes` may come from an old version of the `zerocopy_derive` crate, try updating your dependency with `cargo update -p zerocopy_derive` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + = note: this warning originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) 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() };