diff options
656 files changed, 8200 insertions, 3813 deletions
diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md index 5f17f30b3b0..59862893611 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -28,6 +28,8 @@ Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however *not* meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label. +Discussion comments will get marked as off-topic or deleted. +Repeated discussions on the tracking issue may lead to the tracking issue getting locked. ### Steps <!-- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90269f56c52..3651ef2c614 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,26 +45,25 @@ jobs: - name: Checkout the source code uses: actions/checkout@v4 - name: Calculate the CI job matrix - run: python3 src/ci/scripts/calculate-job-matrix.py >> $GITHUB_OUTPUT + run: python3 src/ci/github-actions/calculate-job-matrix.py >> $GITHUB_OUTPUT id: jobs - pr: - name: "PR - ${{ matrix.name }}" + job: + name: "${{ matrix.name }}" needs: - calculate_matrix env: - PR_CI_JOB: 1 - CI_JOB_NAME: "${{ matrix.name }}" + CI_JOB_NAME: "${{ matrix.image }}" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" SCCACHE_BUCKET: rust-lang-ci-sccache2 TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" CACHE_DOMAIN: ci-caches.rust-lang.org - if: "github.event_name == 'pull_request'" - continue-on-error: "${{ matrix.name == 'mingw-check-tidy' }}" + continue-on-error: "${{ matrix.continue_on_error || false }}" strategy: matrix: include: "${{ fromJSON(needs.calculate_matrix.outputs.jobs) }}" + if: "fromJSON(needs.calculate_matrix.outputs.jobs)[0] != null" defaults: run: shell: "${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}" @@ -89,82 +88,57 @@ jobs: run: "echo \"[CI_PR_NUMBER=$num]\"" env: num: "${{ github.event.number }}" - if: "success() && !env.SKIP_JOB && github.event_name == 'pull_request'" + if: "success() && github.event_name == 'pull_request'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh env: EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" - if: success() && !env.SKIP_JOB - - name: decide whether to skip this job - run: src/ci/scripts/should-skip-this.sh - if: success() && !env.SKIP_JOB - name: ensure the channel matches the target branch run: src/ci/scripts/verify-channel.sh - if: success() && !env.SKIP_JOB - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh - if: success() && !env.SKIP_JOB - name: show the current environment run: src/ci/scripts/dump-environment.sh - if: success() && !env.SKIP_JOB - name: install awscli run: src/ci/scripts/install-awscli.sh - if: success() && !env.SKIP_JOB - name: install sccache run: src/ci/scripts/install-sccache.sh - if: success() && !env.SKIP_JOB - name: select Xcode run: src/ci/scripts/select-xcode.sh - if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh - if: success() && !env.SKIP_JOB - name: install tidy run: src/ci/scripts/install-tidy.sh - if: success() && !env.SKIP_JOB - name: install WIX run: src/ci/scripts/install-wix.sh - if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh - if: success() && !env.SKIP_JOB - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh - if: success() && !env.SKIP_JOB - name: install MSYS2 run: src/ci/scripts/install-msys2.sh - if: success() && !env.SKIP_JOB - name: install MinGW run: src/ci/scripts/install-mingw.sh - if: success() && !env.SKIP_JOB - name: install ninja run: src/ci/scripts/install-ninja.sh - if: success() && !env.SKIP_JOB - name: enable ipv6 on Docker run: src/ci/scripts/enable-docker-ipv6.sh - if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh - if: success() && !env.SKIP_JOB - name: ensure line endings are correct run: src/ci/scripts/verify-line-endings.sh - if: success() && !env.SKIP_JOB - name: ensure backported commits are in upstream branches run: src/ci/scripts/verify-backported-commits.sh - if: success() && !env.SKIP_JOB - name: ensure the stable version number is correct run: src/ci/scripts/verify-stable-version-number.sh - if: success() && !env.SKIP_JOB - name: run the build run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}" - if: success() && !env.SKIP_JOB - name: create github artifacts run: src/ci/scripts/create-doc-artifacts.sh - if: success() && !env.SKIP_JOB - name: upload artifacts to github uses: actions/upload-artifact@v4 with: @@ -172,562 +146,12 @@ jobs: path: obj/artifacts/doc if-no-files-found: ignore retention-days: 5 - if: success() && !env.SKIP_JOB - name: upload artifacts to S3 run: src/ci/scripts/upload-artifacts.sh env: AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" - if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" - auto: - name: "auto - ${{ matrix.name }}" - env: - CI_JOB_NAME: "${{ matrix.name }}" - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse - HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" - DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - SCCACHE_BUCKET: rust-lang-ci-sccache2 - DEPLOY_BUCKET: rust-lang-ci2 - TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" - TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues" - TOOLSTATE_PUBLISH: 1 - CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL - ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 - AWS_REGION: us-west-1 - CACHE_DOMAIN: ci-caches.rust-lang.org - if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" - strategy: - matrix: - include: - - name: aarch64-gnu - os: - - self-hosted - - ARM64 - - linux - - name: arm-android - os: ubuntu-20.04-8core-32gb - env: {} - - name: armhf-gnu - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-aarch64-linux - env: - CODEGEN_BACKENDS: "llvm,cranelift" - os: ubuntu-20.04-8core-32gb - - name: dist-android - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-arm-linux - os: ubuntu-20.04-16core-64gb - env: {} - - name: dist-armhf-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-armv7-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-i586-gnu-i586-i686-musl - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-i686-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-loongarch64-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-ohos - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-powerpc-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-powerpc64-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-powerpc64le-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-riscv64-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-s390x-linux - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-various-1 - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-various-2 - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-x86_64-freebsd - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-x86_64-illumos - os: ubuntu-20.04-8core-32gb - env: {} - - name: dist-x86_64-linux - env: - CODEGEN_BACKENDS: "llvm,cranelift" - os: ubuntu-20.04-16core-64gb - - name: dist-x86_64-linux-alt - env: - IMAGE: dist-x86_64-linux - CODEGEN_BACKENDS: "llvm,cranelift" - os: ubuntu-20.04-16core-64gb - - name: dist-x86_64-musl - env: - CODEGEN_BACKENDS: "llvm,cranelift" - os: ubuntu-20.04-8core-32gb - - name: dist-x86_64-netbsd - os: ubuntu-20.04-8core-32gb - env: {} - - name: i686-gnu - os: ubuntu-20.04-8core-32gb - env: {} - - name: i686-gnu-nopt - os: ubuntu-20.04-8core-32gb - env: {} - - name: mingw-check - os: ubuntu-20.04-4core-16gb - env: {} - - name: test-various - os: ubuntu-20.04-8core-32gb - env: {} - - name: x86_64-gnu - os: ubuntu-20.04-4core-16gb - env: {} - - name: x86_64-gnu-stable - env: - IMAGE: x86_64-gnu - RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable - CI_ONLY_WHEN_CHANNEL: nightly - os: ubuntu-20.04-4core-16gb - - name: x86_64-gnu-aux - os: ubuntu-20.04-4core-16gb - env: {} - - name: x86_64-gnu-integration - env: - CI_ONLY_WHEN_CHANNEL: nightly - os: ubuntu-20.04-8core-32gb - - name: x86_64-gnu-debug - os: ubuntu-20.04-8core-32gb - env: {} - - name: x86_64-gnu-distcheck - os: ubuntu-20.04-8core-32gb - env: {} - - name: x86_64-gnu-llvm-18 - env: - RUST_BACKTRACE: 1 - os: ubuntu-20.04-8core-32gb - - name: x86_64-gnu-llvm-17 - env: - RUST_BACKTRACE: 1 - os: ubuntu-20.04-8core-32gb - - name: x86_64-gnu-nopt - os: ubuntu-20.04-4core-16gb - env: {} - - name: x86_64-gnu-tools - env: - DEPLOY_TOOLSTATES_JSON: toolstates-linux.json - os: ubuntu-20.04-8core-32gb - - name: dist-x86_64-apple - env: - SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin" - RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - CODEGEN_BACKENDS: "llvm,cranelift" - os: macos-13 - - name: dist-apple-various - env: - SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim" - RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - os: macos-13 - - name: x86_64-apple-1 - env: - SCRIPT: "./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - MACOSX_STD_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - os: macos-13 - - name: x86_64-apple-2 - env: - SCRIPT: "./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - MACOSX_STD_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - os: macos-13 - - name: dist-aarch64-apple - env: - SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin" - RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - USE_XCODE_CLANG: 1 - MACOSX_DEPLOYMENT_TARGET: 11.0 - MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - os: macos-14 - - name: aarch64-apple - env: - SCRIPT: "./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin" - RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - USE_XCODE_CLANG: 1 - MACOSX_DEPLOYMENT_TARGET: 11.0 - MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - os: macos-14 - - name: x86_64-msvc - env: - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" - SCRIPT: make ci-msvc - os: windows-2019-8core-32gb - - name: i686-msvc - env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc" - SCRIPT: make ci-msvc - os: windows-2019-8core-32gb - - name: x86_64-msvc-ext - env: - SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo && src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows - HOST_TARGET: x86_64-pc-windows-msvc - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json" - DEPLOY_TOOLSTATES_JSON: toolstates-windows.json - os: windows-2019-8core-32gb - - name: i686-mingw - env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" - SCRIPT: make ci-mingw - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - os: windows-2019-8core-32gb - - name: x86_64-mingw - env: - SCRIPT: make ci-mingw - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - os: windows-2019-8core-32gb - - name: dist-x86_64-msvc - env: - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.codegen-units=1" - SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-2019-8core-32gb - - name: dist-i686-msvc - env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler" - SCRIPT: python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-2019-8core-32gb - - name: dist-aarch64-msvc - env: - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler" - SCRIPT: python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-2019-8core-32gb - - name: dist-i686-mingw - env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler" - NO_DOWNLOAD_CI_LLVM: 1 - SCRIPT: python x.py dist bootstrap --include-default-paths - CUSTOM_MINGW: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-2019-8core-32gb - - name: dist-x86_64-mingw - env: - SCRIPT: python x.py dist bootstrap --include-default-paths - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler" - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - os: windows-2019-8core-32gb - - name: dist-x86_64-msvc-alt - env: - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-extended --enable-profiler" - SCRIPT: python x.py dist bootstrap --include-default-paths - os: windows-2019-8core-32gb - defaults: - run: - shell: "${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}" - timeout-minutes: 600 - runs-on: "${{ matrix.os }}" - steps: - - if: "contains(matrix.os, 'windows')" - uses: msys2/setup-msys2@v2.22.0 - with: - msystem: "${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }}" - update: false - release: true - path-type: inherit - install: "make dos2unix diffutils\n" - - name: disable git crlf conversion - run: git config --global core.autocrlf false - - name: checkout the source code - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - name: configure the PR in which the error message will be posted - run: "echo \"[CI_PR_NUMBER=$num]\"" - env: - num: "${{ github.event.number }}" - if: "success() && !env.SKIP_JOB && github.event_name == 'pull_request'" - - name: add extra environment variables - run: src/ci/scripts/setup-environment.sh - env: - EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" - if: success() && !env.SKIP_JOB - - name: decide whether to skip this job - run: src/ci/scripts/should-skip-this.sh - if: success() && !env.SKIP_JOB - - name: ensure the channel matches the target branch - run: src/ci/scripts/verify-channel.sh - if: success() && !env.SKIP_JOB - - name: collect CPU statistics - run: src/ci/scripts/collect-cpu-stats.sh - if: success() && !env.SKIP_JOB - - name: show the current environment - run: src/ci/scripts/dump-environment.sh - if: success() && !env.SKIP_JOB - - name: install awscli - run: src/ci/scripts/install-awscli.sh - if: success() && !env.SKIP_JOB - - name: install sccache - run: src/ci/scripts/install-sccache.sh - if: success() && !env.SKIP_JOB - - name: select Xcode - run: src/ci/scripts/select-xcode.sh - if: success() && !env.SKIP_JOB - - name: install clang - run: src/ci/scripts/install-clang.sh - if: success() && !env.SKIP_JOB - - name: install tidy - run: src/ci/scripts/install-tidy.sh - if: success() && !env.SKIP_JOB - - name: install WIX - run: src/ci/scripts/install-wix.sh - if: success() && !env.SKIP_JOB - - name: disable git crlf conversion - run: src/ci/scripts/disable-git-crlf-conversion.sh - if: success() && !env.SKIP_JOB - - name: checkout submodules - run: src/ci/scripts/checkout-submodules.sh - if: success() && !env.SKIP_JOB - - name: install MSYS2 - run: src/ci/scripts/install-msys2.sh - if: success() && !env.SKIP_JOB - - name: install MinGW - run: src/ci/scripts/install-mingw.sh - if: success() && !env.SKIP_JOB - - name: install ninja - run: src/ci/scripts/install-ninja.sh - if: success() && !env.SKIP_JOB - - name: enable ipv6 on Docker - run: src/ci/scripts/enable-docker-ipv6.sh - if: success() && !env.SKIP_JOB - - name: disable git crlf conversion - run: src/ci/scripts/disable-git-crlf-conversion.sh - if: success() && !env.SKIP_JOB - - name: ensure line endings are correct - run: src/ci/scripts/verify-line-endings.sh - if: success() && !env.SKIP_JOB - - name: ensure backported commits are in upstream branches - run: src/ci/scripts/verify-backported-commits.sh - if: success() && !env.SKIP_JOB - - name: ensure the stable version number is correct - run: src/ci/scripts/verify-stable-version-number.sh - if: success() && !env.SKIP_JOB - - name: run the build - run: src/ci/scripts/run-build-from-ci.sh 2>&1 - env: - AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" - TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}" - if: success() && !env.SKIP_JOB - - name: create github artifacts - run: src/ci/scripts/create-doc-artifacts.sh - if: success() && !env.SKIP_JOB - - name: upload artifacts to github - uses: actions/upload-artifact@v4 - with: - name: "${{ env.DOC_ARTIFACT_NAME }}" - path: obj/artifacts/doc - if-no-files-found: ignore - retention-days: 5 - if: success() && !env.SKIP_JOB - - name: upload artifacts to S3 - run: src/ci/scripts/upload-artifacts.sh - env: - AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" - if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" - try: - name: "try - ${{ matrix.name }}" - env: - DIST_TRY_BUILD: 1 - CI_JOB_NAME: "${{ matrix.name }}" - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse - HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" - DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - SCCACHE_BUCKET: rust-lang-ci-sccache2 - DEPLOY_BUCKET: rust-lang-ci2 - TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" - TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues" - TOOLSTATE_PUBLISH: 1 - CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL - ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 - AWS_REGION: us-west-1 - CACHE_DOMAIN: ci-caches.rust-lang.org - if: "github.event_name == 'push' && (((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust') || ((github.ref == 'refs/heads/automation/bors/try') && github.repository == 'rust-lang/rust'))" - strategy: - matrix: - include: - - name: dist-x86_64-linux - env: - CODEGEN_BACKENDS: "llvm,cranelift" - os: ubuntu-20.04-16core-64gb - defaults: - run: - shell: "${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}" - timeout-minutes: 600 - runs-on: "${{ matrix.os }}" - steps: - - if: "contains(matrix.os, 'windows')" - uses: msys2/setup-msys2@v2.22.0 - with: - msystem: "${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }}" - update: false - release: true - path-type: inherit - install: "make dos2unix diffutils\n" - - name: disable git crlf conversion - run: git config --global core.autocrlf false - - name: checkout the source code - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - name: configure the PR in which the error message will be posted - run: "echo \"[CI_PR_NUMBER=$num]\"" - env: - num: "${{ github.event.number }}" - if: "success() && !env.SKIP_JOB && github.event_name == 'pull_request'" - - name: add extra environment variables - run: src/ci/scripts/setup-environment.sh - env: - EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" - if: success() && !env.SKIP_JOB - - name: decide whether to skip this job - run: src/ci/scripts/should-skip-this.sh - if: success() && !env.SKIP_JOB - - name: ensure the channel matches the target branch - run: src/ci/scripts/verify-channel.sh - if: success() && !env.SKIP_JOB - - name: collect CPU statistics - run: src/ci/scripts/collect-cpu-stats.sh - if: success() && !env.SKIP_JOB - - name: show the current environment - run: src/ci/scripts/dump-environment.sh - if: success() && !env.SKIP_JOB - - name: install awscli - run: src/ci/scripts/install-awscli.sh - if: success() && !env.SKIP_JOB - - name: install sccache - run: src/ci/scripts/install-sccache.sh - if: success() && !env.SKIP_JOB - - name: select Xcode - run: src/ci/scripts/select-xcode.sh - if: success() && !env.SKIP_JOB - - name: install clang - run: src/ci/scripts/install-clang.sh - if: success() && !env.SKIP_JOB - - name: install tidy - run: src/ci/scripts/install-tidy.sh - if: success() && !env.SKIP_JOB - - name: install WIX - run: src/ci/scripts/install-wix.sh - if: success() && !env.SKIP_JOB - - name: disable git crlf conversion - run: src/ci/scripts/disable-git-crlf-conversion.sh - if: success() && !env.SKIP_JOB - - name: checkout submodules - run: src/ci/scripts/checkout-submodules.sh - if: success() && !env.SKIP_JOB - - name: install MSYS2 - run: src/ci/scripts/install-msys2.sh - if: success() && !env.SKIP_JOB - - name: install MinGW - run: src/ci/scripts/install-mingw.sh - if: success() && !env.SKIP_JOB - - name: install ninja - run: src/ci/scripts/install-ninja.sh - if: success() && !env.SKIP_JOB - - name: enable ipv6 on Docker - run: src/ci/scripts/enable-docker-ipv6.sh - if: success() && !env.SKIP_JOB - - name: disable git crlf conversion - run: src/ci/scripts/disable-git-crlf-conversion.sh - if: success() && !env.SKIP_JOB - - name: ensure line endings are correct - run: src/ci/scripts/verify-line-endings.sh - if: success() && !env.SKIP_JOB - - name: ensure backported commits are in upstream branches - run: src/ci/scripts/verify-backported-commits.sh - if: success() && !env.SKIP_JOB - - name: ensure the stable version number is correct - run: src/ci/scripts/verify-stable-version-number.sh - if: success() && !env.SKIP_JOB - - name: run the build - run: src/ci/scripts/run-build-from-ci.sh 2>&1 - env: - AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" - TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}" - if: success() && !env.SKIP_JOB - - name: create github artifacts - run: src/ci/scripts/create-doc-artifacts.sh - if: success() && !env.SKIP_JOB - - name: upload artifacts to github - uses: actions/upload-artifact@v4 - with: - name: "${{ env.DOC_ARTIFACT_NAME }}" - path: obj/artifacts/doc - if-no-files-found: ignore - retention-days: 5 - if: success() && !env.SKIP_JOB - - name: upload artifacts to S3 - run: src/ci/scripts/upload-artifacts.sh - env: - AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" - if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" + if: "success() && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" master: name: master runs-on: ubuntu-latest @@ -752,10 +176,9 @@ jobs: shell: bash env: TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}" - if: success() && !env.SKIP_JOB try-success: needs: - - try + - job if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'" steps: - name: mark the job as a success @@ -765,7 +188,7 @@ jobs: runs-on: ubuntu-latest try-failure: needs: - - try + - job if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'" steps: - name: mark the job as a failure @@ -775,7 +198,7 @@ jobs: runs-on: ubuntu-latest auto-success: needs: - - auto + - job if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" steps: - name: mark the job as a success @@ -785,7 +208,7 @@ jobs: runs-on: ubuntu-latest auto-failure: needs: - - auto + - job if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" steps: - name: mark the job as a failure diff --git a/Cargo.lock b/Cargo.lock index 552b446a1e7..6b2593ebbb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -491,9 +491,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -2493,8 +2493,10 @@ name = "miri" version = "0.1.0" dependencies = [ "aes", + "chrono", "colored", "ctrlc", + "directories", "getrandom", "jemalloc-sys", "lazy_static", @@ -3343,6 +3345,7 @@ version = "0.0.0" dependencies = [ "object 0.34.0", "regex", + "similar", "wasmparser", ] @@ -5139,6 +5142,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] +name = "similar" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" + +[[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index bddb50568d4..af246e31371 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2786,6 +2786,7 @@ pub enum AttrKind { #[derive(Clone, Encodable, Decodable, Debug)] pub struct NormalAttr { pub item: AttrItem, + // Tokens for the full attribute, e.g. `#[foo]`, `#![bar]`. pub tokens: Option<LazyAttrTokenStream>, } @@ -2802,6 +2803,7 @@ impl NormalAttr { pub struct AttrItem { pub path: Path, pub args: AttrArgs, + // Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`. pub tokens: Option<LazyAttrTokenStream>, } @@ -3112,6 +3114,7 @@ pub struct Delegation { /// Path resolution id. pub id: NodeId, pub qself: Option<P<QSelf>>, + pub rename: Option<Ident>, pub path: Path, pub body: Option<P<Block>>, } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 5e3fc7e3357..0f12fd31975 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -298,7 +298,10 @@ impl MetaItem { } pub fn value_str(&self) -> Option<Symbol> { - self.kind.value_str() + match &self.kind { + MetaItemKind::NameValue(v) => v.kind.str(), + _ => None, + } } fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> @@ -362,13 +365,6 @@ impl MetaItem { } impl MetaItemKind { - pub fn value_str(&self) -> Option<Symbol> { - match self { - MetaItemKind::NameValue(v) => v.kind.str(), - _ => None, - } - } - fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<NestedMetaItem>> { let mut tokens = tokens.trees().peekable(); let mut result = ThinVec::new(); @@ -468,8 +464,9 @@ impl NestedMetaItem { self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) } - /// Returns a name and single literal value tuple of the `MetaItem`. - pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> { + /// If it's a singleton list of the form `foo(lit)`, returns the `foo` and + /// the `lit`. + pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> { self.meta_item().and_then(|meta_item| { meta_item.meta_item_list().and_then(|meta_item_list| { if meta_item_list.len() == 1 diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c4e49d7dbea..1cceca33c17 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -335,7 +335,7 @@ pub fn visit_clobber<T: DummyAstNode>(t: &mut T, f: impl FnOnce(T) -> T) { // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. #[inline] -pub fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F) +fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F) where F: FnMut(&mut T), { @@ -346,7 +346,7 @@ where // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. #[inline] -pub fn visit_thin_vec<T, F>(elems: &mut ThinVec<T>, mut visit_elem: F) +fn visit_thin_vec<T, F>(elems: &mut ThinVec<T>, mut visit_elem: F) where F: FnMut(&mut T), { @@ -357,7 +357,7 @@ where // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. #[inline] -pub fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F) +fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F) where F: FnMut(&mut T), { @@ -367,36 +367,37 @@ where } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) { +fn visit_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) { for attr in attrs.iter_mut() { vis.visit_attribute(attr); } } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_exprs<T: MutVisitor>(exprs: &mut Vec<P<Expr>>, vis: &mut T) { +#[allow(unused)] +fn visit_exprs<T: MutVisitor>(exprs: &mut Vec<P<Expr>>, vis: &mut T) { exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_thin_exprs<T: MutVisitor>(exprs: &mut ThinVec<P<Expr>>, vis: &mut T) { +fn visit_thin_exprs<T: MutVisitor>(exprs: &mut ThinVec<P<Expr>>, vis: &mut T) { exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_bounds<T: MutVisitor>(bounds: &mut GenericBounds, vis: &mut T) { +fn visit_bounds<T: MutVisitor>(bounds: &mut GenericBounds, vis: &mut T) { visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_fn_sig<T: MutVisitor>(FnSig { header, decl, span }: &mut FnSig, vis: &mut T) { +fn visit_fn_sig<T: MutVisitor>(FnSig { header, decl, span }: &mut FnSig, vis: &mut T) { vis.visit_fn_header(header); vis.visit_fn_decl(decl); vis.visit_span(span); } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_attr_args<T: MutVisitor>(args: &mut AttrArgs, vis: &mut T) { +fn visit_attr_args<T: MutVisitor>(args: &mut AttrArgs, vis: &mut T) { match args { AttrArgs::Empty => {} AttrArgs::Delimited(args) => visit_delim_args(args, vis), @@ -411,7 +412,7 @@ pub fn visit_attr_args<T: MutVisitor>(args: &mut AttrArgs, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_delim_args<T: MutVisitor>(args: &mut DelimArgs, vis: &mut T) { +fn visit_delim_args<T: MutVisitor>(args: &mut DelimArgs, vis: &mut T) { let DelimArgs { dspan, delim: _, tokens } = args; visit_delim_span(dspan, vis); visit_tts(tokens, vis); @@ -435,7 +436,7 @@ pub fn noop_flat_map_pat_field<T: MutVisitor>( smallvec![fp] } -pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) { +fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) { let UseTree { prefix, kind, span } = use_tree; vis.visit_path(prefix); match kind { @@ -462,7 +463,7 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[ smallvec![arm] } -pub fn noop_visit_constraint<T: MutVisitor>( +fn noop_visit_constraint<T: MutVisitor>( AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint, vis: &mut T, ) { @@ -541,7 +542,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { visit_lazy_tts(tokens, vis); } -pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) { +fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) { let ForeignMod { unsafety, abi: _, items } = foreign_mod; visit_unsafety(unsafety, vis); items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); @@ -562,11 +563,11 @@ pub fn noop_flat_map_variant<T: MutVisitor>( smallvec![variant] } -pub fn noop_visit_ident<T: MutVisitor>(Ident { name: _, span }: &mut Ident, vis: &mut T) { +fn noop_visit_ident<T: MutVisitor>(Ident { name: _, span }: &mut Ident, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_path<T: MutVisitor>(Path { segments, span, tokens }: &mut Path, vis: &mut T) { +fn noop_visit_path<T: MutVisitor>(Path { segments, span, tokens }: &mut Path, vis: &mut T) { vis.visit_span(span); for PathSegment { ident, id, args } in segments { vis.visit_ident(ident); @@ -576,7 +577,7 @@ pub fn noop_visit_path<T: MutVisitor>(Path { segments, span, tokens }: &mut Path visit_lazy_tts(tokens, vis); } -pub fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<P<QSelf>>, vis: &mut T) { +fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<P<QSelf>>, vis: &mut T) { visit_opt(qself, |qself| { let QSelf { ty, path_span, position: _ } = &mut **qself; vis.visit_ty(ty); @@ -584,14 +585,14 @@ pub fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<P<QSelf>>, vis: &mut T }) } -pub fn noop_visit_generic_args<T: MutVisitor>(generic_args: &mut GenericArgs, vis: &mut T) { +fn noop_visit_generic_args<T: MutVisitor>(generic_args: &mut GenericArgs, vis: &mut T) { match generic_args { GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data), } } -pub fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T) { +fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T) { match arg { GenericArg::Lifetime(lt) => vis.visit_lifetime(lt), GenericArg::Type(ty) => vis.visit_ty(ty), @@ -599,7 +600,7 @@ pub fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T) } } -pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>( +fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>( data: &mut AngleBracketedArgs, vis: &mut T, ) { @@ -611,7 +612,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>( vis.visit_span(span); } -pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>( +fn noop_visit_parenthesized_parameter_data<T: MutVisitor>( args: &mut ParenthesizedArgs, vis: &mut T, ) { @@ -621,7 +622,7 @@ pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>( vis.visit_span(span); } -pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) { +fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) { let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut(); vis.visit_id(id); vis.visit_pat(pat); @@ -642,7 +643,7 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) { visit_lazy_tts(tokens, vis); } -pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { +fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { AttrKind::Normal(normal) => { @@ -658,25 +659,25 @@ pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_mac<T: MutVisitor>(mac: &mut MacCall, vis: &mut T) { +fn noop_visit_mac<T: MutVisitor>(mac: &mut MacCall, vis: &mut T) { let MacCall { path, args } = mac; vis.visit_path(path); visit_delim_args(args, vis); } -pub fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) { +fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) { let MacroDef { body, macro_rules: _ } = macro_def; visit_delim_args(body, vis); } -pub fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) { +fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) { match li { NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi), NestedMetaItem::Lit(_lit) => {} } } -pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) { +fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) { let MetaItem { path: _, kind, span } = mi; match kind { MetaItemKind::Word => {} @@ -697,7 +698,7 @@ pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> Smal } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) { +fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) { match tt { AttrTokenTree::Token(token, _) => { visit_token(token, vis); @@ -724,7 +725,7 @@ pub fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) { +fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) { match tt { TokenTree::Token(token, _) => { visit_token(token, vis); @@ -738,24 +739,21 @@ pub fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) { +fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) { if T::VISIT_TOKENS && !tts.is_empty() { let tts = Lrc::make_mut(tts); visit_vec(tts, |tree| visit_tt(tree, vis)); } } -pub fn visit_attr_tts<T: MutVisitor>(AttrTokenStream(tts): &mut AttrTokenStream, vis: &mut T) { +fn visit_attr_tts<T: MutVisitor>(AttrTokenStream(tts): &mut AttrTokenStream, vis: &mut T) { if T::VISIT_TOKENS && !tts.is_empty() { let tts = Lrc::make_mut(tts); visit_vec(tts, |tree| visit_attr_tt(tree, vis)); } } -pub fn visit_lazy_tts_opt_mut<T: MutVisitor>( - lazy_tts: Option<&mut LazyAttrTokenStream>, - vis: &mut T, -) { +fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyAttrTokenStream>, vis: &mut T) { if T::VISIT_TOKENS { if let Some(lazy_tts) = lazy_tts { let mut tts = lazy_tts.to_attr_token_stream(); @@ -765,7 +763,7 @@ pub fn visit_lazy_tts_opt_mut<T: MutVisitor>( } } -pub fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyAttrTokenStream>, vis: &mut T) { +fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyAttrTokenStream>, vis: &mut T) { visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis); } @@ -818,7 +816,7 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) { // contain multiple items, but decided against it when I looked at // `parse_item_or_view_item` and tried to figure out what I would do with // multiple items there.... -pub fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) { +fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) { match nt { token::NtItem(item) => visit_clobber(item, |item| { // This is probably okay, because the only visitors likely to @@ -851,7 +849,7 @@ pub fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) { +fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) { match defaultness { Defaultness::Default(span) => vis.visit_span(span), Defaultness::Final => {} @@ -859,7 +857,7 @@ pub fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) { +fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) { match unsafety { Unsafe::Yes(span) => vis.visit_span(span), Unsafe::No => {} @@ -867,7 +865,7 @@ pub fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) { +fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) { match polarity { ImplPolarity::Positive => {} ImplPolarity::Negative(span) => vis.visit_span(span), @@ -875,14 +873,14 @@ pub fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) { +fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) { match constness { Const::Yes(span) => vis.visit_span(span), Const::No => {} } } -pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: &mut T) { +fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: &mut T) { match binder { ClosureBinder::NotPresent => {} ClosureBinder::For { span: _, generic_params } => { @@ -891,7 +889,7 @@ pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: } } -pub fn noop_visit_coroutine_kind<T: MutVisitor>(coroutine_kind: &mut CoroutineKind, vis: &mut T) { +fn noop_visit_coroutine_kind<T: MutVisitor>(coroutine_kind: &mut CoroutineKind, vis: &mut T) { match coroutine_kind { CoroutineKind::Async { span, closure_id, return_impl_trait_id } | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } @@ -903,27 +901,27 @@ pub fn noop_visit_coroutine_kind<T: MutVisitor>(coroutine_kind: &mut CoroutineKi } } -pub fn noop_visit_fn_decl<T: MutVisitor>(decl: &mut P<FnDecl>, vis: &mut T) { +fn noop_visit_fn_decl<T: MutVisitor>(decl: &mut P<FnDecl>, vis: &mut T) { let FnDecl { inputs, output } = decl.deref_mut(); inputs.flat_map_in_place(|param| vis.flat_map_param(param)); noop_visit_fn_ret_ty(output, vis); } -pub fn noop_visit_fn_ret_ty<T: MutVisitor>(fn_ret_ty: &mut FnRetTy, vis: &mut T) { +fn noop_visit_fn_ret_ty<T: MutVisitor>(fn_ret_ty: &mut FnRetTy, vis: &mut T) { match fn_ret_ty { FnRetTy::Default(span) => vis.visit_span(span), FnRetTy::Ty(ty) => vis.visit_ty(ty), } } -pub fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) { +fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) { match pb { GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty), GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis), } } -pub fn noop_visit_precise_capturing_arg<T: MutVisitor>(arg: &mut PreciseCapturingArg, vis: &mut T) { +fn noop_visit_precise_capturing_arg<T: MutVisitor>(arg: &mut PreciseCapturingArg, vis: &mut T) { match arg { PreciseCapturingArg::Lifetime(lt) => { vis.visit_lifetime(lt); @@ -960,7 +958,7 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>( smallvec![param] } -pub fn noop_visit_label<T: MutVisitor>(Label { ident }: &mut Label, vis: &mut T) { +fn noop_visit_label<T: MutVisitor>(Label { ident }: &mut Label, vis: &mut T) { vis.visit_ident(ident); } @@ -969,20 +967,20 @@ fn noop_visit_lifetime<T: MutVisitor>(Lifetime { id, ident }: &mut Lifetime, vis vis.visit_ident(ident); } -pub fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) { +fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) { let Generics { params, where_clause, span } = generics; params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_where_clause(where_clause); vis.visit_span(span); } -pub fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) { +fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) { let WhereClause { has_where_token: _, predicates, span } = wc; visit_thin_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); vis.visit_span(span); } -pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mut T) { +fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mut T) { match pred { WherePredicate::BoundPredicate(bp) => { let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; @@ -1006,7 +1004,7 @@ pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: } } -pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) { +fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) { match vdata { VariantData::Struct { fields, .. } => { fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); @@ -1019,12 +1017,12 @@ pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut } } -pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) { +fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) { vis.visit_path(path); vis.visit_id(ref_id); } -pub fn noop_visit_poly_trait_ref<T: MutVisitor>(p: &mut PolyTraitRef, vis: &mut T) { +fn noop_visit_poly_trait_ref<T: MutVisitor>(p: &mut PolyTraitRef, vis: &mut T) { let PolyTraitRef { bound_generic_params, trait_ref, span } = p; bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_trait_ref(trait_ref); @@ -1058,7 +1056,7 @@ pub fn noop_flat_map_expr_field<T: MutVisitor>( smallvec![f] } -pub fn noop_visit_mt<T: MutVisitor>(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) { +fn noop_visit_mt<T: MutVisitor>(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) { vis.visit_ty(ty); } @@ -1149,10 +1147,13 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) { } ItemKind::MacCall(m) => vis.visit_mac_call(m), ItemKind::MacroDef(def) => vis.visit_macro_def(def), - ItemKind::Delegation(box Delegation { id, qself, path, body }) => { + ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { vis.visit_id(id); vis.visit_qself(qself); vis.visit_path(path); + if let Some(rename) = rename { + vis.visit_ident(rename); + } if let Some(body) = body { vis.visit_block(body); } @@ -1195,10 +1196,13 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>( visit_opt(ty, |ty| visitor.visit_ty(ty)); } AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac), - AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => { + AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { visitor.visit_id(id); visitor.visit_qself(qself); visitor.visit_path(path); + if let Some(rename) = rename { + visitor.visit_ident(rename); + } if let Some(body) = body { visitor.visit_block(body); } @@ -1219,7 +1223,7 @@ fn visit_const_item<T: MutVisitor>( visit_opt(expr, |expr| visitor.visit_expr(expr)); } -pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) { +fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) { let FnHeader { unsafety, coroutine_kind, constness, ext: _ } = header; visit_constness(constness, vis); coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); @@ -1337,12 +1341,12 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { visit_lazy_tts(tokens, vis); } -pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonConst, vis: &mut T) { +fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonConst, vis: &mut T) { vis.visit_id(id); vis.visit_expr(value); } -pub fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) { +fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) { for (op, _) in &mut asm.operands { match op { InlineAsmOperand::In { expr, .. } @@ -1362,7 +1366,7 @@ pub fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) { } } -pub fn noop_visit_inline_asm_sym<T: MutVisitor>( +fn noop_visit_inline_asm_sym<T: MutVisitor>( InlineAsmSym { id, qself, path }: &mut InlineAsmSym, vis: &mut T, ) { @@ -1371,7 +1375,7 @@ pub fn noop_visit_inline_asm_sym<T: MutVisitor>( vis.visit_path(path); } -pub fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) { +fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) { for arg in fmt.arguments.all_args_mut() { if let FormatArgumentKind::Named(name) = &mut arg.kind { vis.visit_ident(name); @@ -1588,10 +1592,7 @@ pub fn noop_flat_map_stmt<T: MutVisitor>( stmts } -pub fn noop_flat_map_stmt_kind<T: MutVisitor>( - kind: StmtKind, - vis: &mut T, -) -> SmallVec<[StmtKind; 1]> { +fn noop_flat_map_stmt_kind<T: MutVisitor>(kind: StmtKind, vis: &mut T) -> SmallVec<[StmtKind; 1]> { match kind { StmtKind::Let(mut local) => smallvec![StmtKind::Let({ vis.visit_local(&mut local); @@ -1611,7 +1612,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>( } } -pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) { +fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) { match &mut visibility.kind { VisibilityKind::Public | VisibilityKind::Inherited => {} VisibilityKind::Restricted { path, id, shorthand: _ } => { @@ -1622,7 +1623,7 @@ pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) { vis.visit_span(&mut visibility.span); } -pub fn noop_visit_capture_by<T: MutVisitor>(capture_by: &mut CaptureBy, vis: &mut T) { +fn noop_visit_capture_by<T: MutVisitor>(capture_by: &mut CaptureBy, vis: &mut T) { match capture_by { CaptureBy::Ref => {} CaptureBy::Value { move_kw } => { diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 880f92bbe7b..08d65a5ffa5 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -140,9 +140,8 @@ impl fmt::Debug for LazyAttrTokenStream { } impl<S: SpanEncoder> Encodable<S> for LazyAttrTokenStream { - fn encode(&self, s: &mut S) { - // Used by AST json printing. - Encodable::encode(&self.to_attr_token_stream(), s); + fn encode(&self, _s: &mut S) { + panic!("Attempted to encode LazyAttrTokenStream"); } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 968d10ad487..d9740928f8d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -382,11 +382,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) -> V::Resu } ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)), - ItemKind::Delegation(box Delegation { id, qself, path, body }) => { + ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { if let Some(qself) = qself { try_visit!(visitor.visit_ty(&qself.ty)); } try_visit!(visitor.visit_path(path, *id)); + visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_block, body); } } @@ -782,11 +783,12 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>( AssocItemKind::MacCall(mac) => { try_visit!(visitor.visit_mac_call(mac)); } - AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => { + AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { if let Some(qself) = qself { try_visit!(visitor.visit_ty(&qself.ty)); } try_visit!(visitor.visit_path(path, *id)); + visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_block, body); } } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index a23e714ef01..73001c9990c 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -163,3 +163,6 @@ ast_lowering_underscore_expr_lhs_assign = .label = `_` not allowed here ast_lowering_use_angle_brackets = use angle brackets instead +ast_lowering_yield_in_closure = + `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + .suggestion = use `#[coroutine]` to make this closure a coroutine diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index f4d5e71bade..a1e5c275c18 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -49,7 +49,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; -use rustc_middle::ty::ResolverAstLowering; +use rustc_middle::ty::{Asyncness, ResolverAstLowering}; use rustc_span::{symbol::Ident, Span}; use rustc_target::spec::abi; use std::iter; @@ -67,7 +67,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return false; }; if let Some(local_sig_id) = sig_id.as_local() { - self.resolver.has_self.contains(&local_sig_id) + self.resolver.delegation_fn_sigs[&local_sig_id].has_self } else { match self.tcx.def_kind(sig_id) { DefKind::Fn => false, @@ -82,13 +82,14 @@ impl<'hir> LoweringContext<'_, 'hir> { delegation: &Delegation, item_id: NodeId, ) -> DelegationResults<'hir> { - let span = delegation.path.segments.last().unwrap().ident.span; + let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span); match sig_id { Ok(sig_id) => { - let decl = self.lower_delegation_decl(sig_id, span); - let sig = self.lower_delegation_sig(span, decl); - let body_id = self.lower_delegation_body(sig.decl, delegation); + let (param_count, c_variadic) = self.param_count(sig_id); + let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span); + let sig = self.lower_delegation_sig(sig_id, decl, span); + let body_id = self.lower_delegation_body(delegation, param_count, span); let generics = self.lower_delegation_generics(span); DelegationResults { body_id, sig, generics } @@ -123,34 +124,47 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } + // Function parameter count, including C variadic `...` if present. + fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) { + if let Some(local_sig_id) = sig_id.as_local() { + // Map may be filled incorrectly due to recursive delegation. + // Error will be emmited later during HIR ty lowering. + match self.resolver.delegation_fn_sigs.get(&local_sig_id) { + Some(sig) => (sig.param_count, sig.c_variadic), + None => (0, false), + } + } else { + let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder(); + (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic) + } + } + fn lower_delegation_decl( &mut self, sig_id: DefId, - param_span: Span, + param_count: usize, + c_variadic: bool, + span: Span, ) -> &'hir hir::FnDecl<'hir> { - let args_count = if let Some(local_sig_id) = sig_id.as_local() { - // Map may be filled incorrectly due to recursive delegation. - // Error will be emitted later during HIR ty lowering. - self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default() - } else { - self.tcx.fn_arg_names(sig_id).len() - }; - let inputs = self.arena.alloc_from_iter((0..args_count).map(|arg| hir::Ty { + // The last parameter in C variadic functions is skipped in the signature, + // like during regular lowering. + let decl_param_count = param_count - c_variadic as usize; + let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)), - span: self.lower_span(param_span), + span, })); let output = self.arena.alloc(hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output), - span: self.lower_span(param_span), + span, }); self.arena.alloc(hir::FnDecl { inputs, output: hir::FnRetTy::Return(output), - c_variadic: false, + c_variadic, lifetime_elision_allowed: true, implicit_self: hir::ImplicitSelfKind::None, }) @@ -158,35 +172,45 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_delegation_sig( &mut self, - span: Span, + sig_id: DefId, decl: &'hir hir::FnDecl<'hir>, + span: Span, ) -> hir::FnSig<'hir> { - hir::FnSig { - decl, - header: hir::FnHeader { - unsafety: hir::Unsafety::Normal, - constness: hir::Constness::NotConst, - asyncness: hir::IsAsync::NotAsync, - abi: abi::Abi::Rust, - }, - span: self.lower_span(span), - } + let header = if let Some(local_sig_id) = sig_id.as_local() { + match self.resolver.delegation_fn_sigs.get(&local_sig_id) { + Some(sig) => self.lower_fn_header(sig.header), + None => self.generate_header_error(), + } + } else { + let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder(); + let asyncness = match self.tcx.asyncness(sig_id) { + Asyncness::Yes => hir::IsAsync::Async(span), + Asyncness::No => hir::IsAsync::NotAsync, + }; + hir::FnHeader { + unsafety: sig.unsafety, + constness: self.tcx.constness(sig_id), + asyncness, + abi: sig.abi, + } + }; + hir::FnSig { decl, header, span } } - fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) { + fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) { let pat_node_id = self.next_node_id(); let pat_id = self.lower_node_id(pat_node_id); let pat = self.arena.alloc(hir::Pat { hir_id: pat_id, kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, Ident::empty(), None), - span: ty.span, + span, default_binding_modes: false, }); - (hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id) + (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id) } - fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> { + fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> { let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment { ident: Ident::empty(), hir_id: self.next_id(), @@ -195,20 +219,20 @@ impl<'hir> LoweringContext<'_, 'hir> { infer_args: false, })); - let path = - self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments }); + let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments }); hir::Expr { hir_id: self.next_id(), kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), - span: ty.span, + span, } } fn lower_delegation_body( &mut self, - decl: &'hir hir::FnDecl<'hir>, delegation: &Delegation, + param_count: usize, + span: Span, ) -> BodyId { let path = self.lower_qpath( delegation.id, @@ -224,8 +248,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut parameters: Vec<hir::Param<'_>> = Vec::new(); let mut args: Vec<hir::Expr<'hir>> = Vec::new(); - for (idx, param_ty) in decl.inputs.iter().enumerate() { - let (param, pat_node_id) = this.generate_param(param_ty); + for idx in 0..param_count { + let (param, pat_node_id) = this.generate_param(span); parameters.push(param); let arg = if let Some(block) = block @@ -245,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } else { let pat_hir_id = this.lower_node_id(pat_node_id); - this.generate_arg(param_ty, pat_hir_id) + this.generate_arg(pat_hir_id, span) }; args.push(arg); } @@ -304,7 +328,9 @@ impl<'hir> LoweringContext<'_, 'hir> { implicit_self: hir::ImplicitSelfKind::None, }); - let sig = self.lower_delegation_sig(span, decl); + let header = self.generate_header_error(); + let sig = hir::FnSig { decl, header, span }; + let body_id = self.lower_body(|this| { let expr = hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span }; @@ -312,6 +338,15 @@ impl<'hir> LoweringContext<'_, 'hir> { }); DelegationResults { generics, body_id, sig } } + + fn generate_header_error(&self) -> hir::FnHeader { + hir::FnHeader { + unsafety: hir::Unsafety::Normal, + constness: hir::Constness::NotConst, + asyncness: hir::IsAsync::NotAsync, + abi: abi::Abi::Rust, + } + } } struct SelfResolver<'a> { diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 6799513a323..6f70e135c72 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -421,3 +421,12 @@ pub(crate) struct NoPreciseCapturesOnApit { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_yield_in_closure)] +pub(crate) struct YieldInClosure { + #[primary_span] + pub span: Span, + #[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")] + pub suggestion: Option<Span>, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2305cc07795..5cc05d7336e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -8,6 +8,7 @@ use super::errors::{ }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; +use crate::errors::YieldInClosure; use crate::{FnDeclKind, ImplTraitPosition}; use rustc_ast::ptr::P as AstP; use rustc_ast::*; @@ -217,6 +218,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, + hir_id, *constness, *movability, fn_decl, @@ -955,6 +957,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, + closure_hir_id: hir::HirId, constness: Const, movability: Movability, decl: &FnDecl, @@ -965,8 +968,17 @@ impl<'hir> LoweringContext<'_, 'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { - let mut coroutine_kind = None; + let mut coroutine_kind = if this + .attrs + .get(&closure_hir_id.local_id) + .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) + { + Some(hir::CoroutineKind::Coroutine(Movability::Movable)) + } else { + None + }; let body_id = this.lower_fn_body(decl, |this| { + this.coroutine_kind = coroutine_kind; let e = this.lower_expr_mut(body); coroutine_kind = this.coroutine_kind; e @@ -1565,7 +1577,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) .emit(); } + let suggestion = self.current_item.map(|s| s.shrink_to_lo()); + self.dcx().emit_err(YieldInClosure { span, suggestion }); self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable)); + false } }; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e4c633aa324..dcce54d66c2 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -203,7 +203,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, .. }) => { - self.with_new_scopes(ident.span, |this| { + self.with_new_scopes(*fn_sig_span, |this| { // Note: we don't need to change the return type from `T` to // `impl Future<Output = T>` here because lower_body // only cares about the input argument patterns in the function @@ -1344,7 +1344,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } - fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { + pub(super) fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind { hir::IsAsync::Async(span) } else { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 70a3ccb0f44..d86196cbaa9 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -556,7 +556,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { half_open_range_patterns_in_slices, "half-open range patterns in slices are unstable" ); - gate_all!(inline_const, "inline-const is experimental"); gate_all!(inline_const_pat, "inline-const in pattern position is experimental"); gate_all!(associated_const_equality, "associated const equality is incomplete"); gate_all!(yeet_expr, "`do yeet` expression is experimental"); diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 439f13e7635..1c2077372e1 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -986,7 +986,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { recognised = true; acc.push(h); } - } else if let Some((name, value)) = item.name_value_literal() { + } else if let Some((name, value)) = item.singleton_lit_list() { let mut literal_error = None; let mut err_span = item.span(); if name == sym::align { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 4878da530b0..da58db57525 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -347,7 +347,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { mpi: MovePathIndex, err: &mut Diag<'tcx>, in_pattern: &mut bool, - move_spans: UseSpans<'_>, + move_spans: UseSpans<'tcx>, ) { let move_span = match move_spans { UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span, @@ -491,11 +491,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .. } = move_spans { - self.suggest_cloning(err, ty, expr, None); + self.suggest_cloning(err, ty, expr, None, Some(move_spans)); } else if self.suggest_hoisting_call_outside_loop(err, expr) { // The place where the the type moves would be misleading to suggest clone. // #121466 - self.suggest_cloning(err, ty, expr, None); + self.suggest_cloning(err, ty, expr, None, Some(move_spans)); } } if let Some(pat) = finder.pat { @@ -1085,6 +1085,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty: Ty<'tcx>, mut expr: &'cx hir::Expr<'cx>, mut other_expr: Option<&'cx hir::Expr<'cx>>, + use_spans: Option<UseSpans<'tcx>>, ) { if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind { // We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single @@ -1197,14 +1198,50 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .all(|field| self.implements_clone(field.ty(self.infcx.tcx, args))) }) { + let ty_span = self.infcx.tcx.def_span(def.did()); + let mut span: MultiSpan = ty_span.into(); + span.push_span_label(ty_span, "consider implementing `Clone` for this type"); + span.push_span_label(expr.span, "you could clone this value"); err.span_note( - self.infcx.tcx.def_span(def.did()), + span, + format!("if `{ty}` implemented `Clone`, you could clone the value"), + ); + } else if let ty::Param(param) = ty.kind() + && let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() + && let generics = self.infcx.tcx.generics_of(self.mir_def_id()) + && let generic_param = generics.type_param(*param, self.infcx.tcx) + && let param_span = self.infcx.tcx.def_span(generic_param.def_id) + && if let Some(UseSpans::FnSelfUse { kind, .. }) = use_spans + && let CallKind::FnCall { fn_trait_id, self_ty } = kind + && let ty::Param(_) = self_ty.kind() + && ty == self_ty + && [ + self.infcx.tcx.lang_items().fn_once_trait(), + self.infcx.tcx.lang_items().fn_mut_trait(), + self.infcx.tcx.lang_items().fn_trait(), + ] + .contains(&Some(fn_trait_id)) + { + // Do not suggest `F: FnOnce() + Clone`. + false + } else { + true + } + { + let mut span: MultiSpan = param_span.into(); + span.push_span_label( + param_span, + "consider constraining this type parameter with `Clone`", + ); + span.push_span_label(expr.span, "you could clone this value"); + err.span_help( + span, format!("if `{ty}` implemented `Clone`, you could clone the value"), ); } } - fn implements_clone(&self, ty: Ty<'tcx>) -> bool { + pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool { let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false }; self.infcx .type_implements_trait(clone_trait_def, [ty], self.param_env) @@ -1403,7 +1440,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some(expr) = self.find_expr(borrow_span) && let Some(ty) = typeck_results.node_type_opt(expr.hir_id) { - self.suggest_cloning(&mut err, ty, expr, self.find_expr(span)); + self.suggest_cloning(&mut err, ty, expr, self.find_expr(span), Some(move_spans)); } self.buffer_error(err); } @@ -1490,7 +1527,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, ) => { first_borrow_desc = "mutable "; - self.cannot_reborrow_already_borrowed( + let mut err = self.cannot_reborrow_already_borrowed( span, &desc_place, &msg_place, @@ -1500,7 +1537,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "mutable", &msg_borrow, None, - ) + ); + self.suggest_slice_method_if_applicable( + &mut err, + place, + issued_borrow.borrowed_place, + span, + issued_span, + ); + err } ( BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, @@ -1518,6 +1563,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &msg_borrow, None, ); + self.suggest_slice_method_if_applicable( + &mut err, + place, + issued_borrow.borrowed_place, + span, + issued_span, + ); self.suggest_binding_for_closure_capture_self(&mut err, &issued_spans); self.suggest_using_closure_argument_instead_of_capture( &mut err, @@ -1544,6 +1596,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut err, place, issued_borrow.borrowed_place, + span, + issued_span, ); self.suggest_using_closure_argument_instead_of_capture( &mut err, @@ -1964,7 +2018,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { pub(crate) fn find_expr(&self, span: Span) -> Option<&hir::Expr<'_>> { let tcx = self.infcx.tcx; let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?; - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan::new(span, tcx); expr_finder.visit_expr(tcx.hir().body(body_id).value); expr_finder.result } @@ -1974,40 +2028,47 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err: &mut Diag<'_>, place: Place<'tcx>, borrowed_place: Place<'tcx>, + span: Span, + issued_span: Span, ) { let tcx = self.infcx.tcx; let hir = tcx.hir(); + let has_split_at_mut = |ty: Ty<'tcx>| { + let ty = ty.peel_refs(); + match ty.kind() { + ty::Array(..) | ty::Slice(..) => true, + ty::Adt(def, _) if tcx.get_diagnostic_item(sym::Vec) == Some(def.did()) => true, + _ if ty == tcx.types.str_ => true, + _ => false, + } + }; if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)]) | ( [ProjectionElem::Deref, ProjectionElem::Index(index1)], [ProjectionElem::Deref, ProjectionElem::Index(index2)], ) = (&place.projection[..], &borrowed_place.projection[..]) { + let decl1 = &self.body.local_decls[*index1]; + let decl2 = &self.body.local_decls[*index2]; + let mut note_default_suggestion = || { err.help( - "consider using `.split_at_mut(position)` or similar method to obtain \ - two mutable non-overlapping sub-slices", + "consider using `.split_at_mut(position)` or similar method to obtain two \ + mutable non-overlapping sub-slices", ) - .help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices"); - }; - - let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { - note_default_suggestion(); - return; + .help( + "consider using `.swap(index_1, index_2)` to swap elements at the specified \ + indices", + ); }; - let mut expr_finder = - FindExprBySpan::new(self.body.local_decls[*index1].source_info.span); - expr_finder.visit_expr(hir.body(body_id).value); - let Some(index1) = expr_finder.result else { + let Some(index1) = self.find_expr(decl1.source_info.span) else { note_default_suggestion(); return; }; - expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span); - expr_finder.visit_expr(hir.body(body_id).value); - let Some(index2) = expr_finder.result else { + let Some(index2) = self.find_expr(decl2.source_info.span) else { note_default_suggestion(); return; }; @@ -2055,7 +2116,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None } }) else { - note_default_suggestion(); + let hir::Node::Expr(parent) = tcx.parent_hir_node(index1.hir_id) else { return }; + let hir::ExprKind::Index(_, idx1, _) = parent.kind else { return }; + let hir::Node::Expr(parent) = tcx.parent_hir_node(index2.hir_id) else { return }; + let hir::ExprKind::Index(_, idx2, _) = parent.kind else { return }; + if !idx1.equivalent_for_indexing(idx2) { + err.help("use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices"); + } return; }; @@ -2065,7 +2132,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("{obj_str}.swap({index1_str}, {index2_str})"), Applicability::MachineApplicable, ); + return; + } + let place_ty = PlaceRef::ty(&place.as_ref(), self.body, tcx).ty; + let borrowed_place_ty = PlaceRef::ty(&borrowed_place.as_ref(), self.body, tcx).ty; + if !has_split_at_mut(place_ty) && !has_split_at_mut(borrowed_place_ty) { + // Only mention `split_at_mut` on `Vec`, array and slices. + return; } + let Some(index1) = self.find_expr(span) else { return }; + let hir::Node::Expr(parent) = tcx.parent_hir_node(index1.hir_id) else { return }; + let hir::ExprKind::Index(_, idx1, _) = parent.kind else { return }; + let Some(index2) = self.find_expr(issued_span) else { return }; + let hir::Node::Expr(parent) = tcx.parent_hir_node(index2.hir_id) else { return }; + let hir::ExprKind::Index(_, idx2, _) = parent.kind else { return }; + if idx1.equivalent_for_indexing(idx2) { + // `let a = &mut foo[0]` and `let b = &mut foo[0]`? Don't mention `split_at_mut` + return; + } + err.help("use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices"); } /// Suggest using `while let` for call `next` on an iterator in a for loop. @@ -3706,7 +3791,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | None => (self.describe_any_place(place.as_ref()), assigned_span), Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span), }; - let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg); let msg = if from_arg { "cannot assign to immutable argument" @@ -3726,6 +3810,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("mut {name}"), Applicability::MachineApplicable, ); + if !from_arg + && matches!( + decl.local_info(), + LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_match_place: Some((Some(_), _)), + .. + })) + ) + { + err.span_suggestion( + decl.source_info.span, + "to modify the original value, take a borrow instead", + format!("ref mut {name}"), + Applicability::MaybeIncorrect, + ); + } } err.span_label(span, msg); self.buffer_error(err); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 418eabe3ae2..5ebdb69050b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -76,7 +76,7 @@ impl<'tcx> BorrowExplanation<'tcx> { && let Some(body_id) = node.body_id() { let body = tcx.hir().body(body_id); - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan::new(span, tcx); expr_finder.visit_expr(body.value); if let Some(mut expr) = expr_finder.result { while let hir::ExprKind::AddrOf(_, _, inner) diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index bc02c5be93d..288b846daf5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -2,10 +2,13 @@ #![allow(rustc::untranslatable_diagnostic)] use rustc_errors::{Applicability, Diag}; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{CaptureBy, ExprKind, HirId, Node}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; +use rustc_trait_selection::traits::error_reporting::FindExprBySpan; use crate::diagnostics::CapturedMessageOpt; use crate::diagnostics::{DescribePlaceOpt, UseSpans}; @@ -303,6 +306,121 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.cannot_move_out_of(span, &description) } + fn suggest_clone_of_captured_var_in_move_closure( + &self, + err: &mut Diag<'_>, + upvar_hir_id: HirId, + upvar_name: &str, + use_spans: Option<UseSpans<'tcx>>, + ) { + let tcx = self.infcx.tcx; + let typeck_results = tcx.typeck(self.mir_def_id()); + let Some(use_spans) = use_spans else { return }; + // We only care about the case where a closure captured a binding. + let UseSpans::ClosureUse { args_span, .. } = use_spans else { return }; + let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return }; + // Fetch the type of the expression corresponding to the closure-captured binding. + let Some(captured_ty) = typeck_results.node_type_opt(upvar_hir_id) else { return }; + if !self.implements_clone(captured_ty) { + // We only suggest cloning the captured binding if the type can actually be cloned. + return; + }; + // Find the closure that captured the binding. + let mut expr_finder = FindExprBySpan::new(args_span, tcx); + expr_finder.include_closures = true; + expr_finder.visit_expr(tcx.hir().body(body_id).value); + let Some(closure_expr) = expr_finder.result else { return }; + let ExprKind::Closure(closure) = closure_expr.kind else { return }; + // We'll only suggest cloning the binding if it's a `move` closure. + let CaptureBy::Value { .. } = closure.capture_clause else { return }; + // Find the expression within the closure where the binding is consumed. + let mut suggested = false; + let use_span = use_spans.var_or_use(); + let mut expr_finder = FindExprBySpan::new(use_span, tcx); + expr_finder.include_closures = true; + expr_finder.visit_expr(tcx.hir().body(body_id).value); + let Some(use_expr) = expr_finder.result else { return }; + let parent = tcx.parent_hir_node(use_expr.hir_id); + if let Node::Expr(expr) = parent + && let ExprKind::Assign(lhs, ..) = expr.kind + && lhs.hir_id == use_expr.hir_id + { + // Cloning the value being assigned makes no sense: + // + // error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + // --> $DIR/option-content-move2.rs:11:9 + // | + // LL | let mut var = None; + // | ------- captured outer variable + // LL | func(|| { + // | -- captured by this `FnMut` closure + // LL | // Shouldn't suggest `move ||.as_ref()` here + // LL | move || { + // | ^^^^^^^ `var` is moved here + // LL | + // LL | var = Some(NotCopyable); + // | --- + // | | + // | variable moved due to use in closure + // | move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait + // | + return; + } + + // Search for an appropriate place for the structured `.clone()` suggestion to be applied. + // If we encounter a statement before the borrow error, we insert a statement there. + for (_, node) in tcx.hir().parent_iter(closure_expr.hir_id) { + if let Node::Stmt(stmt) = node { + let padding = tcx + .sess + .source_map() + .indentation_before(stmt.span) + .unwrap_or_else(|| " ".to_string()); + err.multipart_suggestion_verbose( + "clone the value before moving it into the closure", + vec![ + ( + stmt.span.shrink_to_lo(), + format!("let value = {upvar_name}.clone();\n{padding}"), + ), + (use_span, "value".to_string()), + ], + Applicability::MachineApplicable, + ); + suggested = true; + break; + } else if let Node::Expr(expr) = node + && let ExprKind::Closure(_) = expr.kind + { + // We want to suggest cloning only on the first closure, not + // subsequent ones (like `ui/suggestions/option-content-move2.rs`). + break; + } + } + if !suggested { + // If we couldn't find a statement for us to insert a new `.clone()` statement before, + // we have a bare expression, so we suggest the creation of a new block inline to go + // from `move || val` to `{ let value = val.clone(); move || value }`. + let padding = tcx + .sess + .source_map() + .indentation_before(closure_expr.span) + .unwrap_or_else(|| " ".to_string()); + err.multipart_suggestion_verbose( + "clone the value before moving it into the closure", + vec![ + ( + closure_expr.span.shrink_to_lo(), + format!("{{\n{padding}let value = {upvar_name}.clone();\n{padding}"), + ), + (use_spans.var_or_use(), "value".to_string()), + (closure_expr.span.shrink_to_hi(), format!("\n{padding}}}")), + ], + Applicability::MachineApplicable, + ); + } + } + fn report_cannot_move_from_borrowed_content( &mut self, move_place: Place<'tcx>, @@ -310,10 +428,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { span: Span, use_spans: Option<UseSpans<'tcx>>, ) -> Diag<'tcx> { + let tcx = self.infcx.tcx; // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. - let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty; + let ty = deref_target_place.ty(self.body, tcx).ty; let upvar_field = self .prefixes(move_place.as_ref(), PrefixSet::All) .find_map(|p| self.is_upvar_field_projection(p)); @@ -363,8 +482,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar = &self.upvars[upvar_field.unwrap().index()]; let upvar_hir_id = upvar.get_root_variable(); - let upvar_name = upvar.to_string(self.infcx.tcx); - let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); + let upvar_name = upvar.to_string(tcx); + let upvar_span = tcx.hir().span(upvar_hir_id); let place_name = self.describe_any_place(move_place.as_ref()); @@ -380,12 +499,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { closure_kind_ty, closure_kind, place_description, ); - self.cannot_move_out_of(span, &place_description) + let closure_span = tcx.def_span(def_id); + let mut err = self + .cannot_move_out_of(span, &place_description) .with_span_label(upvar_span, "captured outer variable") .with_span_label( - self.infcx.tcx.def_span(def_id), + closure_span, format!("captured by this `{closure_kind}` closure"), - ) + ); + self.suggest_clone_of_captured_var_in_move_closure( + &mut err, + upvar_hir_id, + &upvar_name, + use_spans, + ); + err } _ => { let source = self.borrowed_content_source(deref_base); @@ -415,7 +543,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), (_, _, _) => self.cannot_move_out_of( span, - &source.describe_for_unnamed_place(self.infcx.tcx), + &source.describe_for_unnamed_place(tcx), ), } } @@ -447,7 +575,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if let Some(expr) = self.find_expr(span) { - self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span)); + self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None); } err.subdiagnostic( @@ -482,7 +610,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if let Some(expr) = self.find_expr(use_span) { - self.suggest_cloning(err, place_ty, expr, self.find_expr(span)); + self.suggest_cloning( + err, + place_ty, + expr, + self.find_expr(span), + Some(use_spans), + ); } err.subdiagnostic( @@ -595,7 +729,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let place_desc = &format!("`{}`", self.local_names[*local].unwrap()); if let Some(expr) = self.find_expr(binding_span) { - self.suggest_cloning(err, bind_to.ty, expr, None); + self.suggest_cloning(err, bind_to.ty, expr, None, None); } err.subdiagnostic( diff --git a/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs b/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs index c965b34e13b..407da94c0f0 100644 --- a/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs +++ b/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; @@ -8,7 +8,8 @@ fn main() { } fn run_coroutine<T>() { - let mut coroutine = || { + let mut coroutine = #[coroutine] + || { yield; return; }; diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 0205de55622..90d4ab721da 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -1,6 +1,7 @@ #![feature( core_intrinsics, coroutines, + stmt_expr_attributes, coroutine_trait, is_sorted, repr_simd, @@ -123,9 +124,12 @@ fn main() { test_simd(); } - Box::pin(move |mut _task_context| { - yield (); - }) + Box::pin( + #[coroutine] + move |mut _task_context| { + yield (); + }, + ) .as_mut() .resume(0); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 32b9c824ded..78b3d5a58f4 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -7,7 +7,7 @@ use cranelift_codegen::binemit::CodeOffset; use cranelift_codegen::MachSrcLoc; use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable}; use rustc_span::{ - FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, + hygiene, FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, }; use crate::debuginfo::emit::address_for_func; @@ -63,11 +63,8 @@ impl DebugContext { function_span: Span, span: Span, ) -> (FileId, u64, u64) { - // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131 - // In order to have a good line stepping behavior in debugger, we overwrite debug - // locations of macro expansions with that of the outermost expansion site (when the macro is - // annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - let span = tcx.collapsed_debuginfo(span, function_span); + // Match behavior of `FunctionCx::adjusted_span_and_dbg_scope`. + let span = hygiene::walk_chain_collapsed(span, function_span); match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { let file_id = self.add_source_file(&file); diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs index ad69409eb65..8ab8fcc525e 100644 --- a/compiler/rustc_codegen_gcc/example/std_example.rs +++ b/compiler/rustc_codegen_gcc/example/std_example.rs @@ -1,5 +1,5 @@ #![allow(internal_features)] -#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted)] +#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted, stmt_expr_attributes)] #[cfg(feature="master")] #[cfg(target_arch="x86_64")] @@ -103,7 +103,7 @@ fn main() { test_simd(); } - Box::pin(move |mut _task_context| { + Box::pin(#[coroutine] move |mut _task_context| { yield (); }).as_mut().resume(0); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index aec11e9905f..123aef0f310 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -2,6 +2,7 @@ use crate::attributes; use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, Attribute, AttributePlace}; +use crate::llvm_util; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -425,6 +426,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { cx.type_array(cx.type_i8(), self.ret.layout.size.bytes()), ); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]); + if cx.sess().opts.optimize != config::OptLevel::No + && llvm_util::get_version() >= (18, 0, 0) + { + attributes::apply_to_llfn( + llfn, + llvm::AttributePlace::Argument(i), + &[ + llvm::AttributeKind::Writable.create_attr(cx.llcx), + llvm::AttributeKind::DeadOnUnwind.create_attr(cx.llcx), + ], + ); + } } PassMode::Cast { cast, pad_i32: _ } => { cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a10dc61967e..7a34e21628d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -200,6 +200,8 @@ pub enum AttributeKind { AllocAlign = 39, SanitizeSafeStack = 40, FnRetThunkExtern = 41, + Writable = 42, + DeadOnUnwind = 43, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 9c9e134f033..c28b0d644e6 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -435,7 +435,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::repr => { codegen_fn_attrs.alignment = if let Some(items) = attr.meta_item_list() && let [item] = items.as_slice() - && let Some((sym::align, literal)) = item.name_value_literal() + && let Some((sym::align, literal)) = item.singleton_lit_list() { rustc_attr::parse_alignment(&literal.kind) .map_err(|msg| { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index a5fd82a3054..d0e2fc2de12 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -4,13 +4,12 @@ use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Instance; use rustc_middle::ty::Ty; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{hygiene, BytePos, Span}; use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; @@ -220,26 +219,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, source_info: mir::SourceInfo, ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> { - let span = self.adjust_span_for_debugging(source_info.span); let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]; + let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span); Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span)) } - /// In order to have a good line stepping behavior in debugger, we overwrite debug - /// locations of macro expansions with that of the outermost expansion site (when the macro is - /// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - fn adjust_span_for_debugging(&self, span: Span) -> Span { - // Bail out if debug info emission is not enabled. - if self.debug_context.is_none() { - return span; - } - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - // Use span of the outermost expansion site, while keeping the original lexical scope. - self.cx.tcx().collapsed_debuginfo(span, self.mir.span) - } - fn spill_operand_to_stack( operand: OperandRef<'tcx, Bx::Value>, name: Option<String>, diff --git a/compiler/rustc_error_codes/src/error_codes/E0626.md b/compiler/rustc_error_codes/src/error_codes/E0626.md index e2534415d83..28d543350ff 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0626.md +++ b/compiler/rustc_error_codes/src/error_codes/E0626.md @@ -4,10 +4,10 @@ yield point. Erroneous code example: ```compile_fail,E0626 -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let a = &String::new(); // <-- This borrow... yield (); // ...is still in scope here, when the yield occurs. println!("{}", a); @@ -23,10 +23,10 @@ resolve the previous example by removing the borrow and just storing the integer by value: ``` -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let a = 3; yield (); println!("{}", a); @@ -41,10 +41,10 @@ in those cases, something like the `Rc` or `Arc` types may be useful. This error also frequently arises with iteration: ```compile_fail,E0626 -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let v = vec![1,2,3]; for &x in &v { // <-- borrow of `v` is still in scope... yield x; // ...when this yield occurs. @@ -57,10 +57,10 @@ Such cases can sometimes be resolved by iterating "by value" (or using `into_iter()`) to avoid borrowing: ``` -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let v = vec![1,2,3]; for x in v { // <-- Take ownership of the values instead! yield x; // <-- Now yield is OK. @@ -72,10 +72,10 @@ Pin::new(&mut b).resume(()); If taking ownership is not an option, using indices can work too: ``` -# #![feature(coroutines, coroutine_trait, pin)] +# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] # use std::ops::Coroutine; # use std::pin::Pin; -let mut b = || { +let mut b = #[coroutine] || { let v = vec![1,2,3]; let len = v.len(); // (*) for i in 0..len { diff --git a/compiler/rustc_error_codes/src/error_codes/E0627.md b/compiler/rustc_error_codes/src/error_codes/E0627.md index 5d366f78fc5..da2e2d355a1 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0627.md +++ b/compiler/rustc_error_codes/src/error_codes/E0627.md @@ -3,7 +3,7 @@ A yield expression was used outside of the coroutine literal. Erroneous code example: ```compile_fail,E0627 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn fake_coroutine() -> &'static str { yield 1; @@ -19,10 +19,10 @@ The error occurs because keyword `yield` can only be used inside the coroutine literal. This can be fixed by constructing the coroutine correctly. ``` -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo" }; diff --git a/compiler/rustc_error_codes/src/error_codes/E0628.md b/compiler/rustc_error_codes/src/error_codes/E0628.md index ce19bcd56cc..d0d387cf6c7 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0628.md +++ b/compiler/rustc_error_codes/src/error_codes/E0628.md @@ -3,10 +3,10 @@ More than one parameter was used for a coroutine. Erroneous code example: ```compile_fail,E0628 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let coroutine = |a: i32, b: i32| { + let coroutine = #[coroutine] |a: i32, b: i32| { // error: too many parameters for a coroutine // Allowed only 0 or 1 parameter yield a; @@ -20,10 +20,10 @@ at most 1 parameter for the coroutine. For example, we might resolve the previous example by passing only one parameter. ``` -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let coroutine = |a: i32| { + let coroutine = #[coroutine] |a: i32| { yield a; }; } diff --git a/compiler/rustc_error_codes/src/error_codes/E0727.md b/compiler/rustc_error_codes/src/error_codes/E0727.md index fde35885c92..7754186508f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0727.md +++ b/compiler/rustc_error_codes/src/error_codes/E0727.md @@ -3,10 +3,10 @@ A `yield` clause was used in an `async` context. Erroneous code example: ```compile_fail,E0727,edition2018 -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let coroutine = || { + let coroutine = #[coroutine] || { async { yield; } @@ -20,10 +20,10 @@ which is not yet supported. To fix this error, you have to move `yield` out of the `async` block: ```edition2018 -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let coroutine = || { + let coroutine = #[coroutine] || { yield; }; } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b3c1c6c8515..adbac80d7cc 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -502,7 +502,7 @@ struct DiagCtxtInner { } /// A key denoting where from a diagnostic was stashed. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum StashKey { ItemNoType, UnderscoreForArrayLengths, @@ -779,7 +779,7 @@ impl DiagCtxt { // We delay a bug here so that `-Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs` // can be used to create a backtrace at the stashing site insted of whenever the // diagnostic context is dropped and thus delayed bugs are emitted. - Error => Some(self.span_delayed_bug(span, "stashing {key:?}")), + Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))), DelayedBug => return self.inner.borrow_mut().emit_diagnostic(diag), ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow | Expect(_) => None, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b25dd8fe67b..3c465709ec7 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -789,55 +789,50 @@ impl SyntaxExtension { } } - fn collapse_debuginfo_by_name(sess: &Session, attr: &Attribute) -> CollapseMacroDebuginfo { - use crate::errors::CollapseMacroDebuginfoIllegal; - // #[collapse_debuginfo] without enum value (#[collapse_debuginfo(no/external/yes)]) - // considered as `yes` - attr.meta_item_list().map_or(CollapseMacroDebuginfo::Yes, |l| { - let [NestedMetaItem::MetaItem(item)] = &l[..] else { - sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: attr.span }); - return CollapseMacroDebuginfo::Unspecified; - }; - if !item.is_word() { - sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span }); - CollapseMacroDebuginfo::Unspecified - } else { - match item.name_or_empty() { - sym::no => CollapseMacroDebuginfo::No, - sym::external => CollapseMacroDebuginfo::External, - sym::yes => CollapseMacroDebuginfo::Yes, - _ => { - sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span }); - CollapseMacroDebuginfo::Unspecified - } - } - } - }) + fn collapse_debuginfo_by_name(attr: &Attribute) -> Result<CollapseMacroDebuginfo, Span> { + let list = attr.meta_item_list(); + let Some([NestedMetaItem::MetaItem(item)]) = list.as_deref() else { + return Err(attr.span); + }; + if !item.is_word() { + return Err(item.span); + } + + match item.name_or_empty() { + sym::no => Ok(CollapseMacroDebuginfo::No), + sym::external => Ok(CollapseMacroDebuginfo::External), + sym::yes => Ok(CollapseMacroDebuginfo::Yes), + _ => Err(item.path.span), + } } /// if-ext - if macro from different crate (related to callsite code) /// | cmd \ attr | no | (unspecified) | external | yes | /// | no | no | no | no | no | - /// | (unspecified) | no | no | if-ext | yes | + /// | (unspecified) | no | if-ext | if-ext | yes | /// | external | no | if-ext | if-ext | yes | /// | yes | yes | yes | yes | yes | - fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], is_local: bool) -> bool { - let mut collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo) - .map(|v| Self::collapse_debuginfo_by_name(sess, v)) - .unwrap_or(CollapseMacroDebuginfo::Unspecified); - if collapse_debuginfo_attr == CollapseMacroDebuginfo::Unspecified - && attr::contains_name(attrs, sym::rustc_builtin_macro) - { - collapse_debuginfo_attr = CollapseMacroDebuginfo::Yes; - } - - let flag = sess.opts.unstable_opts.collapse_macro_debuginfo; - let attr = collapse_debuginfo_attr; - let ext = !is_local; + fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], ext: bool) -> bool { + let flag = sess.opts.cg.collapse_macro_debuginfo; + let attr = attr::find_by_name(attrs, sym::collapse_debuginfo) + .and_then(|attr| { + Self::collapse_debuginfo_by_name(attr) + .map_err(|span| { + sess.dcx().emit_err(errors::CollapseMacroDebuginfoIllegal { span }) + }) + .ok() + }) + .unwrap_or_else(|| { + if attr::contains_name(attrs, sym::rustc_builtin_macro) { + CollapseMacroDebuginfo::Yes + } else { + CollapseMacroDebuginfo::Unspecified + } + }); #[rustfmt::skip] let collapse_table = [ [false, false, false, false], - [false, false, ext, true], + [false, ext, ext, true], [false, ext, ext, true], [true, true, true, true], ]; @@ -864,7 +859,7 @@ impl SyntaxExtension { let local_inner_macros = attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) .is_some_and(|l| attr::list_contains_name(&l, sym::local_inner_macros)); - let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, is_local); + let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local); tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 1eee11604ce..de2bd60ffad 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -98,6 +98,8 @@ declare_features! ( (accepted, closure_to_fn_coercion, "1.19.0", Some(39817)), /// Allows using the CMPXCHG16B target feature. (accepted, cmpxchg16b_target_feature, "1.69.0", Some(44839)), + /// Allows use of the `#[collapse_debuginfo]` attribute. + (accepted, collapse_debuginfo, "CURRENT_RUSTC_VERSION", Some(100758)), /// Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872)), /// Allows `impl Trait` in function return types. @@ -211,6 +213,8 @@ declare_features! ( (accepted, inclusive_range_syntax, "1.26.0", Some(28237)), /// Allows inferring outlives requirements (RFC 2093). (accepted, infer_outlives_requirements, "1.30.0", Some(44493)), + /// Allow anonymous constants from an inline `const` block + (accepted, inline_const, "CURRENT_RUSTC_VERSION", Some(76001)), /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). (accepted, irrefutable_let_patterns, "1.33.0", Some(44495)), /// Allows `#[instruction_set(_)]` attribute. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 23b3f31b437..9d3aac66c41 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -450,6 +450,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), DuplicatesOk, EncodeCrossCrate::No ), + ungated!(collapse_debuginfo, Normal, template!(List: "no|external|yes"), ErrorFollowing, + EncodeCrossCrate::Yes + ), // ========================================================================== // Unstable attributes: @@ -516,12 +519,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, experimental!(deprecated_safe), ), - // `#[collapse_debuginfo]` - gated!( - collapse_debuginfo, Normal, template!(Word, List: "no|external|yes"), ErrorFollowing, - EncodeCrossCrate::No, experimental!(collapse_debuginfo) - ), - // RFC 2397 gated!( do_not_recommend, Normal, template!(Word), WarnFollowing, @@ -534,6 +531,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, experimental!(cfi_encoding) ), + // `#[coroutine]` attribute to be applied to closures to make them coroutines instead + gated!( + coroutine, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, coroutines, experimental!(coroutines) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 9641d336c3f..132e2ddee29 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -395,8 +395,6 @@ declare_features! ( (unstable, closure_track_caller, "1.57.0", Some(87417)), /// Allows to use the `#[cmse_nonsecure_entry]` attribute. (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)), - /// Allows use of the `#[collapse_debuginfo]` attribute. - (unstable, collapse_debuginfo, "1.65.0", Some(100758)), /// Allows `async {}` expressions in const contexts. (unstable, const_async_blocks, "1.53.0", Some(85368)), /// Allows `const || {}` closures in const contexts. @@ -501,8 +499,6 @@ declare_features! ( (unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697)), /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995)), - /// Allow anonymous constants from an inline `const` block - (unstable, inline_const, "1.49.0", Some(76001)), /// Allow anonymous constants from an inline `const` block in pattern position (unstable, inline_const_pat, "1.58.0", Some(76001)), /// Allows using `pointer` and `reference` in intra-doc links diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 3359fef8c1c..d376c24cb58 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(absolute_path)] - use std::ffi::CString; use std::fs; use std::io; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2268905430a..1646ea50fb0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1811,6 +1811,44 @@ impl Expr<'_> { } } + /// Whether this and the `other` expression are the same for purposes of an indexing operation. + /// + /// This is only used for diagnostics to see if we have things like `foo[i]` where `foo` is + /// borrowed multiple times with `i`. + pub fn equivalent_for_indexing(&self, other: &Expr<'_>) -> bool { + match (self.kind, other.kind) { + (ExprKind::Lit(lit1), ExprKind::Lit(lit2)) => lit1.node == lit2.node, + ( + ExprKind::Path(QPath::LangItem(item1, _)), + ExprKind::Path(QPath::LangItem(item2, _)), + ) => item1 == item2, + ( + ExprKind::Path(QPath::Resolved(None, path1)), + ExprKind::Path(QPath::Resolved(None, path2)), + ) => path1.res == path2.res, + ( + ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val1], None), + ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val2], None), + ) + | ( + ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val1], None), + ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val2], None), + ) + | ( + ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val1], None), + ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val2], None), + ) => val1.expr.equivalent_for_indexing(val2.expr), + ( + ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val1, val3], None), + ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val2, val4], None), + ) => { + val1.expr.equivalent_for_indexing(val2.expr) + && val3.expr.equivalent_for_indexing(val4.expr) + } + _ => false, + } + } + pub fn method_ident(&self) -> Option<Ident> { match self.kind { ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 1085caa310b..599f25147ce 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -992,7 +992,7 @@ fn lower_variant( .inspect(|f| { has_unnamed_fields |= f.ident.name == kw::Underscore; // We only check named ADT here because anonymous ADTs are checked inside - // the nammed ADT in which they are defined. + // the named ADT in which they are defined. if !is_anonymous { field_uniqueness_check_ctx.check_field(f); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 4a0df6cf7b8..63da27246a2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1964,11 +1964,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { try_emit("recursive delegation"); } - let sig = self.tcx().fn_sig(sig_id).instantiate_identity(); - if sig.output().has_opaque_types() { - try_emit("delegation to a function with opaque type"); - } - let sig_generics = self.tcx().generics_of(sig_id); let parent = self.tcx().parent(self.item_def_id()); let parent_generics = self.tcx().generics_of(parent); @@ -1991,29 +1986,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { try_emit("delegation to a trait method from a free function"); } - if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes { - try_emit("delegation to async functions"); - } - - if self.tcx().constness(sig_id) == hir::Constness::Const { - try_emit("delegation to const functions"); - } - - if sig.c_variadic() { - try_emit("delegation to variadic functions"); - // variadic functions are also `unsafe` and `extern "C"`. - // Do not emit same error multiple times. - return error_occured; - } - - if let hir::Unsafety::Unsafe = sig.unsafety() { - try_emit("delegation to unsafe functions"); - } - - if abi::Abi::Rust != sig.abi() { - try_emit("delegation to non Rust ABI functions"); - } - error_occured } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index b0d1b6655db..b106eca59c4 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi}; use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::RegionVariableOrigin; +use rustc_infer::traits::WellFormedLoc; use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; @@ -71,6 +72,18 @@ pub(super) fn check_fn<'a, 'tcx>( let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); let inputs_fn = fn_sig.inputs().iter().copied(); for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { + // We checked the root's signature during wfcheck, but not the child. + if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) { + fcx.register_wf_obligation( + param_ty.into(), + param.span, + traits::WellFormed(Some(WellFormedLoc::Param { + function: fn_def_id, + param_idx: idx, + })), + ); + } + // Check the pattern. let ty: Option<&hir::Ty<'_>> = inputs_hir.and_then(|h| h.get(idx)); let ty_span = ty.map(|ty| ty.span); @@ -108,7 +121,13 @@ pub(super) fn check_fn<'a, 'tcx>( hir::FnRetTy::DefaultReturn(_) => body.value.span, hir::FnRetTy::Return(ty) => ty.span, }; + fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); + // We checked the root's signature during wfcheck, but not the child. + if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) { + fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::WellFormed(None)); + } + fcx.is_whole_body.set(true); fcx.check_return_expr(body.value, false); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9ebb5f95f05..4165fa7f07d 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // are the same function and their parameters have a LUB. match self.commit_if_ok(|_| { self.at(cause, self.param_env).lub( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, prev_ty, new_ty, ) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index f6014bcd893..68c7f187f52 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -600,6 +600,7 @@ fn test_codegen_options_tracking_hash() { // Make sure that changing a [TRACKED] option changes the hash. // tidy-alphabetical-start tracked!(code_model, Some(CodeModel::Large)); + tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes); tracked!(control_flow_guard, CFGuard::Checks); tracked!(debug_assertions, Some(true)); tracked!(debuginfo, DebugInfo::Limited); @@ -760,12 +761,10 @@ fn test_unstable_options_tracking_hash() { }) ); tracked!(codegen_backend, Some("abc".to_string())); - tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes); tracked!(coverage_options, CoverageOptions { branch: true, mcdc: true }); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(cross_crate_inline_threshold, InliningThreshold::Always); tracked!(debug_info_for_profiling, true); - tracked!(debug_macros, true); tracked!(default_hidden_visibility, Some(true)); tracked!(dep_info_omit_d_target, true); tracked!(direct_access_external_data, Some(true)); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 83fff98bad5..6f8a9792b6c 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -630,7 +630,7 @@ impl Cursor<'_> { // with a number self.bump(); let mut empty_exponent = false; - if self.first().is_digit(10) { + if self.first().is_ascii_digit() { self.eat_decimal_digits(); match self.first() { 'e' | 'E' => { @@ -661,7 +661,7 @@ impl Cursor<'_> { // If the first symbol is valid for identifier, it can be a lifetime. // Also check if it's a number for a better error reporting (so '0 will // be reported as invalid lifetime and not as unterminated char literal). - is_id_start(self.first()) || self.first().is_digit(10) + is_id_start(self.first()) || self.first().is_ascii_digit() }; if !can_be_a_lifetime { @@ -677,7 +677,7 @@ impl Cursor<'_> { // Either a lifetime or a character literal with // length greater than 1. - let starts_with_number = self.first().is_digit(10); + let starts_with_number = self.first().is_ascii_digit(); // Skip the literal contents. // First symbol can be a number (which isn't a valid identifier start), diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 03d178eb266..d6ea4249247 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -259,7 +259,7 @@ fn scan_escape<T: From<char> + From<u8>>( } else { // This may be a high byte, but that will only happen if `T` is // `MixedUnit`, because of the `allow_high_bytes` check above. - Ok(T::from(value as u8)) + Ok(T::from(value)) }; } 'u' => return scan_unicode(chars, mode.allow_unicode_escapes()).map(T::from), @@ -300,7 +300,7 @@ fn scan_unicode(chars: &mut Chars<'_>, allow_unicode_escapes: bool) -> Result<ch return Err(EscapeError::UnicodeEscapeInByte); } - break std::char::from_u32(value).ok_or_else(|| { + break std::char::from_u32(value).ok_or({ if value > 0x10FFFF { EscapeError::OutOfRangeUnicodeEscape } else { diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 66ca94d1d9c..024f6f89a4b 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -50,7 +50,7 @@ fn detect_llvm_link() -> (&'static str, &'static str) { fn restore_library_path() { let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR"); if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") { - env::set_var(&key, &env); + env::set_var(&key, env); } else { env::remove_var(&key); } diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 6d578c97f3f..a493abbbc7e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -91,6 +91,8 @@ enum LLVMRustAttribute { AllocAlign = 39, SanitizeSafeStack = 40, FnRetThunkExtern = 41, + Writable = 42, + DeadOnUnwind = 43, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 565bdc3af03..20167a4b45e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -312,6 +312,16 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::SafeStack; case FnRetThunkExtern: return Attribute::FnRetThunkExtern; +#if LLVM_VERSION_GE(18, 0) + case Writable: + return Attribute::Writable; + case DeadOnUnwind: + return Attribute::DeadOnUnwind; +#else + case Writable: + case DeadOnUnwind: + report_fatal_error("Not supported on this LLVM version"); +#endif } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_macros/build.rs b/compiler/rustc_macros/build.rs index 717f8a92245..62e827371a7 100644 --- a/compiler/rustc_macros/build.rs +++ b/compiler/rustc_macros/build.rs @@ -1,7 +1,7 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP"); - if !std::env::var("RUSTC_BOOTSTRAP").is_ok() { + if std::env::var("RUSTC_BOOTSTRAP").is_err() { eprintln!( "error: you are attempting to build the compiler without going through bootstrap" ); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index c4ab4eb2657..fd42c9c1faa 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1260,30 +1260,34 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { id: DefIndex, sess: &'a Session, ) -> impl Iterator<Item = ModChild> + 'a { - iter::from_coroutine(move || { - if let Some(data) = &self.root.proc_macro_data { - // If we are loading as a proc macro, we want to return - // the view of this crate as a proc macro crate. - if id == CRATE_DEF_INDEX { - for child_index in data.macros.decode(self) { + iter::from_coroutine( + #[cfg_attr(not(bootstrap), coroutine)] + move || { + if let Some(data) = &self.root.proc_macro_data { + // If we are loading as a proc macro, we want to return + // the view of this crate as a proc macro crate. + if id == CRATE_DEF_INDEX { + for child_index in data.macros.decode(self) { + yield self.get_mod_child(child_index, sess); + } + } + } else { + // Iterate over all children. + let non_reexports = + self.root.tables.module_children_non_reexports.get(self, id); + for child_index in non_reexports.unwrap().decode(self) { yield self.get_mod_child(child_index, sess); } - } - } else { - // Iterate over all children. - let non_reexports = self.root.tables.module_children_non_reexports.get(self, id); - for child_index in non_reexports.unwrap().decode(self) { - yield self.get_mod_child(child_index, sess); - } - let reexports = self.root.tables.module_children_reexports.get(self, id); - if !reexports.is_default() { - for reexport in reexports.decode((self, sess)) { - yield reexport; + let reexports = self.root.tables.module_children_reexports.get(self, id); + if !reexports.is_default() { + for reexport in reexports.decode((self, sess)) { + yield reexport; + } } } - } - }) + }, + ) } fn is_ctfe_mir_available(self, id: DefIndex) -> bool { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index aadaca18326..501052b7411 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -35,8 +35,9 @@ #![feature(const_type_name)] #![feature(discriminant_kind)] #![feature(coroutines)] +#![feature(stmt_expr_attributes)] #![feature(if_let_guard)] -#![feature(inline_const)] +#![cfg_attr(bootstrap, feature(inline_const))] #![feature(iter_from_coroutine)] #![feature(negative_impls)] #![feature(never_type)] diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index ceee3ea48e3..b1e34dcd5f3 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -328,11 +328,16 @@ pub enum ObligationCauseCode<'tcx> { /// `static` items must have `Sync` type. SharedStatic, + /// Derived obligation (i.e. theoretical `where` clause) on a built-in + /// implementation like `Copy` or `Sized`. BuiltinDerivedObligation(DerivedObligationCause<'tcx>), + /// Derived obligation (i.e. `where` clause) on an user-provided impl + /// or a trait alias. ImplDerivedObligation(Box<ImplDerivedObligationCause<'tcx>>), - DerivedObligation(DerivedObligationCause<'tcx>), + /// Derived obligation for WF goals. + WellFormedDerivedObligation(DerivedObligationCause<'tcx>), FunctionArgumentObligation { /// The node of the relevant argument in the function call. @@ -487,7 +492,7 @@ pub enum WellFormedLoc { /// The index of the parameter to use. /// Parameters are indexed from 0, with the return type /// being the last 'parameter' - param_idx: u16, + param_idx: usize, }, } @@ -534,7 +539,7 @@ impl<'tcx> ObligationCauseCode<'tcx> { match self { FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)), BuiltinDerivedObligation(derived) - | DerivedObligation(derived) + | WellFormedDerivedObligation(derived) | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => { Some((&derived.parent_code, Some(derived.parent_trait_pred))) } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 11167515b7c..b66c664e6ae 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -422,49 +422,53 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>( child_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>, mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T, ) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> { - std::iter::from_coroutine(move || { - let mut child_captures = child_captures.into_iter().enumerate().peekable(); - - // One parent capture may correspond to several child captures if we end up - // refining the set of captures via edition-2021 precise captures. We want to - // match up any number of child captures with one parent capture, so we keep - // peeking off this `Peekable` until the child doesn't match anymore. - for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() { - // Make sure we use every field at least once, b/c why are we capturing something - // if it's not used in the inner coroutine. - let mut field_used_at_least_once = false; - - // A parent matches a child if they share the same prefix of projections. - // The child may have more, if it is capturing sub-fields out of - // something that is captured by-move in the parent closure. - while child_captures.peek().map_or(false, |(_, child_capture)| { - child_prefix_matches_parent_projections(parent_capture, child_capture) - }) { - let (child_field_idx, child_capture) = child_captures.next().unwrap(); - // This analysis only makes sense if the parent capture is a - // prefix of the child capture. - assert!( - child_capture.place.projections.len() >= parent_capture.place.projections.len(), - "parent capture ({parent_capture:#?}) expected to be prefix of \ + std::iter::from_coroutine( + #[cfg_attr(not(bootstrap), coroutine)] + move || { + let mut child_captures = child_captures.into_iter().enumerate().peekable(); + + // One parent capture may correspond to several child captures if we end up + // refining the set of captures via edition-2021 precise captures. We want to + // match up any number of child captures with one parent capture, so we keep + // peeking off this `Peekable` until the child doesn't match anymore. + for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() { + // Make sure we use every field at least once, b/c why are we capturing something + // if it's not used in the inner coroutine. + let mut field_used_at_least_once = false; + + // A parent matches a child if they share the same prefix of projections. + // The child may have more, if it is capturing sub-fields out of + // something that is captured by-move in the parent closure. + while child_captures.peek().map_or(false, |(_, child_capture)| { + child_prefix_matches_parent_projections(parent_capture, child_capture) + }) { + let (child_field_idx, child_capture) = child_captures.next().unwrap(); + // This analysis only makes sense if the parent capture is a + // prefix of the child capture. + assert!( + child_capture.place.projections.len() + >= parent_capture.place.projections.len(), + "parent capture ({parent_capture:#?}) expected to be prefix of \ child capture ({child_capture:#?})" - ); + ); - yield for_each( - (parent_field_idx, parent_capture), - (child_field_idx, child_capture), - ); + yield for_each( + (parent_field_idx, parent_capture), + (child_field_idx, child_capture), + ); - field_used_at_least_once = true; - } + field_used_at_least_once = true; + } - // Make sure the field was used at least once. - assert!( - field_used_at_least_once, - "we captured {parent_capture:#?} but it was not used in the child coroutine?" - ); - } - assert_eq!(child_captures.next(), None, "leftover child captures?"); - }) + // Make sure the field was used at least once. + assert!( + field_used_at_least_once, + "we captured {parent_capture:#?} but it was not used in the child coroutine?" + ); + } + assert_eq!(child_captures.next(), None, "leftover child captures?"); + }, + ) } fn child_prefix_matches_parent_projections( diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7dbe59e132d..45fa5e8f7ca 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1284,20 +1284,23 @@ impl<'tcx> TyCtxt<'tcx> { self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); let definitions = &self.untracked.definitions; - std::iter::from_coroutine(|| { - let mut i = 0; - - // Recompute the number of definitions each time, because our caller may be creating - // new ones. - while i < { definitions.read().num_definitions() } { - let local_def_index = rustc_span::def_id::DefIndex::from_usize(i); - yield LocalDefId { local_def_index }; - i += 1; - } + std::iter::from_coroutine( + #[cfg_attr(not(bootstrap), coroutine)] + || { + let mut i = 0; + + // Recompute the number of definitions each time, because our caller may be creating + // new ones. + while i < { definitions.read().num_definitions() } { + let local_def_index = rustc_span::def_id::DefIndex::from_usize(i); + yield LocalDefId { local_def_index }; + i += 1; + } - // Freeze definitions once we finish iterating on them, to prevent adding new ones. - definitions.freeze(); - }) + // Freeze definitions once we finish iterating on them, to prevent adding new ones. + definitions.freeze(); + }, + ) } pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 7c925d5fbb6..10b0909209a 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -58,30 +58,6 @@ pub enum TreatParams { /// This also treats projections with inference variables as infer vars /// since they could be further normalized. ForLookup, - /// Treat parameters as placeholders in the given environment. This is the - /// correct mode for *lookup*, as during candidate selection. - /// - /// N.B. during deep rejection, this acts identically to `ForLookup`. - /// - /// FIXME(-Znext-solver): Remove this variant and cleanup - /// the code. - NextSolverLookup, -} - -/// During fast-rejection, we have the choice of treating projection types -/// as either simplifiable or not, depending on whether we expect the projection -/// to be normalized/rigid. -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -pub enum TreatProjections { - /// In the old solver we don't try to normalize projections - /// when looking up impls and only access them by using the - /// current self type. This means that if the self type is - /// a projection which could later be normalized, we must not - /// treat it as rigid. - ForLookup, - /// We can treat projections in the self type as opaque as - /// we separately look up impls for the normalized self type. - NextSolverLookup, } /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. @@ -139,21 +115,17 @@ pub fn simplify_type<'tcx>( ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())), ty::Placeholder(..) => Some(SimplifiedType::Placeholder), ty::Param(_) => match treat_params { - TreatParams::ForLookup | TreatParams::NextSolverLookup => { - Some(SimplifiedType::Placeholder) - } + TreatParams::ForLookup => Some(SimplifiedType::Placeholder), TreatParams::AsCandidateKey => None, }, ty::Alias(..) => match treat_params { // When treating `ty::Param` as a placeholder, projections also // don't unify with anything else as long as they are fully normalized. - // - // We will have to be careful with lazy normalization here. - // FIXME(lazy_normalization): This is probably not right... + // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder` + // when the new solver is enabled by default. TreatParams::ForLookup if !ty.has_non_region_infer() => { Some(SimplifiedType::Placeholder) } - TreatParams::NextSolverLookup => Some(SimplifiedType::Placeholder), TreatParams::ForLookup | TreatParams::AsCandidateKey => None, }, ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), @@ -331,7 +303,7 @@ impl DeepRejectCtxt { // Depending on the value of `treat_obligation_params`, we either // treat generic parameters like placeholders or like inference variables. ty::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup | TreatParams::NextSolverLookup => false, + TreatParams::ForLookup => false, TreatParams::AsCandidateKey => true, }, @@ -373,7 +345,7 @@ impl DeepRejectCtxt { let k = impl_ct.kind(); match obligation_ct.kind() { ty::ConstKind::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup | TreatParams::NextSolverLookup => false, + TreatParams::ForLookup => false, TreatParams::AsCandidateKey => true, }, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cc026e349d7..094b68ce5ad 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -45,7 +45,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_errors::{Diag, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_index::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; @@ -54,7 +54,7 @@ use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{hygiene, ExpnId, ExpnKind, Span}; +use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -224,8 +224,15 @@ pub struct ResolverAstLowering { pub lint_buffer: Steal<LintBuffer>, /// Information about functions signatures for delegation items expansion - pub has_self: LocalDefIdSet, - pub fn_parameter_counts: LocalDefIdMap<usize>, + pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>, +} + +#[derive(Debug)] +pub struct DelegationFnSig { + pub header: ast::FnHeader, + pub param_count: usize, + pub has_self: bool, + pub c_variadic: bool, } #[derive(Clone, Copy, Debug)] @@ -2006,22 +2013,6 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } - /// Returns corrected span if the debuginfo for `span` should be collapsed to the outermost - /// expansion site (with collapse_debuginfo attribute if the corresponding feature enabled). - /// Only applies when `Span` is the result of macro expansion. - /// - /// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default - /// and only when a (some enclosing) macro definition is annotated with `#[collapse_debuginfo]`. - /// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default. - /// - /// When `-Zdebug-macros` is provided then debuginfo will never be collapsed. - pub fn collapsed_debuginfo(self, span: Span, upto: Span) -> Span { - if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() { - return span; - } - hygiene::walk_chain_collapsed(span, upto, self.features().collapse_debuginfo) - } - #[inline] pub fn is_const_fn_raw(self, def_id: DefId) -> bool { matches!( diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index d85b541d363..e06e3465eb2 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,5 +1,5 @@ use crate::traits::specialization_graph; -use crate::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; +use crate::ty::fast_reject::{self, SimplifiedType, TreatParams}; use crate::ty::{Ident, Ty, TyCtxt}; use hir::def_id::LOCAL_CRATE; use rustc_hir as hir; @@ -135,21 +135,6 @@ impl<'tcx> TyCtxt<'tcx> { self, trait_def_id: DefId, self_ty: Ty<'tcx>, - f: impl FnMut(DefId), - ) { - self.for_each_relevant_impl_treating_projections( - trait_def_id, - self_ty, - TreatProjections::ForLookup, - f, - ) - } - - pub fn for_each_relevant_impl_treating_projections( - self, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - treat_projections: TreatProjections, mut f: impl FnMut(DefId), ) { // FIXME: This depends on the set of all impls for the trait. That is @@ -163,17 +148,13 @@ impl<'tcx> TyCtxt<'tcx> { f(impl_def_id); } - // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using - // `TreatParams::AsCandidateKey` while actually adding them. - let treat_params = match treat_projections { - TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup, - TreatProjections::ForLookup => TreatParams::ForLookup, - }; // This way, when searching for some impl for `T: Trait`, we do not look at any impls // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on. - if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) { + // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using + // `TreatParams::AsCandidateKey` while actually adding them. + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { f(impl_def_id); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b308a80f7ba..e42755ca7bf 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -4,7 +4,7 @@ #![feature(cow_is_borrowed)] #![feature(decl_macro)] #![feature(impl_trait_in_assoc_type)] -#![feature(inline_const)] +#![cfg_attr(bootstrap, feature(inline_const))] #![feature(is_sorted)] #![feature(let_chains)] #![feature(map_try_insert)] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 84ecd0a0de5..ed51710564a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -686,6 +686,8 @@ impl<'a> Parser<'a> { (None, self.parse_path(PathStyle::Expr)?) }; + let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None }; + let body = if self.check(&token::OpenDelim(Delimiter::Brace)) { Some(self.parse_block()?) } else { @@ -695,11 +697,9 @@ impl<'a> Parser<'a> { let span = span.to(self.prev_token.span); self.psess.gated_spans.gate(sym::fn_delegation, span); - let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty()); - Ok(( - ident, - ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })), - )) + let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); + let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body }; + Ok((ident, ItemKind::Delegation(Box::new(deleg)))) } fn parse_item_list<T>( diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 742f4bd3c83..7486da33b21 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1252,8 +1252,6 @@ impl<'a> Parser<'a> { fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P<Expr>> { if pat { self.psess.gated_spans.gate(sym::inline_const_pat, span); - } else { - self.psess.gated_spans.gate(sym::inline_const, span); } self.eat_keyword(kw::Const); let (attrs, blk) = self.parse_inner_attrs_and_block()?; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c877ae5e21f..292af43b602 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,6 +21,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; +use rustc_middle::ty::DelegationFnSig; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; @@ -4749,12 +4750,13 @@ struct ItemInfoCollector<'a, 'b, 'tcx> { impl ItemInfoCollector<'_, '_, '_> { fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) { - let def_id = self.r.local_def_id(id); - self.r.fn_parameter_counts.insert(def_id, sig.decl.inputs.len()); - - if sig.decl.has_self() { - self.r.has_self.insert(def_id); - } + let sig = DelegationFnSig { + header: sig.header, + param_count: sig.decl.inputs.len(), + has_self: sig.decl.has_self(), + c_variadic: sig.decl.c_variadic(), + }; + self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig); } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d79c638fa07..64451030adf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2039,7 +2039,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called }, ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType, ast::AssocItemKind::Delegation(..) - if self.r.has_self.contains(&self.r.local_def_id(assoc_item.id)) => + if self.r.delegation_fn_sigs[&self.r.local_def_id(assoc_item.id)] + .has_self => { AssocSuggestion::MethodWithSelf { called } } @@ -2062,7 +2063,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if filter_fn(res) { let def_id = res.def_id(); let has_self = match def_id.as_local() { - Some(def_id) => self.r.has_self.contains(&def_id), + Some(def_id) => { + self.r.delegation_fn_sigs.get(&def_id).map_or(false, |sig| sig.has_self) + } None => self .r .tcx diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b5b6d899cc5..e07c3247d07 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -43,7 +43,7 @@ use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::NonMacroAttrKind; use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalDefIdSet}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{PrimTy, TraitCandidate}; use rustc_index::IndexVec; @@ -52,8 +52,8 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt, TyCtxtFeed}; -use rustc_middle::ty::{Feed, ResolverGlobalCtxt, ResolverOutputs}; +use rustc_middle::ty::{self, DelegationFnSig, Feed, MainDefinition, RegisteredTools}; +use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed}; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::LintBuffer; @@ -992,7 +992,6 @@ pub struct Resolver<'a, 'tcx> { extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'a>>, /// N.B., this is used only for better diagnostics, not name resolution itself. - has_self: LocalDefIdSet, field_def_ids: LocalDefIdMap<&'tcx [DefId]>, /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. @@ -1149,8 +1148,7 @@ pub struct Resolver<'a, 'tcx> { legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>, /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>, - /// Amount of parameters for each function in the crate. - fn_parameter_counts: LocalDefIdMap<usize>, + delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>, main_def: Option<MainDefinition>, trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>, @@ -1399,7 +1397,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { prelude: None, extern_prelude, - has_self: Default::default(), field_def_ids: Default::default(), field_visibility_spans: FxHashMap::default(), @@ -1508,7 +1505,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { doc_link_resolutions: Default::default(), doc_link_traits_in_scope: Default::default(), all_macro_rules: Default::default(), - fn_parameter_counts: Default::default(), + delegation_fn_sigs: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1621,8 +1618,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), - has_self: self.has_self, - fn_parameter_counts: self.fn_parameter_counts, + delegation_fn_sigs: self.delegation_fn_sigs, }; ResolverOutputs { global_ctxt, ast_lowering } } diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 3e1d8f3828b..19f4e6994ac 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -11,7 +11,7 @@ #![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(const_option)] #![feature(core_intrinsics)] -#![feature(inline_const)] +#![cfg_attr(bootstrap, feature(inline_const))] #![feature(min_specialization)] #![feature(never_type)] #![feature(ptr_sub_ptr)] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 07c11663173..4f259960ac3 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1888,9 +1888,12 @@ fn collect_print_requests( let prints = PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>(); let prints = prints.join(", "); - early_dcx.early_fatal(format!( - "unknown print request `{req}`. Valid print requests are: {prints}" - )); + + let mut diag = + early_dcx.early_struct_fatal(format!("unknown print request: `{req}`")); + #[allow(rustc::diagnostic_outside_of_impl)] + diag.help(format!("valid print requests are: {prints}")); + diag.emit() } }; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index d5108058948..e1474ee365b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1,5 +1,4 @@ use crate::config::*; - use crate::search_paths::SearchPath; use crate::utils::NativeLib; use crate::{lint, EarlyDiagCtxt}; @@ -8,20 +7,17 @@ use rustc_data_structures::profiling::TimePassesFormat; use rustc_data_structures::stable_hasher::Hash64; use rustc_errors::ColorConfig; use rustc_errors::{LanguageIdentifier, TerminalUrl}; +use rustc_feature::UnstableFeatures; +use rustc_span::edition::Edition; +use rustc_span::RealFileName; +use rustc_span::SourceFileHashAlgorithm; use rustc_target::spec::{ CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet, WasmCAbi, }; use rustc_target::spec::{ RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, }; - -use rustc_feature::UnstableFeatures; -use rustc_span::edition::Edition; -use rustc_span::RealFileName; -use rustc_span::SourceFileHashAlgorithm; - use std::collections::BTreeMap; - use std::hash::{DefaultHasher, Hasher}; use std::num::{IntErrorKind, NonZero}; use std::path::PathBuf; @@ -118,8 +114,8 @@ top_level_options!( /// incremental compilation cache before proceeding. /// /// - `[TRACKED_NO_CRATE_HASH]` - /// Same as `[TRACKED]`, but will not affect the crate hash. This is useful for options that only - /// affect the incremental cache. + /// Same as `[TRACKED]`, but will not affect the crate hash. This is useful for options that + /// only affect the incremental cache. /// /// - `[UNTRACKED]` /// Incremental compilation is not influenced by this option. @@ -1362,10 +1358,20 @@ mod parse { slot: &mut CollapseMacroDebuginfo, v: Option<&str>, ) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + CollapseMacroDebuginfo::Yes + } else { + CollapseMacroDebuginfo::No + }; + return true; + } + } + *slot = match v { - Some("no") => CollapseMacroDebuginfo::No, Some("external") => CollapseMacroDebuginfo::External, - Some("yes") => CollapseMacroDebuginfo::Yes, _ => return false, }; true @@ -1464,6 +1470,9 @@ options! { "choose the code model to use (`rustc --print code-models` for details)"), codegen_units: Option<usize> = (None, parse_opt_number, [UNTRACKED], "divide crate into N units to optimize in parallel"), + collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified, + parse_collapse_macro_debuginfo, [TRACKED], + "set option to collapse debuginfo for macros"), control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED], "use Windows Control Flow Guard (default: no)"), debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED], @@ -1611,9 +1620,6 @@ options! { "show all expected values in check-cfg diagnostics (default: no)"), codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED], "the backend to use"), - collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified, - parse_collapse_macro_debuginfo, [TRACKED], - "set option to collapse debuginfo for macros"), combine_cgu: bool = (false, parse_bool, [TRACKED], "combine CGUs into a single one"), coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED], @@ -1624,8 +1630,6 @@ options! { "threshold to allow cross crate inlining of functions"), debug_info_for_profiling: bool = (false, parse_bool, [TRACKED], "emit discriminators and other data necessary for AutoFDO"), - debug_macros: bool = (false, parse_bool, [TRACKED], - "emit line numbers debug info inside macros (default: no)"), debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED], "compress debug info sections (none, zlib, zstd, default: none)"), deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 1df2b357ac1..6093df94179 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -459,28 +459,21 @@ impl HygieneData { span } - // We need to walk up and update return span if we meet macro instantiation to be collapsed - fn walk_chain_collapsed( - &self, - mut span: Span, - to: Span, - collapse_debuginfo_feature_enabled: bool, - ) -> Span { + fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span { let orig_span = span; let mut ret_span = span; - - debug!( - "walk_chain_collapsed({:?}, {:?}), feature_enable={}", - span, to, collapse_debuginfo_feature_enabled, - ); + debug!("walk_chain_collapsed({:?}, {:?})", span, to); debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt()); - while !span.eq_ctxt(to) && span.from_expansion() { - let outer_expn = self.outer_expn(span.ctxt()); + while let ctxt = span.ctxt() + && !ctxt.is_root() + && ctxt != to.ctxt() + { + let outer_expn = self.outer_expn(ctxt); debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn); let expn_data = self.expn_data(outer_expn); debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data); span = expn_data.call_site; - if !collapse_debuginfo_feature_enabled || expn_data.collapse_debuginfo { + if expn_data.collapse_debuginfo { ret_span = span; } } @@ -604,14 +597,13 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { HygieneData::with(|data| data.walk_chain(span, to)) } -pub fn walk_chain_collapsed( - span: Span, - to: Span, - collapse_debuginfo_feature_enabled: bool, -) -> Span { - HygieneData::with(|hdata| { - hdata.walk_chain_collapsed(span, to, collapse_debuginfo_feature_enabled) - }) +/// In order to have good line stepping behavior in debugger, for the given span we return its +/// outermost macro call site that still has a `#[collapse_debuginfo(yes)]` property on it. +/// We also stop walking call sites at the function body level because no line stepping can occur +/// at the level above that. +/// The returned span can then be used in emitted debuginfo. +pub fn walk_chain_collapsed(span: Span, to: Span) -> Span { + HygieneData::with(|data| data.walk_chain_collapsed(span, to)) } pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) { @@ -1251,7 +1243,7 @@ struct HygieneDecodeContextInner { // global `HygieneData`. When we deserialize a `SyntaxContext`, we need to create // a new id in the global `HygieneData`. This map tracks the ID we end up picking, // so that multiple occurrences of the same serialized id are decoded to the same - // `SyntaxContext`. This only stores `SyntaxContext`s which are completly decoded. + // `SyntaxContext`. This only stores `SyntaxContext`s which are completely decoded. remapped_ctxts: Vec<Option<SyntaxContext>>, /// Maps serialized `SyntaxContext` ids that are currently being decoded to a `SyntaxContext`. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8abf42e2c13..99591b5e144 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -192,6 +192,7 @@ symbols! { Duration, Encodable, Encoder, + Enumerate, Eq, Equal, Err, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index ed76ea74f08..f6d12a9a013 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -14,7 +14,7 @@ use rustc_middle::traits::solve::{ CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult, }; use rustc_middle::traits::{BuiltinImplSource, Reveal}; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; @@ -1045,6 +1045,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + // If we still have an alias here, it must be rigid. For opaques, it's always + // okay to consider auto traits because that'll reveal its hidden type. For + // non-opaque aliases, we will not assemble any candidates since there's no way + // to further look into its type. + ty::Alias(..) => None, + // For rigid types, any possible implementation that could apply to // the type (even if after unification and processing nested goals // it does not hold) will disqualify the built-in auto impl. @@ -1072,15 +1078,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) - | ty::Adt(_, _) - // FIXME: Handling opaques here is kinda sus. Especially because we - // simplify them to SimplifiedType::Placeholder. - | ty::Alias(ty::Opaque, _) => { + | ty::Adt(_, _) => { let mut disqualifying_impl = None; - self.tcx().for_each_relevant_impl_treating_projections( + self.tcx().for_each_relevant_impl( goal.predicate.def_id(), goal.predicate.self_ty(), - TreatProjections::NextSolverLookup, |impl_def_id| { disqualifying_impl = Some(impl_def_id); }, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 837b784f272..e50edfdc656 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -50,22 +50,38 @@ pub struct FindExprBySpan<'hir> { pub span: Span, pub result: Option<&'hir hir::Expr<'hir>>, pub ty_result: Option<&'hir hir::Ty<'hir>>, + pub include_closures: bool, + pub tcx: TyCtxt<'hir>, } impl<'hir> FindExprBySpan<'hir> { - pub fn new(span: Span) -> Self { - Self { span, result: None, ty_result: None } + pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self { + Self { span, result: None, ty_result: None, tcx, include_closures: false } } } impl<'v> Visitor<'v> for FindExprBySpan<'v> { + type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { if self.span == ex.span { self.result = Some(ex); } else { + if let hir::ExprKind::Closure(..) = ex.kind + && self.include_closures + && let closure_header_sp = self.span.with_hi(ex.span.hi()) + && closure_header_sp == ex.span + { + self.result = Some(ex); + } hir::intravisit::walk_expr(self, ex); } } + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { if self.span == ty.span { self.ty_result = Some(ty); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 5fccc769785..b418219fb95 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -128,7 +128,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match obligation.cause.code() { ObligationCauseCode::BuiltinDerivedObligation(..) | ObligationCauseCode::ImplDerivedObligation(..) - | ObligationCauseCode::DerivedObligation(..) => {} + | ObligationCauseCode::WellFormedDerivedObligation(..) => {} _ => { // this is a "direct", user-specified, rather than derived, // obligation. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9d3caaa01ab..d24942f3f46 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -901,7 +901,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Remove all the desugaring and macro contexts. span.remove_mark(); } - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan::new(span, self.tcx); let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return; }; @@ -1367,7 +1367,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return false; }; let body = self.tcx.hir().body(body_id); - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(body.value); let Some(expr) = expr_finder.result else { return false; @@ -1469,7 +1469,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Remove all the hir desugaring contexts while maintaining the macro contexts. span.remove_mark(); } - let mut expr_finder = super::FindExprBySpan::new(span); + let mut expr_finder = super::FindExprBySpan::new(span, self.tcx); let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; @@ -2294,7 +2294,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { next_code = Some(&cause.derived.parent_code); } - ObligationCauseCode::DerivedObligation(derived_obligation) + ObligationCauseCode::WellFormedDerivedObligation(derived_obligation) | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => { let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty(); debug!( @@ -3423,7 +3423,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) }); } - ObligationCauseCode::DerivedObligation(ref data) => { + ObligationCauseCode::WellFormedDerivedObligation(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let parent_predicate = parent_trait_ref; // #74711: avoid a stack overflow diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 0e309689680..1971136e54c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2457,7 +2457,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(self.tcx.hir().body(body_id).value); if let Some(hir::Expr { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index f1c24b6adc1..28ee76f7145 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -381,7 +381,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() { cause = cause.derived_cause( parent_trait_pred, - traits::ObligationCauseCode::DerivedObligation, + traits::ObligationCauseCode::WellFormedDerivedObligation, ); } extend_cause_with_original_assoc_item_obligation(tcx, item, &mut cause, predicate); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index c1661fa63a8..d0aa4eb2e71 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -101,18 +101,11 @@ fn resolve_associated_item<'tcx>( let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) { Ok(vtbl) => vtbl, - Err(CodegenObligationError::Ambiguity) => { - let reported = tcx.dcx().span_delayed_bug( - tcx.def_span(trait_item_id), - format!( - "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \ - overflow or prior type error", - ), - ); - return Err(reported); - } - Err(CodegenObligationError::Unimplemented) => return Ok(None), - Err(CodegenObligationError::FulfillmentError) => return Ok(None), + Err( + CodegenObligationError::Ambiguity + | CodegenObligationError::Unimplemented + | CodegenObligationError::FulfillmentError, + ) => return Ok(None), }; // Now that we know which impl is being used, we can dispatch to diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 397e104512f..3924b371bbc 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -183,7 +183,7 @@ pub enum TyKind<I: Interner> { /// /// ``` /// #![feature(coroutines)] - /// static |a| { + /// #[coroutine] static |a| { /// let x = &vec![3]; /// yield a; /// yield x[0]; @@ -227,7 +227,7 @@ pub enum TyKind<I: Interner> { /// A placeholder type, used during higher ranked subtyping to instantiate /// bound variables. /// - /// It is conventional to render anonymous placeholer types like `!N` or `!U_N`, + /// It is conventional to render anonymous placeholder types like `!N` or `!U_N`, /// where `N` is the placeholder variable's anonymous index (which corresponds /// to the bound variable's index from the binder from which it was instantiated), /// and `U` is the universe index in which it is instantiated, or totally omitted diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index c54f0062824..846b9a1404d 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -31,7 +31,7 @@ //! // instead of a max-heap. //! impl Ord for State { //! fn cmp(&self, other: &Self) -> Ordering { -//! // Notice that the we flip the ordering on costs. +//! // Notice that we flip the ordering on costs. //! // In case of a tie we compare positions - this step is necessary //! // to make implementations of `PartialEq` and `Ord` consistent. //! other.cost.cmp(&self.cost) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 88faf5a9c7d..b417513aaa2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -128,7 +128,6 @@ #![feature(fn_traits)] #![feature(hasher_prefixfree_extras)] #![feature(hint_assert_unchecked)] -#![feature(inline_const)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] @@ -169,6 +168,7 @@ // Language features: // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(associated_type_bounds))] +#![cfg_attr(bootstrap, feature(inline_const))] #![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)] #![cfg_attr(not(test), feature(coroutine_trait))] #![cfg_attr(test, feature(panic_update_hook))] diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 5e4dac8f49b..92626feabf3 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -153,7 +153,7 @@ impl<'a> Argument<'a> { /// /// # Safety /// - /// This argument must actually be a placeholer argument. + /// This argument must actually be a placeholder argument. /// // FIXME: Transmuting formatter in new and indirectly branching to/calling // it here is an explicit CFI violation. diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index ef46040f0a7..7adbabf69e4 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -15,6 +15,7 @@ use crate::ops::Try; #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Enumerate")] pub struct Enumerate<I> { iter: I, count: usize, diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 616dd0afc51..a5cf069d407 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -515,9 +515,7 @@ macro_rules! spec_int_ranges_r { unsafe impl StepByBackImpl<Range<$t>> for StepBy<Range<$t>> { #[inline] - fn spec_next_back(&mut self) -> Option<Self::Item> - where Range<$t>: DoubleEndedIterator + ExactSizeIterator, - { + fn spec_next_back(&mut self) -> Option<Self::Item> { let step = self.original_step().get() as $t; let remaining = self.iter.end; if remaining > 0 { @@ -533,9 +531,7 @@ macro_rules! spec_int_ranges_r { // We have to repeat them here so that the specialization overrides the StepByImplBack defaults #[inline] - fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> - where Self: DoubleEndedIterator, - { + fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> { if self.advance_back_by(n).is_err() { return None; } @@ -544,10 +540,9 @@ macro_rules! spec_int_ranges_r { #[inline] fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R - where - Self: DoubleEndedIterator, - F: FnMut(Acc, Self::Item) -> R, - R: Try<Output = Acc> + where + F: FnMut(Acc, Self::Item) -> R, + R: Try<Output = Acc> { let mut accum = init; while let Some(x) = self.next_back() { @@ -558,9 +553,8 @@ macro_rules! spec_int_ranges_r { #[inline] fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc - where - Self: DoubleEndedIterator, - F: FnMut(Acc, Self::Item) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc { let mut accum = init; while let Some(x) = self.next_back() { diff --git a/library/core/src/iter/sources/from_coroutine.rs b/library/core/src/iter/sources/from_coroutine.rs index bf413b24d41..9bac9037a02 100644 --- a/library/core/src/iter/sources/from_coroutine.rs +++ b/library/core/src/iter/sources/from_coroutine.rs @@ -14,7 +14,7 @@ use crate::pin::Pin; /// #![feature(coroutines)] /// #![feature(iter_from_coroutine)] /// -/// let it = std::iter::from_coroutine(|| { +/// let it = std::iter::from_coroutine(#[cfg_attr(not(bootstrap), coroutine)] || { /// yield 1; /// yield 2; /// yield 3; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 154565b6fee..6925a7d1da1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -201,6 +201,7 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(inline_const))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] @@ -231,7 +232,6 @@ #![feature(fundamental)] #![feature(generic_arg_infer)] #![feature(if_let_guard)] -#![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index 6e067f95da9..5250be15fe4 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -40,12 +40,13 @@ pub enum CoroutineState<Y, R> { /// ```rust /// #![feature(coroutines)] /// #![feature(coroutine_trait)] +/// #![feature(stmt_expr_attributes)] /// /// use std::ops::{Coroutine, CoroutineState}; /// use std::pin::Pin; /// /// fn main() { -/// let mut coroutine = || { +/// let mut coroutine = #[cfg_attr(not(bootstrap), coroutine)] || { /// yield 1; /// "foo" /// }; diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index efd525aeb3b..a11c6c742d7 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1809,7 +1809,7 @@ impl<Ptr, U> DispatchFromDyn<Pin<U>> for Pin<Ptr> where Ptr: DispatchFromDyn<U> /// fn coroutine_fn() -> impl Coroutine<Yield = usize, Return = ()> /* not Unpin */ { /// // Allow coroutine to be self-referential (not `Unpin`) /// // vvvvvv so that locals can cross yield points. -/// static || { +/// #[cfg_attr(not(bootstrap), coroutine)] static || { /// let foo = String::from("foo"); /// let foo_ref = &foo; // ------+ /// yield 0; // | <- crosses yield point! diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index c8fd997a5da..073459fcb00 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -511,7 +511,8 @@ impl AtomicBool { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const)] + /// #![feature(atomic_from_mut)] + /// # #![cfg_attr(bootstrap, feature(inline_const))] /// use std::sync::atomic::{AtomicBool, Ordering}; /// /// let mut some_bools = [const { AtomicBool::new(false) }; 10]; @@ -1313,7 +1314,8 @@ impl<T> AtomicPtr<T> { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const)] + /// #![feature(atomic_from_mut)] + /// # #![cfg_attr(bootstrap, feature(inline_const))] /// use std::ptr::null_mut; /// use std::sync::atomic::{AtomicPtr, Ordering}; /// @@ -2303,7 +2305,8 @@ macro_rules! atomic_int { /// # Examples /// /// ``` - /// #![feature(atomic_from_mut, inline_const)] + /// #![feature(atomic_from_mut)] + /// # #![cfg_attr(bootstrap, feature(inline_const))] #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] /// #[doc = concat!("let mut some_ints = [const { ", stringify!($atomic_type), "::new(0) }; 10];")] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 7bd962fa260..d6e705a37a7 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -46,7 +46,7 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(try_find)] -#![feature(inline_const)] +#![cfg_attr(bootstrap, feature(inline_const))] #![feature(is_sorted)] #![feature(layout_for_ptr)] #![feature(pattern)] diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs index 48514e52587..331b6626249 100644 --- a/library/portable-simd/crates/core_simd/src/lib.rs +++ b/library/portable-simd/crates/core_simd/src/lib.rs @@ -7,7 +7,6 @@ convert_float_to_int, core_intrinsics, decl_macro, - inline_const, intra_doc_pointers, repr_simd, simd_ffi, diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 21ae7b91207..801621c6112 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -869,8 +869,6 @@ impl Error { /// # Examples /// /// ``` - /// #![feature(io_error_downcast)] - /// /// use std::fmt; /// use std::io; /// use std::error::Error; @@ -923,7 +921,7 @@ impl Error { /// assert!(io_error.raw_os_error().is_none()); /// # } /// ``` - #[unstable(feature = "io_error_downcast", issue = "99262")] + #[stable(feature = "io_error_downcast", since = "CURRENT_RUSTC_VERSION")] pub fn downcast<E>(self) -> result::Result<E, Self> where E: error::Error + Send + Sync + 'static, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 0636f55771e..1c58671a0cf 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3332,7 +3332,6 @@ impl Error for StripPrefixError { /// ## Posix paths /// /// ``` -/// #![feature(absolute_path)] /// # #[cfg(unix)] /// fn main() -> std::io::Result<()> { /// use std::path::{self, Path}; @@ -3357,7 +3356,6 @@ impl Error for StripPrefixError { /// ## Windows paths /// /// ``` -/// #![feature(absolute_path)] /// # #[cfg(windows)] /// fn main() -> std::io::Result<()> { /// use std::path::{self, Path}; @@ -3382,7 +3380,7 @@ impl Error for StripPrefixError { /// /// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 /// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew -#[unstable(feature = "absolute_path", issue = "92750")] +#[stable(feature = "absolute_path", since = "CURRENT_RUSTC_VERSION")] pub fn absolute<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { let path = path.as_ref(); if path.as_os_str().is_empty() { diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index b49585599cb..ff41f6e77be 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -201,14 +201,21 @@ pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> { // currently reside in the buffer. This function is an abstraction over these // functions by making them easier to call. // -// The first callback, `f1`, is yielded a (pointer, len) pair which can be +// The first callback, `f1`, is passed a (pointer, len) pair which can be // passed to a syscall. The `ptr` is valid for `len` items (u16 in this case). -// The closure is expected to return what the syscall returns which will be -// interpreted by this function to determine if the syscall needs to be invoked -// again (with more buffer space). +// The closure is expected to: +// - On success, return the actual length of the written data *without* the null terminator. +// This can be 0. In this case the last_error must be left unchanged. +// - On insufficient buffer space, +// - either return the required length *with* the null terminator, +// - or set the last-error to ERROR_INSUFFICIENT_BUFFER and return `len`. +// - On other failure, return 0 and set last_error. +// +// This is how most but not all syscalls indicate the required buffer space. +// Other syscalls may need translation to match this protocol. // // Once the syscall has completed (errors bail out early) the second closure is -// yielded the data which has been read from the syscall. The return value +// passed the data which has been read from the syscall. The return value // from this closure is then the return value of the function. pub fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T> where diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 374c9845ea4..64d8b72aed2 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -326,6 +326,8 @@ fn home_dir_crt() -> Option<PathBuf> { super::fill_utf16_buf( |buf, mut sz| { + // GetUserProfileDirectoryW does not quite use the usual protocol for + // negotiating the buffer size, so we have to translate. match c::GetUserProfileDirectoryW( ptr::without_provenance_mut(CURRENT_PROCESS_TOKEN), buf, diff --git a/library/std/src/sys/pal/windows/thread_local_key.rs b/library/std/src/sys/pal/windows/thread_local_key.rs index 4c00860dae3..e5ba619fc6b 100644 --- a/library/std/src/sys/pal/windows/thread_local_key.rs +++ b/library/std/src/sys/pal/windows/thread_local_key.rs @@ -141,9 +141,15 @@ impl StaticKey { panic!("out of TLS indexes"); } - self.key.store(key + 1, Release); register_dtor(self); + // Release-storing the key needs to be the last thing we do. + // This is because in `fn key()`, other threads will do an acquire load of the key, + // and if that sees this write then it will entirely bypass the `InitOnce`. We thus + // need to establish synchronization through `key`. In particular that acquire load + // must happen-after the register_dtor above, to ensure the dtor actually runs! + self.key.store(key + 1, Release); + let r = c::InitOnceComplete(self.once.get(), 0, ptr::null_mut()); debug_assert_eq!(r, c::TRUE); @@ -313,8 +319,22 @@ unsafe fn run_dtors() { // Use acquire ordering to observe key initialization. let mut cur = DTORS.load(Acquire); while !cur.is_null() { - let key = (*cur).key.load(Relaxed) - 1; + let pre_key = (*cur).key.load(Acquire); let dtor = (*cur).dtor.unwrap(); + cur = (*cur).next.load(Relaxed); + + // In StaticKey::init, we register the dtor before setting `key`. + // So if one thread's `run_dtors` races with another thread executing `init` on the same + // `StaticKey`, we can encounter a key of 0 here. That means this key was never + // initialized in this thread so we can safely skip it. + if pre_key == 0 { + continue; + } + // If this is non-zero, then via the `Acquire` load above we synchronized with + // everything relevant for this key. (It's not clear that this is needed, since the + // release-acquire pair on DTORS also establishes synchronization, but better safe than + // sorry.) + let key = pre_key - 1; let ptr = c::TlsGetValue(key); if !ptr.is_null() { @@ -322,8 +342,6 @@ unsafe fn run_dtors() { dtor(ptr as *mut _); any_run = true; } - - cur = (*cur).next.load(Relaxed); } if !any_run { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c20653b5dfa..1d46a158f9e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -43,7 +43,7 @@ pub struct Std { /// This shouldn't be used from other steps; see the comment on [`Rustc`]. crates: Vec<String>, /// When using download-rustc, we need to use a new build of `std` for running unit tests of Std itself, - /// but we need to use the downloaded copy of std for linking to rustdoc. Allow this to be overriden by `builder.ensure` from other steps. + /// but we need to use the downloaded copy of std for linking to rustdoc. Allow this to be overridden by `builder.ensure` from other steps. force_recompile: bool, extra_rust_args: &'static [&'static str], is_for_mir_opt_tests: bool, diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh index d6de992913b..9cc508fe928 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh @@ -5,7 +5,7 @@ set -euf -o pipefail -INTEGRATION_SHA=56310bca298872ffb5ea02e665956d9b6dc41171 +INTEGRATION_SHA=1011e3298775ee7cdf6f6dc73e808d6a86e33bd6 PICK_REFS=() checkout=fuchsia diff --git a/src/ci/docker/scripts/build-fuchsia-toolchain.sh b/src/ci/docker/scripts/build-fuchsia-toolchain.sh index beea2f522fd..7a0d4fcffc1 100755 --- a/src/ci/docker/scripts/build-fuchsia-toolchain.sh +++ b/src/ci/docker/scripts/build-fuchsia-toolchain.sh @@ -4,13 +4,13 @@ set -ex source shared.sh FUCHSIA_SDK_URL=https://chrome-infra-packages.appspot.com/dl/fuchsia/sdk/core/linux-amd64 -FUCHSIA_SDK_ID=MrhQwtmP8CpZre-i_PNOREcThbUcrX3bA-45d6WQr-cC -FUCHSIA_SDK_SHA256=32b850c2d98ff02a59adefa2fcf34e44471385b51cad7ddb03ee3977a590afe7 +FUCHSIA_SDK_ID=version:20.20240412.3.1 +FUCHSIA_SDK_SHA256=cc52f3497487dd813c89d9316e6967efcea89c7759edccf3e40fcf3662e53f19 FUCHSIA_SDK_USR_DIR=/usr/local/core-linux-amd64-fuchsia-sdk CLANG_DOWNLOAD_URL=\ https://chrome-infra-packages.appspot.com/dl/fuchsia/third_party/clang/linux-amd64 -CLANG_DOWNLOAD_ID=Tpc85d1ZwSlZ6UKl2d96GRUBGNA5JKholOKe24sRDr0C -CLANG_DOWNLOAD_SHA256=4e973ce5dd59c12959e942a5d9df7a19150118d03924a86894e29edb8b110ebd +CLANG_DOWNLOAD_ID=git_revision:c777c011a709dffd4fa5e79cad7947b7c3405d02 +CLANG_DOWNLOAD_SHA256=779167422ad73c292f049dcea5569f84577af9292189ed2749518b966a4d0844 install_clang() { mkdir -p clang_download diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 437b51641fc..8ac00a8863f 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -280,7 +280,7 @@ class TestEnvironment: # Look up the product bundle transfer manifest. self.log_info("Looking up the product bundle transfer manifest...") product_name = "minimal." + self.triple_to_arch(self.target) - fuchsia_version = "14.20230811.2.1" + fuchsia_version = "20.20240412.3.1" # FIXME: We should be able to replace this with the machine parsable # `ffx --machine json product lookup ...` once F15 is released. diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/calculate-job-matrix.py new file mode 100755 index 00000000000..124c22bd979 --- /dev/null +++ b/src/ci/github-actions/calculate-job-matrix.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 + +""" +This script serves for generating a matrix of jobs that should +be executed on CI. + +It reads job definitions from `src/ci/github-actions/jobs.yml` +and filters them based on the event that happened on CI. +""" +import dataclasses +import enum +import json +import logging +import os +from pathlib import Path +from typing import List, Dict, Any, Optional + +import yaml + +CI_DIR = Path(__file__).absolute().parent.parent +JOBS_YAML_PATH = Path(__file__).absolute().parent / "jobs.yml" + +Job = Dict[str, Any] + + +def name_jobs(jobs: List[Dict], prefix: str) -> List[Job]: + """ + Add a `name` attribute to each job, based on its image and the given `prefix`. + """ + for job in jobs: + job["name"] = f"{prefix} - {job['image']}" + return jobs + + +def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]: + """ + Prepends `environment` to the `env` attribute of each job. + The `env` of each job has higher precedence than `environment`. + """ + for job in jobs: + env = environment.copy() + env.update(job.get("env", {})) + job["env"] = env + return jobs + + +class JobType(enum.Enum): + PR = enum.auto() + Try = enum.auto() + Auto = enum.auto() + + +@dataclasses.dataclass +class GitHubCtx: + event_name: str + ref: str + repository: str + + +def find_job_type(ctx: GitHubCtx) -> Optional[JobType]: + if ctx.event_name == "pull_request": + return JobType.PR + elif ctx.event_name == "push": + old_bors_try_build = ( + ctx.ref in ("refs/heads/try", "refs/heads/try-perf") and + ctx.repository == "rust-lang-ci/rust" + ) + new_bors_try_build = ( + ctx.ref == "refs/heads/automation/bors/try" and + ctx.repository == "rust-lang/rust" + ) + try_build = old_bors_try_build or new_bors_try_build + + if try_build: + return JobType.Try + + if ctx.ref == "refs/heads/auto" and ctx.repository == "rust-lang-ci/rust": + return JobType.Auto + + return None + + +def calculate_jobs(job_type: JobType, job_data: Dict[str, Any]) -> List[Job]: + if job_type == JobType.PR: + return add_base_env(name_jobs(job_data["pr"], "PR"), job_data["envs"]["pr"]) + elif job_type == JobType.Try: + return add_base_env(name_jobs(job_data["try"], "try"), job_data["envs"]["try"]) + elif job_type == JobType.Auto: + return add_base_env(name_jobs(job_data["auto"], "auto"), job_data["envs"]["auto"]) + + return [] + + +def skip_jobs(jobs: List[Dict[str, Any]], channel: str) -> List[Job]: + """ + Skip CI jobs that are not supposed to be executed on the given `channel`. + """ + return [j for j in jobs if j.get("only_on_channel", channel) == channel] + + +def get_github_ctx() -> GitHubCtx: + return GitHubCtx( + event_name=os.environ["GITHUB_EVENT_NAME"], + ref=os.environ["GITHUB_REF"], + repository=os.environ["GITHUB_REPOSITORY"] + ) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + + with open(JOBS_YAML_PATH) as f: + data = yaml.safe_load(f) + + github_ctx = get_github_ctx() + + job_type = find_job_type(github_ctx) + logging.info(f"Job type: {job_type}") + + with open(CI_DIR / "channel") as f: + channel = f.read().strip() + + jobs = [] + if job_type is not None: + jobs = calculate_jobs(job_type, data) + jobs = skip_jobs(jobs, channel) + + logging.info(f"Output:\n{yaml.dump(jobs, indent=4)}") + print(f"jobs={json.dumps(jobs)}") diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index de71b9f874f..bc4b1b815cf 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -107,9 +107,6 @@ x--expand-yaml-anchors--remove: - &job-aarch64-linux os: [self-hosted, ARM64, linux] - - &step - if: success() && !env.SKIP_JOB - - &base-ci-job defaults: run: @@ -151,7 +148,7 @@ x--expand-yaml-anchors--remove: run: echo "[CI_PR_NUMBER=$num]" env: num: ${{ github.event.number }} - if: success() && !env.SKIP_JOB && github.event_name == 'pull_request' + if: success() && github.event_name == 'pull_request' - name: add extra environment variables run: src/ci/scripts/setup-environment.sh @@ -161,71 +158,51 @@ x--expand-yaml-anchors--remove: # are passed to the `setup-environment.sh` script encoded in JSON, # which then uses log commands to actually set them. EXTRA_VARIABLES: ${{ toJson(matrix.env) }} - <<: *step - - - name: decide whether to skip this job - run: src/ci/scripts/should-skip-this.sh - <<: *step - name: ensure the channel matches the target branch run: src/ci/scripts/verify-channel.sh - <<: *step - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh - <<: *step - name: show the current environment run: src/ci/scripts/dump-environment.sh - <<: *step - name: install awscli run: src/ci/scripts/install-awscli.sh - <<: *step - name: install sccache run: src/ci/scripts/install-sccache.sh - <<: *step - name: select Xcode run: src/ci/scripts/select-xcode.sh - <<: *step - name: install clang run: src/ci/scripts/install-clang.sh - <<: *step - name: install tidy run: src/ci/scripts/install-tidy.sh - <<: *step - name: install WIX run: src/ci/scripts/install-wix.sh - <<: *step - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh - <<: *step - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh - <<: *step - name: install MSYS2 run: src/ci/scripts/install-msys2.sh - <<: *step - name: install MinGW run: src/ci/scripts/install-mingw.sh - <<: *step - name: install ninja run: src/ci/scripts/install-ninja.sh - <<: *step - name: enable ipv6 on Docker run: src/ci/scripts/enable-docker-ipv6.sh - <<: *step # Disable automatic line ending conversion (again). On Windows, when we're # installing dependencies, something switches the git configuration directory or @@ -234,19 +211,15 @@ x--expand-yaml-anchors--remove: # appropriate line endings. - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh - <<: *step - name: ensure line endings are correct run: src/ci/scripts/verify-line-endings.sh - <<: *step - name: ensure backported commits are in upstream branches run: src/ci/scripts/verify-backported-commits.sh - <<: *step - name: ensure the stable version number is correct run: src/ci/scripts/verify-stable-version-number.sh - <<: *step - name: run the build # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. @@ -255,11 +228,9 @@ x--expand-yaml-anchors--remove: AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }} - <<: *step - name: create github artifacts run: src/ci/scripts/create-doc-artifacts.sh - <<: *step - name: upload artifacts to github uses: actions/upload-artifact@v4 @@ -269,7 +240,6 @@ x--expand-yaml-anchors--remove: path: obj/artifacts/doc if-no-files-found: ignore retention-days: 5 - <<: *step - name: upload artifacts to S3 run: src/ci/scripts/upload-artifacts.sh @@ -281,8 +251,7 @@ x--expand-yaml-anchors--remove: # adding the condition is helpful as this way CI will not silently skip # deploying artifacts from a dist builder if the variables are misconfigured, # erroring about invalid credentials instead. - if: success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1') - <<: *step + if: success() && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1') # These snippets are used by the try-success, try-failure, auto-success and auto-failure jobs. # Check out their documentation for more information on why they're needed. @@ -342,6 +311,8 @@ concurrency: jobs: # The job matrix for `calculate_matrix` is defined in src/ci/github-actions/jobs.yml. + # It calculates which jobs should be executed, based on the data of the ${{ github }} context. + # If you want to modify CI jobs, take a look at src/ci/github-actions/jobs.yml. calculate_matrix: name: Calculate job matrix runs-on: ubuntu-latest @@ -351,422 +322,34 @@ jobs: - name: Checkout the source code uses: actions/checkout@v4 - name: Calculate the CI job matrix - run: python3 src/ci/scripts/calculate-job-matrix.py >> $GITHUB_OUTPUT + run: python3 src/ci/github-actions/calculate-job-matrix.py >> $GITHUB_OUTPUT id: jobs - pr: + job: <<: *base-ci-job - name: PR - ${{ matrix.name }} + name: ${{ matrix.name }} needs: [ calculate_matrix ] env: - <<: [*shared-ci-variables, *public-variables] - PR_CI_JOB: 1 - if: github.event_name == 'pull_request' - continue-on-error: ${{ matrix.name == 'mingw-check-tidy' }} + CI_JOB_NAME: ${{ matrix.image }} + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs. + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + DOCKER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SCCACHE_BUCKET: rust-lang-ci-sccache2 + TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate + CACHE_DOMAIN: ci-caches.rust-lang.org + continue-on-error: ${{ matrix.continue_on_error || false }} strategy: matrix: # Check the `calculate_matrix` job to see how is the matrix defined. include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }} - - auto: - <<: *base-ci-job - name: auto - ${{ matrix.name }} - env: - <<: [*shared-ci-variables, *prod-variables] - if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust' - strategy: - matrix: - include: - ############################# - # Linux/Docker builders # - ############################# - - - name: aarch64-gnu - <<: *job-aarch64-linux - - - name: arm-android - <<: *job-linux-8c - - - name: armhf-gnu - <<: *job-linux-8c - - - name: dist-aarch64-linux - env: - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-8c - - - name: dist-android - <<: *job-linux-8c - - - name: dist-arm-linux - <<: *job-linux-16c - - - name: dist-armhf-linux - <<: *job-linux-8c - - - name: dist-armv7-linux - <<: *job-linux-8c - - - name: dist-i586-gnu-i586-i686-musl - <<: *job-linux-8c - - - name: dist-i686-linux - <<: *job-linux-8c - - - name: dist-loongarch64-linux - <<: *job-linux-8c - - - name: dist-ohos - <<: *job-linux-8c - - - name: dist-powerpc-linux - <<: *job-linux-8c - - - name: dist-powerpc64-linux - <<: *job-linux-8c - - - name: dist-powerpc64le-linux - <<: *job-linux-8c - - - name: dist-riscv64-linux - <<: *job-linux-8c - - - name: dist-s390x-linux - <<: *job-linux-8c - - - name: dist-various-1 - <<: *job-linux-8c - - - name: dist-various-2 - <<: *job-linux-8c - - - name: dist-x86_64-freebsd - <<: *job-linux-8c - - - name: dist-x86_64-illumos - <<: *job-linux-8c - - - &dist-x86_64-linux - name: dist-x86_64-linux - env: - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c - - - name: dist-x86_64-linux-alt - env: - IMAGE: dist-x86_64-linux - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c - - - name: dist-x86_64-musl - env: - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-8c - - - name: dist-x86_64-netbsd - <<: *job-linux-8c - - - name: i686-gnu - <<: *job-linux-8c - - - name: i686-gnu-nopt - <<: *job-linux-8c - - - name: mingw-check - <<: *job-linux-4c - - - name: test-various - <<: *job-linux-8c - - - name: x86_64-gnu - <<: *job-linux-4c - - # This job ensures commits landing on nightly still pass the full - # test suite on the stable channel. There are some UI tests that - # depend on the channel being built (for example if they include the - # channel name on the output), and this builder prevents landing - # changes that would result in broken builds after a promotion. - - name: x86_64-gnu-stable - env: - IMAGE: x86_64-gnu - RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable - # Only run this job on the nightly channel. Running this on beta - # could cause failures when `dev: 1` in `stage0.txt`, and running - # this on stable is useless. - CI_ONLY_WHEN_CHANNEL: nightly - <<: *job-linux-4c - - - name: x86_64-gnu-aux - <<: *job-linux-4c - - - name: x86_64-gnu-integration - env: - # Only run this job on the nightly channel. Fuchsia requires - # nightly features to compile, and this job would fail if - # executed on beta and stable. - CI_ONLY_WHEN_CHANNEL: nightly - <<: *job-linux-8c - - - name: x86_64-gnu-debug - <<: *job-linux-8c - - - name: x86_64-gnu-distcheck - <<: *job-linux-8c - - - name: x86_64-gnu-llvm-18 - env: - RUST_BACKTRACE: 1 - <<: *job-linux-8c - - - name: x86_64-gnu-llvm-17 - env: - RUST_BACKTRACE: 1 - <<: *job-linux-8c - - - name: x86_64-gnu-nopt - <<: *job-linux-4c - - - name: x86_64-gnu-tools - env: - DEPLOY_TOOLSTATES_JSON: toolstates-linux.json - <<: *job-linux-8c - - #################### - # macOS Builders # - #################### - - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin - RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1 - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-macos-xl - - - name: dist-apple-various - env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim - RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-xl - - - name: x86_64-apple-1 - env: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.12 - MACOSX_STD_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-xl - - - name: x86_64-apple-2 - env: - SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps - <<: *env-x86_64-apple-tests - <<: *job-macos-xl - - # This target only needs to support 11.0 and up as nothing else supports the hardware - - name: dist-aarch64-apple - env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin - RUST_CONFIGURE_ARGS: >- - --enable-full-tools - --enable-sanitizers - --enable-profiler - --set rust.jemalloc - --set llvm.ninja=false - --set rust.lto=thin - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - USE_XCODE_CLANG: 1 - MACOSX_DEPLOYMENT_TARGET: 11.0 - MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-macos-m1 - - # This target only needs to support 11.0 and up as nothing else supports the hardware - - name: aarch64-apple - env: - SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin - RUST_CONFIGURE_ARGS: >- - --enable-sanitizers - --enable-profiler - --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - SELECT_XCODE: /Applications/Xcode_14.3.1.app - USE_XCODE_CLANG: 1 - MACOSX_DEPLOYMENT_TARGET: 11.0 - MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-m1 - - ###################### - # Windows Builders # - ###################### - - - name: x86_64-msvc - env: - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: make ci-msvc - <<: *job-windows-8c - - - name: i686-msvc - env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-msvc - <<: *job-windows-8c - - - name: x86_64-msvc-ext - env: - SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo && src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows - HOST_TARGET: x86_64-pc-windows-msvc - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json - DEPLOY_TOOLSTATES_JSON: toolstates-windows.json - <<: *job-windows-8c - - # 32/64-bit MinGW builds. - # - # We are using MinGW with POSIX threads since LLVM requires - # C++'s std::thread which is disabled in libstdc++ with win32 threads. - # FIXME: Libc++ doesn't have this limitation so we can avoid - # winpthreads if we switch to it. - # - # Instead of relying on the MinGW version installed on CI we download - # and install one ourselves so we won't be surprised by changes to CI's - # build image. - # - # Finally, note that the downloads below are all in the `rust-lang-ci` S3 - # bucket, but they clearly didn't originate there! The downloads originally - # came from the mingw-w64 SourceForge download site. Unfortunately - # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - - - name: i686-mingw - env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make ci-mingw - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - <<: *job-windows-8c - - - name: x86_64-mingw - env: - SCRIPT: make ci-mingw - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-gnu - --enable-profiler - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - <<: *job-windows-8c - - - name: dist-x86_64-msvc - env: - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-msvc - --host=x86_64-pc-windows-msvc - --target=x86_64-pc-windows-msvc - --enable-full-tools - --enable-profiler - --set rust.codegen-units=1 - SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-i686-msvc - env: - RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-msvc - --host=i686-pc-windows-msvc - --target=i686-pc-windows-msvc,i586-pc-windows-msvc - --enable-full-tools - --enable-profiler - SCRIPT: python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-aarch64-msvc - env: - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-msvc - --host=aarch64-pc-windows-msvc - --enable-full-tools - --enable-profiler - SCRIPT: python x.py dist bootstrap --include-default-paths - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-i686-mingw - env: - RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-gnu - --enable-full-tools - --enable-profiler - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - SCRIPT: python x.py dist bootstrap --include-default-paths - CUSTOM_MINGW: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-x86_64-mingw - env: - SCRIPT: python x.py dist bootstrap --include-default-paths - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-gnu - --enable-full-tools - --enable-profiler - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c - - - name: dist-x86_64-msvc-alt - env: - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler - SCRIPT: python x.py dist bootstrap --include-default-paths - <<: *job-windows-8c - - try: - <<: *base-ci-job - name: try - ${{ matrix.name }} - env: - DIST_TRY_BUILD: 1 - <<: [*shared-ci-variables, *prod-variables] - if: github.event_name == 'push' && (((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust') || ((github.ref == 'refs/heads/automation/bors/try') && github.repository == 'rust-lang/rust')) - strategy: - matrix: - include: - - &dist-x86_64-linux - name: dist-x86_64-linux - env: - CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c - + # GitHub Actions fails the workflow if an empty list of jobs is provided to + # the workflow, so we need to skip this job if nothing was produced by + # the Python script. + # + # Unfortunately checking whether a list is empty is not possible in a nice + # way due to GitHub Actions expressions limits. + # This hack is taken from https://github.com/ferrocene/ferrocene/blob/d43edc6b7697cf1719ec1c17c54904ab94825763/.github/workflows/release.yml#L75-L82 + if: fromJSON(needs.calculate_matrix.outputs.jobs)[0] != null master: name: master @@ -785,24 +368,23 @@ jobs: shell: bash env: TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }} - <<: *step # These jobs don't actually test anything, but they're used to tell bors the # build completed, as there is no practical way to detect when a workflow is # successful listening to webhooks only. try-success: - needs: [try] + needs: [ job ] if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'" <<: *base-success-job try-failure: - needs: [try] + needs: [ job ] if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'" <<: *base-failure-job auto-success: - needs: [auto] + needs: [ job ] if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" <<: *base-success-job auto-failure: - needs: [auto] + needs: [ job ] if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" <<: *base-failure-job diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 7e89eef2670..df6c5d6079d 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -2,7 +2,7 @@ # dynamically in CI from ci.yml. # You *do not* need to re-run `src/tools/expand-yaml-anchors` when you # modify this file. -shared_defs: +runners: - &base-job env: { } @@ -37,14 +37,429 @@ shared_defs: - &job-aarch64-linux os: [ self-hosted, ARM64, linux ] +envs: + production: + &production + DEPLOY_BUCKET: rust-lang-ci2 + TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues + TOOLSTATE_PUBLISH: 1 + # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named + # AWS_SECRET_ACCESS_KEY_<keyid>. Including the key id in the name allows to + # rotate them in a single branch while keeping the old key in another + # branch, which wouldn't be possible if the key was named with the kind + # (caches, artifacts...). + CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL + ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 + AWS_REGION: us-west-1 + + try: + <<: *production + DIST_TRY_BUILD: 1 + + auto: + <<: *production + + pr: + PR_CI_JOB: 1 + +# Jobs that run on each push to a pull request (PR) +# These jobs automatically inherit envs.pr, to avoid repeating +# it in each job definition. pr: - - name: mingw-check + - image: mingw-check <<: *job-linux-4c - - name: mingw-check-tidy + - image: mingw-check-tidy + continue_on_error: true <<: *job-linux-4c - - name: x86_64-gnu-llvm-17 + - image: x86_64-gnu-llvm-17 env: ENABLE_GCC_CODEGEN: "1" <<: *job-linux-16c - - name: x86_64-gnu-tools + - image: x86_64-gnu-tools + <<: *job-linux-16c + +# Jobs that run when you perform a try build (@bors try) +# These jobs automatically inherit envs.try, to avoid repeating +# it in each job definition. +try: + - image: dist-x86_64-linux + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-16c + +# Main CI jobs that have to be green to merge a commit into master +# These jobs automatically inherit envs.auto, to avoid repeating +# it in each job definition. +auto: + ############################# + # Linux/Docker builders # + ############################# + + - image: aarch64-gnu + <<: *job-aarch64-linux + + - image: arm-android + <<: *job-linux-8c + + - image: armhf-gnu + <<: *job-linux-8c + + - image: dist-aarch64-linux + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-8c + + - image: dist-android + <<: *job-linux-8c + + - image: dist-arm-linux + <<: *job-linux-16c + + - image: dist-armhf-linux + <<: *job-linux-8c + + - image: dist-armv7-linux + <<: *job-linux-8c + + - image: dist-i586-gnu-i586-i686-musl + <<: *job-linux-8c + + - image: dist-i686-linux + <<: *job-linux-8c + + - image: dist-loongarch64-linux + <<: *job-linux-8c + + - image: dist-ohos + <<: *job-linux-8c + + - image: dist-powerpc-linux + <<: *job-linux-8c + + - image: dist-powerpc64-linux + <<: *job-linux-8c + + - image: dist-powerpc64le-linux + <<: *job-linux-8c + + - image: dist-riscv64-linux + <<: *job-linux-8c + + - image: dist-s390x-linux + <<: *job-linux-8c + + - image: dist-various-1 + <<: *job-linux-8c + + - image: dist-various-2 + <<: *job-linux-8c + + - image: dist-x86_64-freebsd + <<: *job-linux-8c + + - image: dist-x86_64-illumos + <<: *job-linux-8c + + - image: dist-x86_64-linux + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-16c + + - image: dist-x86_64-linux-alt + env: + IMAGE: dist-x86_64-linux + CODEGEN_BACKENDS: llvm,cranelift <<: *job-linux-16c + + - image: dist-x86_64-musl + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-8c + + - image: dist-x86_64-netbsd + <<: *job-linux-8c + + - image: i686-gnu + <<: *job-linux-8c + + - image: i686-gnu-nopt + <<: *job-linux-8c + + - image: mingw-check + <<: *job-linux-4c + + - image: test-various + <<: *job-linux-8c + + - image: x86_64-gnu + <<: *job-linux-4c + + # This job ensures commits landing on nightly still pass the full + # test suite on the stable channel. There are some UI tests that + # depend on the channel being built (for example if they include the + # channel name on the output), and this builder prevents landing + # changes that would result in broken builds after a promotion. + - image: x86_64-gnu-stable + # Only run this job on the nightly channel. Running this on beta + # could cause failures when `dev: 1` in `stage0.txt`, and running + # this on stable is useless. + only_on_channel: nightly + env: + IMAGE: x86_64-gnu + RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable + <<: *job-linux-4c + + - image: x86_64-gnu-aux + <<: *job-linux-4c + + - image: x86_64-gnu-integration + # Only run this job on the nightly channel. Fuchsia requires + # nightly features to compile, and this job would fail if + # executed on beta and stable. + only_on_channel: nightly + <<: *job-linux-8c + + - image: x86_64-gnu-debug + <<: *job-linux-8c + + - image: x86_64-gnu-distcheck + <<: *job-linux-8c + + - image: x86_64-gnu-llvm-18 + env: + RUST_BACKTRACE: 1 + <<: *job-linux-8c + + - image: x86_64-gnu-llvm-17 + env: + RUST_BACKTRACE: 1 + <<: *job-linux-8c + + - image: x86_64-gnu-nopt + <<: *job-linux-4c + + - image: x86_64-gnu-tools + env: + DEPLOY_TOOLSTATES_JSON: toolstates-linux.json + <<: *job-linux-8c + + #################### + # macOS Builders # + #################### + + - image: dist-x86_64-apple + env: + SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin + RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1 + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.12 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-macos-xl + + - image: dist-apple-various + env: + SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim + RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.12 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-xl + + - image: x86_64-apple-1 + env: &env-x86_64-apple-tests + SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.12 + MACOSX_STD_DEPLOYMENT_TARGET: 10.12 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-xl + + - image: x86_64-apple-2 + env: + SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps + <<: *env-x86_64-apple-tests + <<: *job-macos-xl + + # This target only needs to support 11.0 and up as nothing else supports the hardware + - image: dist-aarch64-apple + env: + SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin + RUST_CONFIGURE_ARGS: >- + --enable-full-tools + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + --set llvm.ninja=false + --set rust.lto=thin + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-m1 + + # This target only needs to support 11.0 and up as nothing else supports the hardware + - image: aarch64-apple + env: + SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_14.3.1.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-m1 + + ###################### + # Windows Builders # + ###################### + + - image: x86_64-msvc + env: + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler + SCRIPT: make ci-msvc + <<: *job-windows-8c + + - image: i686-msvc + env: + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc + SCRIPT: make ci-msvc + <<: *job-windows-8c + + - image: x86_64-msvc-ext + env: + SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo && src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows + HOST_TARGET: x86_64-pc-windows-msvc + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json + DEPLOY_TOOLSTATES_JSON: toolstates-windows.json + <<: *job-windows-8c + + # 32/64-bit MinGW builds. + # + # We are using MinGW with POSIX threads since LLVM requires + # C++'s std::thread which is disabled in libstdc++ with win32 threads. + # FIXME: Libc++ doesn't have this limitation so we can avoid + # winpthreads if we switch to it. + # + # Instead of relying on the MinGW version installed on CI we download + # and install one ourselves so we won't be surprised by changes to CI's + # build image. + # + # Finally, note that the downloads below are all in the `rust-lang-ci` S3 + # bucket, but they clearly didn't originate there! The downloads originally + # came from the mingw-w64 SourceForge download site. Unfortunately + # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. + + - image: i686-mingw + env: + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + SCRIPT: make ci-mingw + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 + CUSTOM_MINGW: 1 + <<: *job-windows-8c + + - image: x86_64-mingw + env: + SCRIPT: make ci-mingw + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-profiler + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 + CUSTOM_MINGW: 1 + <<: *job-windows-8c + + - image: dist-x86_64-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-msvc + --host=x86_64-pc-windows-msvc + --target=x86_64-pc-windows-msvc + --enable-full-tools + --enable-profiler + --set rust.codegen-units=1 + SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-i686-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-msvc + --host=i686-pc-windows-msvc + --target=i686-pc-windows-msvc,i586-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist bootstrap --include-default-paths + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-aarch64-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-msvc + --host=aarch64-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist bootstrap --include-default-paths + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-i686-mingw + env: + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-gnu + --enable-full-tools + --enable-profiler + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 + SCRIPT: python x.py dist bootstrap --include-default-paths + CUSTOM_MINGW: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-x86_64-mingw + env: + SCRIPT: python x.py dist bootstrap --include-default-paths + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-full-tools + --enable-profiler + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 + CUSTOM_MINGW: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-windows-8c + + - image: dist-x86_64-msvc-alt + env: + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler + SCRIPT: python x.py dist bootstrap --include-default-paths + <<: *job-windows-8c diff --git a/src/ci/scripts/calculate-job-matrix.py b/src/ci/scripts/calculate-job-matrix.py deleted file mode 100755 index 9b1e74c23c3..00000000000 --- a/src/ci/scripts/calculate-job-matrix.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 - -""" -This script serves for generating a matrix of jobs that should -be executed on CI. - -It reads job definitions from `src/ci/github-actions/jobs.yml` -and filters them based on the event that happened on CI. - -Currently, it only supports PR builds. -""" - -import json -from pathlib import Path - -import yaml - -JOBS_YAML_PATH = Path(__file__).absolute().parent.parent / "github-actions" / "jobs.yml" - - -if __name__ == "__main__": - with open(JOBS_YAML_PATH) as f: - jobs = yaml.safe_load(f) - job_output = jobs["pr"] - print(f"jobs={json.dumps(job_output)}") diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh deleted file mode 100755 index 48127166ad0..00000000000 --- a/src/ci/scripts/should-skip-this.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# Set the SKIP_JOB environment variable if this job is not supposed to run on the current builder. - -set -euo pipefail -IFS=$'\n\t' - -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" - -if [[ -n "${CI_ONLY_WHEN_CHANNEL-}" ]]; then - if [[ "${CI_ONLY_WHEN_CHANNEL}" = "$(cat src/ci/channel)" ]]; then - echo "The channel is the expected one" - else - echo "Not executing this job as the channel is not the expected one" - ciCommandSetEnv SKIP_JOB 1 - exit 0 - fi -fi - - -echo "Executing the job since there is no skip rule preventing the execution" -exit 0 diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 673ff12b5ce..babe2bc342b 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -42,6 +42,18 @@ generated code, but may be slower to compile. The default value, if not specified, is 16 for non-incremental builds. For incremental builds the default is 256 which allows caching to be more granular. +## collapse-macro-debuginfo + +This flag controls whether code locations from a macro definition are collapsed into a single +location associated with that macro's call site, when generating debuginfo for this crate. + +This option, if passed, overrides both default collapsing behavior and `#[collapse_debuginfo]` +attributes in code. + +* `y`, `yes`, `on`, `true`: collapse code locations in debuginfo. +* `n`, `no`, `off` or `false`: do not collapse code locations in debuginfo. +* `external`: collapse code locations in debuginfo only if the macro comes from a different crate. + ## control-flow-guard This flag controls whether LLVM enables the Windows [Control Flow diff --git a/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md b/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md index 9fd0ac49881..2e827535862 100644 --- a/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md +++ b/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md @@ -73,7 +73,7 @@ Tests can be run on AArch64 Windows 11 devices. ## Cross-compilation toolchains and C code -C code can be built using the Arm64-targetting MSVC or Clang toolchain. +C code can be built using the Arm64-targeting MSVC or Clang toolchain. To compile: diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1.md b/src/doc/rustc/src/platform-support/wasm32-wasip1.md index 77efa9c3282..4faa1988735 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1.md @@ -59,7 +59,7 @@ languages compiled to WebAssembly, for example C/C++. Any ABI differences or mismatches are considered bugs that need to be fixed. By default the WASI targets in Rust ship in rustup with a precompiled copy of -[`wasi-libc`] meaning that a WebAssembly-targetting-Clang is not required to +[`wasi-libc`] meaning that a WebAssembly-targeting-Clang is not required to use the WASI targets from Rust. If there is no actual interoperation with C then `rustup target add wasm32-wasip1` is all that's needed to get started with WASI. diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 7d573ac950d..c05077befdb 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -417,7 +417,7 @@ warning: 1 warning emitted This lint is **warn-by-default**. It detects explicit links that are the same as computed automatic links. -This usually means the explicit links are removeable. For example: +This usually means the explicit links are removable. For example: ```rust #![warn(rustdoc::redundant_explicit_links)] // note: unnecessary - warns by default. diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md index 56c14b1638a..1a367b8274b 100644 --- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md @@ -168,4 +168,4 @@ render differently in this case: ``` `1.` and `2.` will be displayed as is in the rendered documentation (ie, `[a]` and `[b][c]`) -whereas `3.` and `4.` will be replaced by a link targetting `e` for `[d](e)` and `g` for `[f]`. +whereas `3.` and `4.` will be replaced by a link targeting `e` for `[d](e)` and `g` for `[f]`. diff --git a/src/doc/unstable-book/src/language-features/coroutines.md b/src/doc/unstable-book/src/language-features/coroutines.md index f8e5a22fbd5..9fb07594650 100644 --- a/src/doc/unstable-book/src/language-features/coroutines.md +++ b/src/doc/unstable-book/src/language-features/coroutines.md @@ -26,13 +26,13 @@ tweaks to the overall design. A syntactical example of a coroutine is: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo" }; @@ -48,7 +48,8 @@ fn main() { } ``` -Coroutines are closure-like literals which can contain a `yield` statement. The +Coroutines are closure-like literals which are annotated with `#[coroutine]` +and can contain a `yield` statement. The `yield` statement takes an optional expression of a value to yield out of the coroutine. All coroutine literals implement the `Coroutine` trait in the `std::ops` module. The `Coroutine` trait has one main method, `resume`, which @@ -58,13 +59,13 @@ An example of the control flow of coroutines is that the following example prints all numbers in order: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { println!("2"); yield; println!("4"); @@ -78,9 +79,9 @@ fn main() { } ``` -At this time the main intended use case of coroutines is an implementation -primitive for async/await syntax, but coroutines will likely be extended to -ergonomic implementations of iterators and other primitives in the future. +At this time the main use case of coroutines is an implementation +primitive for `async`/`await` and `gen` syntax, but coroutines +will likely be extended to other primitives in the future. Feedback on the design and usage is always appreciated! ### The `Coroutine` trait @@ -163,14 +164,14 @@ which point all state is saved off in the coroutine and a value is returned. Let's take a look at an example to see what's going on here: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { let ret = "foo"; - let mut coroutine = move || { + let mut coroutine = #[coroutine] move || { yield 1; return ret }; @@ -183,7 +184,7 @@ fn main() { This coroutine literal will compile down to something similar to: ```rust -#![feature(arbitrary_self_types, coroutines, coroutine_trait)] +#![feature(arbitrary_self_types, coroutine_trait)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; diff --git a/src/doc/unstable-book/src/language-features/inline-const-pat.md b/src/doc/unstable-book/src/language-features/inline-const-pat.md index 5f0f7547a0a..c6f54d79cfc 100644 --- a/src/doc/unstable-book/src/language-features/inline-const-pat.md +++ b/src/doc/unstable-book/src/language-features/inline-const-pat.md @@ -2,8 +2,6 @@ The tracking issue for this feature is: [#76001] -See also [`inline_const`](inline-const.md) - ------ This feature allows you to use inline constant expressions in pattern position: diff --git a/src/doc/unstable-book/src/language-features/inline-const.md b/src/doc/unstable-book/src/language-features/inline-const.md deleted file mode 100644 index 7be70eed6ce..00000000000 --- a/src/doc/unstable-book/src/language-features/inline-const.md +++ /dev/null @@ -1,32 +0,0 @@ -# `inline_const` - -The tracking issue for this feature is: [#76001] - -See also [`inline_const_pat`](inline-const-pat.md) - ------- - -This feature allows you to use inline constant expressions. For example, you can -turn this code: - -```rust -# fn add_one(x: i32) -> i32 { x + 1 } -const MY_COMPUTATION: i32 = 1 + 2 * 3 / 4; - -fn main() { - let x = add_one(MY_COMPUTATION); -} -``` - -into this code: - -```rust -#![feature(inline_const)] - -# fn add_one(x: i32) -> i32 { x + 1 } -fn main() { - let x = add_one(const { 1 + 2 * 3 / 4 }); -} -``` - -[#76001]: https://github.com/rust-lang/rust/issues/76001 diff --git a/src/doc/unstable-book/src/the-unstable-book.md b/src/doc/unstable-book/src/the-unstable-book.md index 0f4fb405669..63134f7ae28 100644 --- a/src/doc/unstable-book/src/the-unstable-book.md +++ b/src/doc/unstable-book/src/the-unstable-book.md @@ -5,13 +5,13 @@ each one organized by a "feature flag." That is, when using an unstable feature of Rust, you must use a flag, like this: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo" }; diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index f78743a7917..dd2bb47e592 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -187,7 +187,7 @@ declare_rustdoc_lint! { declare_rustdoc_lint! { /// This lint is **warn-by-default**. It detects explicit links that are the same - /// as computed automatic links. This usually means the explicit links are removeable. + /// as computed automatic links. This usually means the explicit links are removable. /// This is a `rustdoc` only lint, see the documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#redundant_explicit_links diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1ba4e6cbdf0..747f5c0a835 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1420,7 +1420,7 @@ impl LinkCollector<'_, '_> { // // Otherwise, check if 2 links are same, if so, skip the resolve process. // - // Notice that this algorithm is passive, might possibly miss actual redudant cases. + // Notice that this algorithm is passive, might possibly miss actual redundant cases. let explicit_link = explicit_link.to_string(); let display_text = ori_link.display_text.as_ref().unwrap(); diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 89d6f8d67f1..e788069ea80 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -314,7 +314,7 @@ pub enum StructKind { /// All [`Id`]'s will point to [`ItemEnum::StructField`]. Private and /// `#[doc(hidden)]` fields will be given as `None` Tuple(Vec<Option<Id>>), - /// A struct with nammed fields. + /// A struct with named fields. /// /// ```rust /// pub struct PlainStruct { x: i32 } diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs index 4ae75544c60..232bccf6a15 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr index 120f5c35cb0..5ce2ed2ffae 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:27:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:26:5 | LL | x[index]; | ^^^^^^^^ @@ -9,7 +9,7 @@ LL | x[index]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:41:5 | LL | v[0]; | ^^^^ @@ -17,7 +17,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 | LL | v[10]; | ^^^^^ @@ -25,7 +25,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:44:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:49:5 | LL | v[N]; | ^^^^ @@ -41,7 +41,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:51:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 | LL | v[M]; | ^^^^ diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index b454c29aef4..fdec14a1528 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -10,7 +10,7 @@ arithmetic_overflow, unconditional_panic )] -#![feature(const_mut_refs, inline_const)] +#![feature(const_mut_refs)] #![warn(clippy::arithmetic_side_effects)] extern crate proc_macro_derive; diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed index 167263d31df..f7dad28b036 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed @@ -1,4 +1,4 @@ -#![feature(let_chains, inline_const)] +#![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs index f3f055eb7f0..d22871d2c8f 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs @@ -1,4 +1,4 @@ -#![feature(let_chains, inline_const)] +#![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/const_is_empty.rs b/src/tools/clippy/tests/ui/const_is_empty.rs index ae37a82e4f9..04e0de91ecf 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.rs +++ b/src/tools/clippy/tests/ui/const_is_empty.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![warn(clippy::const_is_empty)] #![allow(clippy::needless_late_init, unused_must_use)] diff --git a/src/tools/clippy/tests/ui/const_is_empty.stderr b/src/tools/clippy/tests/ui/const_is_empty.stderr index 0e09da77bb4..7f80b520b1a 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.stderr +++ b/src/tools/clippy/tests/ui/const_is_empty.stderr @@ -1,5 +1,5 @@ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:6:8 + --> tests/ui/const_is_empty.rs:5:8 | LL | if "".is_empty() { | ^^^^^^^^^^^^^ @@ -8,151 +8,151 @@ LL | if "".is_empty() { = help: to override `-D warnings` add `#[allow(clippy::const_is_empty)]` error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:9:8 + --> tests/ui/const_is_empty.rs:8:8 | LL | if "foobar".is_empty() { | ^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:15:8 + --> tests/ui/const_is_empty.rs:14:8 | LL | if b"".is_empty() { | ^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:18:8 + --> tests/ui/const_is_empty.rs:17:8 | LL | if b"foobar".is_empty() { | ^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:35:8 + --> tests/ui/const_is_empty.rs:34:8 | LL | if empty2.is_empty() { | ^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:38:8 + --> tests/ui/const_is_empty.rs:37:8 | LL | if non_empty2.is_empty() { | ^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:60:13 + --> tests/ui/const_is_empty.rs:59:13 | LL | let _ = EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:62:13 + --> tests/ui/const_is_empty.rs:61:13 | LL | let _ = NON_EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:64:13 + --> tests/ui/const_is_empty.rs:63:13 | LL | let _ = EMPTY_BSTR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:66:13 + --> tests/ui/const_is_empty.rs:65:13 | LL | let _ = NON_EMPTY_BSTR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:68:13 + --> tests/ui/const_is_empty.rs:67:13 | LL | let _ = EMPTY_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:70:13 + --> tests/ui/const_is_empty.rs:69:13 | LL | let _ = EMPTY_ARRAY_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:72:13 + --> tests/ui/const_is_empty.rs:71:13 | LL | let _ = EMPTY_U8_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:74:13 + --> tests/ui/const_is_empty.rs:73:13 | LL | let _ = NON_EMPTY_U8_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:76:13 + --> tests/ui/const_is_empty.rs:75:13 | LL | let _ = NON_EMPTY_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:78:13 + --> tests/ui/const_is_empty.rs:77:13 | LL | let _ = NON_EMPTY_ARRAY_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:80:13 + --> tests/ui/const_is_empty.rs:79:13 | LL | let _ = EMPTY_REF_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:82:13 + --> tests/ui/const_is_empty.rs:81:13 | LL | let _ = NON_EMPTY_REF_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:84:13 + --> tests/ui/const_is_empty.rs:83:13 | LL | let _ = EMPTY_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:86:13 + --> tests/ui/const_is_empty.rs:85:13 | LL | let _ = NON_EMPTY_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:88:13 + --> tests/ui/const_is_empty.rs:87:13 | LL | let _ = NON_EMPTY_SLICE_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:94:13 + --> tests/ui/const_is_empty.rs:93:13 | LL | let _ = value.is_empty(); | ^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:97:13 + --> tests/ui/const_is_empty.rs:96:13 | LL | let _ = x.is_empty(); | ^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:99:13 + --> tests/ui/const_is_empty.rs:98:13 | LL | let _ = "".is_empty(); | ^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:101:13 + --> tests/ui/const_is_empty.rs:100:13 | LL | let _ = b"".is_empty(); | ^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:155:13 + --> tests/ui/const_is_empty.rs:154:13 | LL | let _ = val.is_empty(); | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/crashes/ice-5238.rs b/src/tools/clippy/tests/ui/crashes/ice-5238.rs index b1fc3fb9d25..fe03a39ad1b 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5238.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5238.rs @@ -1,9 +1,9 @@ // Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { - let _ = || { + let _ = #[coroutine] || { yield; }; } diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs index 27ee2f91594..2e726141649 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs @@ -1,6 +1,5 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes -#![feature(inline_const)] #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 5f62ec9b556..386f91becf1 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:16:20 + --> tests/ui/indexing_slicing_index.rs:15:20 | LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^ @@ -10,19 +10,19 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error[E0080]: evaluation of `main::{constant#3}` failed - --> tests/ui/indexing_slicing_index.rs:48:14 + --> tests/ui/indexing_slicing_index.rs:47:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:48:5 + --> tests/ui/indexing_slicing_index.rs:47:5 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:29:5 + --> tests/ui/indexing_slicing_index.rs:28:5 | LL | x[index]; | ^^^^^^^^ @@ -30,7 +30,7 @@ LL | x[index]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:32:5 + --> tests/ui/indexing_slicing_index.rs:31:5 | LL | x[4]; | ^^^^ @@ -39,13 +39,13 @@ LL | x[4]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:34:5 + --> tests/ui/indexing_slicing_index.rs:33:5 | LL | x[1 << 3]; | ^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:45:14 + --> tests/ui/indexing_slicing_index.rs:44:14 | LL | const { &ARR[idx()] }; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | const { &ARR[idx()] }; = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:48:14 + --> tests/ui/indexing_slicing_index.rs:47:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ @@ -63,13 +63,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:55:5 + --> tests/ui/indexing_slicing_index.rs:54:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:58:5 + --> tests/ui/indexing_slicing_index.rs:57:5 | LL | v[0]; | ^^^^ @@ -77,7 +77,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:60:5 + --> tests/ui/indexing_slicing_index.rs:59:5 | LL | v[10]; | ^^^^^ @@ -85,7 +85,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:62:5 + --> tests/ui/indexing_slicing_index.rs:61:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +93,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:70:5 + --> tests/ui/indexing_slicing_index.rs:69:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:73:5 + --> tests/ui/indexing_slicing_index.rs:72:5 | LL | v[N]; | ^^^^ @@ -107,7 +107,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:75:5 + --> tests/ui/indexing_slicing_index.rs:74:5 | LL | v[M]; | ^^^^ @@ -115,7 +115,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:79:13 + --> tests/ui/indexing_slicing_index.rs:78:13 | LL | let _ = x[4]; | ^^^^ diff --git a/src/tools/clippy/tests/ui/large_futures.fixed b/src/tools/clippy/tests/ui/large_futures.fixed index aa8c3021b97..1e87859f452 100644 --- a/src/tools/clippy/tests/ui/large_futures.fixed +++ b/src/tools/clippy/tests/ui/large_futures.fixed @@ -1,4 +1,3 @@ -#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/src/tools/clippy/tests/ui/large_futures.rs b/src/tools/clippy/tests/ui/large_futures.rs index fc6ea458d3d..3f4ea2ebf8b 100644 --- a/src/tools/clippy/tests/ui/large_futures.rs +++ b/src/tools/clippy/tests/ui/large_futures.rs @@ -1,4 +1,3 @@ -#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/src/tools/clippy/tests/ui/large_futures.stderr b/src/tools/clippy/tests/ui/large_futures.stderr index 5709c7b77a0..00082e579c5 100644 --- a/src/tools/clippy/tests/ui/large_futures.stderr +++ b/src/tools/clippy/tests/ui/large_futures.stderr @@ -1,5 +1,5 @@ error: large future with a size of 16385 bytes - --> tests/ui/large_futures.rs:11:9 + --> tests/ui/large_futures.rs:10:9 | LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` @@ -8,37 +8,37 @@ LL | big_fut([0u8; 1024 * 16]).await; = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` error: large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:15:5 + --> tests/ui/large_futures.rs:14:5 | LL | f.await | ^ help: consider `Box::pin` on it: `Box::pin(f)` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:20:9 + --> tests/ui/large_futures.rs:19:9 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:25:13 + --> tests/ui/large_futures.rs:24:13 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:33:5 + --> tests/ui/large_futures.rs:32:5 | LL | foo().await; | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` error: large future with a size of 49159 bytes - --> tests/ui/large_futures.rs:35:5 + --> tests/ui/large_futures.rs:34:5 | LL | calls_fut(fut).await; | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:48:5 + --> tests/ui/large_futures.rs:47:5 | LL | / async { LL | | @@ -59,7 +59,7 @@ LL + }) | error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:60:13 + --> tests/ui/large_futures.rs:59:13 | LL | / async { LL | | let x = [0i32; 1024 * 16]; diff --git a/src/tools/clippy/tests/ui/manual_float_methods.rs b/src/tools/clippy/tests/ui/manual_float_methods.rs index f3e95d6807d..80781ecda72 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.rs +++ b/src/tools/clippy/tests/ui/manual_float_methods.rs @@ -2,7 +2,6 @@ //@aux-build:proc_macros.rs #![allow(clippy::needless_if, unused)] #![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] -#![feature(inline_const)] #[macro_use] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/manual_float_methods.stderr b/src/tools/clippy/tests/ui/manual_float_methods.stderr index dae96839262..930df0b97cb 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.stderr +++ b/src/tools/clippy/tests/ui/manual_float_methods.stderr @@ -1,5 +1,5 @@ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:23:8 + --> tests/ui/manual_float_methods.rs:22:8 | LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` @@ -8,7 +8,7 @@ LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} = help: to override `-D warnings` add `#[allow(clippy::manual_is_infinite)]` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:24:8 + --> tests/ui/manual_float_methods.rs:23:8 | LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,13 +29,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:25:8 + --> tests/ui/manual_float_methods.rs:24:8 | LL | if x == INFINITE || x == NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:26:8 + --> tests/ui/manual_float_methods.rs:25:8 | LL | if x != INFINITE && x != NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,13 +54,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:28:8 + --> tests/ui/manual_float_methods.rs:27:8 | LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:29:8 + --> tests/ui/manual_float_methods.rs:28:8 | LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs index 92f173d9db4..93c69209c69 100644 --- a/src/tools/clippy/tests/ui/never_loop.rs +++ b/src/tools/clippy/tests/ui/never_loop.rs @@ -1,4 +1,4 @@ -#![feature(inline_const, try_blocks)] +#![feature(try_blocks)] #![allow( clippy::eq_op, clippy::single_match, diff --git a/src/tools/clippy/tests/ui/panicking_macros.rs b/src/tools/clippy/tests/ui/panicking_macros.rs index dccfbd409e5..2bbf5792ec4 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.rs +++ b/src/tools/clippy/tests/ui/panicking_macros.rs @@ -1,5 +1,4 @@ #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::let_unit_value)] -#![feature(inline_const)] #![warn(clippy::unimplemented, clippy::unreachable, clippy::todo, clippy::panic)] extern crate core; diff --git a/src/tools/clippy/tests/ui/panicking_macros.stderr b/src/tools/clippy/tests/ui/panicking_macros.stderr index 06025859c0c..7c0f0a7d376 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.stderr +++ b/src/tools/clippy/tests/ui/panicking_macros.stderr @@ -1,5 +1,5 @@ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:23:5 + --> tests/ui/panicking_macros.rs:22:5 | LL | panic!(); | ^^^^^^^^ @@ -8,19 +8,19 @@ LL | panic!(); = help: to override `-D warnings` add `#[allow(clippy::panic)]` error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:26:5 + --> tests/ui/panicking_macros.rs:25:5 | LL | panic!("message"); | ^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:28:5 + --> tests/ui/panicking_macros.rs:27:5 | LL | panic!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:35:5 + --> tests/ui/panicking_macros.rs:34:5 | LL | todo!(); | ^^^^^^^ @@ -29,19 +29,19 @@ LL | todo!(); = help: to override `-D warnings` add `#[allow(clippy::todo)]` error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:38:5 + --> tests/ui/panicking_macros.rs:37:5 | LL | todo!("message"); | ^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:40:5 + --> tests/ui/panicking_macros.rs:39:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:47:5 + --> tests/ui/panicking_macros.rs:46:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ @@ -50,19 +50,19 @@ LL | unimplemented!(); = help: to override `-D warnings` add `#[allow(clippy::unimplemented)]` error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:50:5 + --> tests/ui/panicking_macros.rs:49:5 | LL | unimplemented!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:52:5 + --> tests/ui/panicking_macros.rs:51:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:59:5 + --> tests/ui/panicking_macros.rs:58:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ @@ -71,37 +71,37 @@ LL | unreachable!(); = help: to override `-D warnings` add `#[allow(clippy::unreachable)]` error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:62:5 + --> tests/ui/panicking_macros.rs:61:5 | LL | unreachable!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:64:5 + --> tests/ui/panicking_macros.rs:63:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:71:5 + --> tests/ui/panicking_macros.rs:70:5 | LL | panic!(); | ^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:73:5 + --> tests/ui/panicking_macros.rs:72:5 | LL | todo!(); | ^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:75:5 + --> tests/ui/panicking_macros.rs:74:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:77:5 + --> tests/ui/panicking_macros.rs:76:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs index f6909828aa9..e9d77182a91 100644 --- a/src/tools/clippy/tests/ui/redundant_locals.rs +++ b/src/tools/clippy/tests/ui/redundant_locals.rs @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs #![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)] #![warn(clippy::redundant_locals)] -#![feature(async_closure, coroutines)] +#![feature(async_closure, coroutines, stmt_expr_attributes)] extern crate proc_macros; use proc_macros::{external, with_span}; @@ -191,11 +191,11 @@ fn issue12225() { let v4 = v4; dbg!(&v4); }); - assert_static(static || { + assert_static(#[coroutine] static || { let v5 = v5; yield; }); - assert_static(|| { + assert_static(#[coroutine] || { let v6 = v6; yield; }); diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index b0dab9f509d..0af334a654b 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: env: HOST_TARGET: ${{ matrix.host_target }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Show Rust version (stable toolchain) run: | @@ -57,12 +57,12 @@ jobs: ~/.cargo/bin ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: cargo-${{ runner.os }}-reset20240331-${{ hashFiles('**/Cargo.lock') }} - restore-keys: cargo-${{ runner.os }}-reset20240331 + key: cargo-${{ runner.os }}-reset20240425-${{ hashFiles('**/Cargo.lock') }} + restore-keys: cargo-${{ runner.os }}-reset20240425 - - name: Install rustup-toolchain-install-master + - name: Install tools if: ${{ steps.cache.outputs.cache-hit != 'true' }} - run: cargo install -f rustup-toolchain-install-master + run: cargo install -f rustup-toolchain-install-master hyperfine - name: Install miri toolchain run: | @@ -85,7 +85,7 @@ jobs: name: style checks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # This is exactly duplicated from above. GHA is pretty terrible when it comes # to avoiding code duplication. @@ -165,7 +165,7 @@ jobs: name: cronjob failure notification runs-on: ubuntu-latest needs: [build, style] - if: github.event_name == 'schedule' && (failure() || cancelled()) + if: github.event_name == 'schedule' && failure() steps: # Send a Zulip notification - name: Install zulip-send @@ -191,7 +191,7 @@ jobs: The Miri Cronjobs Bot' # Attempt to auto-sync with rustc - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 256 # get a bit more of the history - name: install josh-proxy diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 4fb479e1c54..293b937a5e5 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -38,6 +38,21 @@ dependencies = [ ] [[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] name = "annotate-snippets" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -107,6 +122,12 @@ dependencies = [ ] [[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] name = "camino" version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -151,6 +172,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.3", +] + +[[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -217,6 +250,12 @@ dependencies = [ ] [[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] name = "cpufeatures" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -261,6 +300,27 @@ dependencies = [ ] [[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -320,6 +380,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] name = "indenter" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -373,6 +456,15 @@ dependencies = [ ] [[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -420,6 +512,16 @@ dependencies = [ ] [[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.4.2", + "libc", +] + +[[package]] name = "linux-raw-sys" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -484,8 +586,10 @@ name = "miri" version = "0.1.0" dependencies = [ "aes", + "chrono", "colored", "ctrlc", + "directories", "getrandom", "jemalloc-sys", "lazy_static", @@ -513,6 +617,15 @@ dependencies = [ ] [[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] name = "number_prefix" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -534,6 +647,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] name = "owo-colors" version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -666,6 +785,17 @@ dependencies = [ ] [[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] name = "regex" version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -965,6 +1095,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -987,6 +1171,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.3", +] + +[[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 9d24d3c6f47..b00dae784d2 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -24,6 +24,8 @@ smallvec = "1.7" aes = { version = "0.8.3", features = ["hazmat"] } measureme = "11" ctrlc = "3.2.5" +chrono = { version = "0.4.38", default-features = false, features = ["clock"] } +directories = "5" # Copied from `compiler/rustc/Cargo.toml`. # But only for some targets, it fails for others. Rustc configures this in its CI, but we can't diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 4254b9bb67d..ef01ca25fb0 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -321,6 +321,10 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-env-forward=<var>` forwards the `var` environment variable to the interpreted program. Can be used multiple times to forward several variables. Execution will still be deterministic if the value of forwarded variables stays the same. Has no effect if `-Zmiri-disable-isolation` is set. +* `-Zmiri-env-set=<var>=<value>` sets the `var` environment variable to `value` in the interpreted program. + It can be used to pass environment variables without needing to alter the host environment. It can + be used multiple times to set several variables. If `-Zmiri-disable-isolation` or `-Zmiri-env-forward` + is set, values set with this option will have priority over values from the host environment. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-isolation-error=<action>` configures Miri's response to operations @@ -560,7 +564,8 @@ used according to their aliasing restrictions. ## Bugs found by Miri -Miri has already found a number of bugs in the Rust standard library and beyond, which we collect here. +Miri has already found a number of bugs in the Rust standard library and beyond, some of which we collect here. +If Miri helped you find a subtle UB bug in your code, we'd appreciate a PR adding it to the list! Definite bugs found: @@ -595,6 +600,7 @@ Definite bugs found: * [Deallocating with the wrong layout in new specializations for in-place `Iterator::collect`](https://github.com/rust-lang/rust/pull/118460) * [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138) * [Occasional memory leak in `std::mpsc` channels](https://github.com/rust-lang/rust/issues/121582) (original code in [crossbeam](https://github.com/crossbeam-rs/crossbeam/pull/1084)) +* [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index f8ba612750e..c1ffb80783e 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -78,8 +78,8 @@ function run_tests { done fi if [ -n "${TEST_BENCH-}" ]; then - # Check that the benchmarks build and run, but without actually benchmarking. - time HYPERFINE="'$BASH' -c" ./miri bench + # Check that the benchmarks build and run, but only once. + time HYPERFINE="hyperfine -w0 -r1" ./miri bench fi ## test-cargo-miri @@ -128,16 +128,18 @@ function run_tests_minimal { ## Main Testing Logic ## # In particular, fully cover all tier 1 targets. +# We also want to run the many-seeds tests on all tier 1 targets. case $HOST_TARGET in x86_64-unknown-linux-gnu) # Host GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 - MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests - MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests - MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests + # With reduced many-seed count to avoid spending too much time on that. + # (All OSes are run with 64 seeds at least once though via the macOS runner.) + MANY_SEEDS=16 MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests + MANY_SEEDS=16 MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests + MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-apple-darwin run_tests + MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests # Extra tier 2 MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests @@ -155,13 +157,15 @@ case $HOST_TARGET in # Host (tier 2) GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 - MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests + MANY_SEEDS=64 MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests + MANY_SEEDS=64 MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests # Extra tier 2 MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture ;; i686-pc-windows-msvc) # Host - # Only smoke-test `many-seeds`; 64 runs take 15min here! + # Only smoke-test `many-seeds`; 64 runs of just the scoped-thread-leak test take 15min here! + # See <https://github.com/rust-lang/miri/issues/3509>. GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=1 TEST_BENCH=1 run_tests # Extra tier 1 # We really want to ensure a Linux target works on a Windows host, diff --git a/src/tools/miri/clippy.toml b/src/tools/miri/clippy.toml new file mode 100644 index 00000000000..284e18a45a3 --- /dev/null +++ b/src/tools/miri/clippy.toml @@ -0,0 +1 @@ +arithmetic-side-effects-allowed = ["rustc_target::abi::Size"] diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index aaa788d5846..79d0b13600d 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -8,7 +8,9 @@ version = "0.1.0" default-run = "miri-script" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace] +# We make this a workspace root so that cargo does not go looking in ../Cargo.toml for the workspace root. +# This is needed to make this package build on stable when the parent package uses unstable cargo features. [dependencies] which = "4.4" diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index a60acf44a40..a6433a8e286 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -c8d19a92aa9022eb690899cf6d54fd23cb6877e5 +cb3752d20e0f5d24348062211102a08d46fbecff diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 0070d1f3ebc..44201cb89ae 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -506,6 +506,11 @@ fn main() { ); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { miri_config.forwarded_env_vars.push(param.to_owned()); + } else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") { + let Some((name, value)) = param.split_once('=') else { + show_error!("-Zmiri-env-set requires an argument of the form <name>=<value>"); + }; + miri_config.set_env_vars.insert(name.to_owned(), value.to_owned()); } else if let Some(param) = arg.strip_prefix("-Zmiri-track-pointer-tag=") { let ids: Vec<u64> = parse_comma_list(param).unwrap_or_else(|err| { show_error!("-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {err}") diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index bebd14d2f1e..55ff09c53fe 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -248,7 +248,7 @@ impl<'tcx> Stack { #[cfg(feature = "stack-cache")] fn find_granting_cache(&mut self, access: AccessKind, tag: BorTag) -> Option<usize> { // This looks like a common-sense optimization; we're going to do a linear search of the - // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule + // cache or the borrow stack to scan the shorter of the two. This optimization is minuscule // and this check actually ensures we do not access an invalid cache. // When a stack is created and when items are removed from the top of the borrow stack, we // need some valid value to populate the cache. In both cases, we try to use the bottom diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 2281609a049..f2bec972b18 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -847,6 +847,7 @@ impl VClockAlloc { kind: MemoryKind, current_span: Span, ) -> VClockAlloc { + // Determine the thread that did the allocation, and when it did it. let (alloc_timestamp, alloc_index) = match kind { // User allocated and stack memory should track allocation. MemoryKind::Machine( @@ -858,13 +859,13 @@ impl VClockAlloc { | MiriMemoryKind::Mmap, ) | MemoryKind::Stack => { - let (alloc_index, clocks) = global.current_thread_state(thread_mgr); + let (alloc_index, clocks) = global.active_thread_state(thread_mgr); let mut alloc_timestamp = clocks.clock[alloc_index]; alloc_timestamp.span = current_span; (alloc_timestamp, alloc_index) } // Other global memory should trace races but be allocated at the 0 timestamp - // (conceptually they are allocated before everything). + // (conceptually they are allocated on the main thread before everything). MemoryKind::Machine( MiriMemoryKind::Global | MiriMemoryKind::Machine @@ -872,7 +873,8 @@ impl VClockAlloc { | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls, ) - | MemoryKind::CallerLocation => (VTimestamp::ZERO, VectorIdx::MAX_INDEX), + | MemoryKind::CallerLocation => + (VTimestamp::ZERO, global.thread_index(ThreadId::MAIN_THREAD)), }; VClockAlloc { alloc_ranges: RefCell::new(RangeMap::new( @@ -930,7 +932,7 @@ impl VClockAlloc { ptr_dbg: Pointer<AllocId>, ty: Option<Ty<'_>>, ) -> InterpResult<'tcx> { - let (current_index, current_clocks) = global.current_thread_state(thread_mgr); + let (active_index, active_clocks) = global.active_thread_state(thread_mgr); let mut other_size = None; // if `Some`, this was a size-mismatch race let write_clock; let (other_access, other_thread, other_clock) = @@ -939,30 +941,30 @@ impl VClockAlloc { // we are reporting races between two non-atomic reads. if !access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && - let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) + let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock) { (AccessType::AtomicStore, idx, &atomic.write_vector) } else if !access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && - let Some(idx) = Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) + let Some(idx) = Self::find_gt_index(&atomic.read_vector, &active_clocks.clock) { (AccessType::AtomicLoad, idx, &atomic.read_vector) // Then check races with non-atomic writes/reads. - } else if mem_clocks.write.1 > current_clocks.clock[mem_clocks.write.0] { + } else if mem_clocks.write.1 > active_clocks.clock[mem_clocks.write.0] { write_clock = mem_clocks.write(); (AccessType::NaWrite(mem_clocks.write_type), mem_clocks.write.0, &write_clock) - } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, ¤t_clocks.clock) { + } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &active_clocks.clock) { (AccessType::NaRead(mem_clocks.read[idx].read_type()), idx, &mem_clocks.read) // Finally, mixed-size races. } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size { // This is only a race if we are not synchronized with all atomic accesses, so find // the one we are not synchronized with. other_size = Some(atomic.size); - if let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) + if let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock) { (AccessType::AtomicStore, idx, &atomic.write_vector) } else if let Some(idx) = - Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) + Self::find_gt_index(&atomic.read_vector, &active_clocks.clock) { (AccessType::AtomicLoad, idx, &atomic.read_vector) } else { @@ -975,7 +977,7 @@ impl VClockAlloc { }; // Load elaborated thread information about the racing thread actions. - let current_thread_info = global.print_thread_metadata(thread_mgr, current_index); + let active_thread_info = global.print_thread_metadata(thread_mgr, active_index); let other_thread_info = global.print_thread_metadata(thread_mgr, other_thread); let involves_non_atomic = !access.is_atomic() || !other_access.is_atomic(); @@ -1003,8 +1005,8 @@ impl VClockAlloc { }, op2: RacingOp { action: access.description(ty, other_size.map(|_| access_size)), - thread_info: current_thread_info, - span: current_clocks.clock.as_slice()[current_index.index()].span_data(), + thread_info: active_thread_info, + span: active_clocks.clock.as_slice()[active_index.index()].span_data(), }, }))? } @@ -1026,7 +1028,7 @@ impl VClockAlloc { let current_span = machine.current_span(); let global = machine.data_race.as_ref().unwrap(); if global.race_detecting() { - let (index, mut thread_clocks) = global.current_thread_state_mut(&machine.threads); + let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (mem_clocks_range, mem_clocks) in alloc_ranges.iter_mut(access_range.start, access_range.size) @@ -1069,7 +1071,7 @@ impl VClockAlloc { let current_span = machine.current_span(); let global = machine.data_race.as_mut().unwrap(); if global.race_detecting() { - let (index, mut thread_clocks) = global.current_thread_state_mut(&machine.threads); + let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); for (mem_clocks_range, mem_clocks) in self.alloc_ranges.get_mut().iter_mut(access_range.start, access_range.size) { @@ -1454,7 +1456,7 @@ impl GlobalState { // Setup the main-thread since it is not explicitly created: // uses vector index and thread-id 0. let index = global_state.vector_clocks.get_mut().push(ThreadClockSet::default()); - global_state.vector_info.get_mut().push(ThreadId::new(0)); + global_state.vector_info.get_mut().push(ThreadId::MAIN_THREAD); global_state .thread_info .get_mut() @@ -1518,7 +1520,7 @@ impl GlobalState { thread: ThreadId, current_span: Span, ) { - let current_index = self.current_index(thread_mgr); + let current_index = self.active_thread_index(thread_mgr); // Enable multi-threaded execution, there are now at least two threads // so data-races are now possible. @@ -1642,7 +1644,7 @@ impl GlobalState { /// `thread_joined`. #[inline] pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>, current_span: Span) { - let current_index = self.current_index(thread_mgr); + let current_index = self.active_thread_index(thread_mgr); // Increment the clock to a unique termination timestamp. let vector_clocks = self.vector_clocks.get_mut(); @@ -1680,9 +1682,9 @@ impl GlobalState { op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx, bool>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { - let (index, clocks) = self.current_thread_state_mut(thread_mgr); + let (index, clocks) = self.active_thread_state_mut(thread_mgr); if op(index, clocks)? { - let (_, mut clocks) = self.current_thread_state_mut(thread_mgr); + let (_, mut clocks) = self.active_thread_state_mut(thread_mgr); clocks.increment_clock(index, current_span); } } @@ -1725,13 +1727,15 @@ impl GlobalState { Ref::map(clocks, |c| &c.clock) } + fn thread_index(&self, thread: ThreadId) -> VectorIdx { + self.thread_info.borrow()[thread].vector_index.expect("thread has no assigned vector") + } + /// Load the vector index used by the given thread as well as the set of vector clocks /// used by the thread. #[inline] fn thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { - let index = self.thread_info.borrow()[thread] - .vector_index - .expect("Loading thread state for thread with no assigned vector"); + let index = self.thread_index(thread); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); (index, clocks) @@ -1741,9 +1745,7 @@ impl GlobalState { /// used by the thread. #[inline] fn thread_state(&self, thread: ThreadId) -> (VectorIdx, Ref<'_, ThreadClockSet>) { - let index = self.thread_info.borrow()[thread] - .vector_index - .expect("Loading thread state for thread with no assigned vector"); + let index = self.thread_index(thread); let ref_vector = self.vector_clocks.borrow(); let clocks = Ref::map(ref_vector, |vec| &vec[index]); (index, clocks) @@ -1752,7 +1754,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector. #[inline] - pub(super) fn current_thread_state( + pub(super) fn active_thread_state( &self, thread_mgr: &ThreadManager<'_, '_>, ) -> (VectorIdx, Ref<'_, ThreadClockSet>) { @@ -1762,7 +1764,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector mutably for modification. #[inline] - pub(super) fn current_thread_state_mut( + pub(super) fn active_thread_state_mut( &self, thread_mgr: &ThreadManager<'_, '_>, ) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { @@ -1772,22 +1774,20 @@ impl GlobalState { /// Return the current thread, should be the same /// as the data-race active thread. #[inline] - fn current_index(&self, thread_mgr: &ThreadManager<'_, '_>) -> VectorIdx { + fn active_thread_index(&self, thread_mgr: &ThreadManager<'_, '_>) -> VectorIdx { let active_thread_id = thread_mgr.get_active_thread_id(); - self.thread_info.borrow()[active_thread_id] - .vector_index - .expect("active thread has no assigned vector") + self.thread_index(active_thread_id) } // SC ATOMIC STORE rule in the paper. pub(super) fn sc_write(&self, thread_mgr: &ThreadManager<'_, '_>) { - let (index, clocks) = self.current_thread_state(thread_mgr); + let (index, clocks) = self.active_thread_state(thread_mgr); self.last_sc_write.borrow_mut().set_at_index(&clocks.clock, index); } // SC ATOMIC READ rule in the paper. pub(super) fn sc_read(&self, thread_mgr: &ThreadManager<'_, '_>) { - let (.., mut clocks) = self.current_thread_state_mut(thread_mgr); + let (.., mut clocks) = self.active_thread_state_mut(thread_mgr); clocks.read_seqcst.join(&self.last_sc_fence.borrow()); } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 2fabd39a744..0116bd0281a 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -57,6 +57,8 @@ impl ThreadId { pub fn to_u32(self) -> u32 { self.0 } + + pub const MAIN_THREAD: ThreadId = ThreadId(0); } impl Idx for ThreadId { @@ -401,7 +403,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { // Create the main thread and add it to the list of threads. threads.push(Thread::new(Some("main"), None)); Self { - active_thread: ThreadId::new(0), + active_thread: ThreadId::MAIN_THREAD, threads, sync: SynchronizationState::default(), thread_local_alloc_ids: Default::default(), @@ -416,10 +418,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { ecx: &mut MiriInterpCx<'mir, 'tcx>, on_main_stack_empty: StackEmptyCallback<'mir, 'tcx>, ) { - ecx.machine.threads.threads[ThreadId::new(0)].on_stack_empty = Some(on_main_stack_empty); + ecx.machine.threads.threads[ThreadId::MAIN_THREAD].on_stack_empty = + Some(on_main_stack_empty); if ecx.tcx.sess.target.os.as_ref() != "windows" { // The main thread can *not* be joined on except on windows. - ecx.machine.threads.threads[ThreadId::new(0)].join_status = ThreadJoinStatus::Detached; + ecx.machine.threads.threads[ThreadId::MAIN_THREAD].join_status = + ThreadJoinStatus::Detached; } } diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index 2cd3d031b1e..c3496bc1a0c 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -13,15 +13,13 @@ use super::data_race::NaReadType; /// but in some cases one vector index may be shared with /// multiple thread ids if it's safe to do so. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct VectorIdx(u32); +pub(super) struct VectorIdx(u32); impl VectorIdx { #[inline(always)] - pub fn to_u32(self) -> u32 { + fn to_u32(self) -> u32 { self.0 } - - pub const MAX_INDEX: VectorIdx = VectorIdx(u32::MAX); } impl Idx for VectorIdx { @@ -51,7 +49,7 @@ const SMALL_VECTOR: usize = 4; /// a 32-bit unsigned integer which is the actual timestamp, and a `Span` /// so that diagnostics can report what code was responsible for an operation. #[derive(Clone, Copy, Debug)] -pub struct VTimestamp { +pub(super) struct VTimestamp { /// The lowest bit indicates read type, the rest is the time. /// `1` indicates a retag read, `0` a regular read. time_and_read_type: u32, @@ -87,7 +85,7 @@ impl VTimestamp { } #[inline] - pub fn read_type(&self) -> NaReadType { + pub(super) fn read_type(&self) -> NaReadType { if self.time_and_read_type & 1 == 0 { NaReadType::Read } else { NaReadType::Retag } } @@ -97,7 +95,7 @@ impl VTimestamp { } #[inline] - pub fn span_data(&self) -> SpanData { + pub(super) fn span_data(&self) -> SpanData { self.span.data() } } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 9ebb64afd35..574962c48d4 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -270,7 +270,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { ) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { - let (index, clocks) = global.current_thread_state(thread_mgr); + let (index, clocks) = global.active_thread_state(thread_mgr); store_elem.load_impl(index, &clocks, is_seqcst); } } @@ -289,7 +289,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { let (store_elem, recency) = { // The `clocks` we got here must be dropped before calling validate_atomic_load // as the race detector will update it - let (.., clocks) = global.current_thread_state(thread_mgr); + let (.., clocks) = global.active_thread_state(thread_mgr); // Load from a valid entry in the store buffer self.fetch_store(is_seqcst, &clocks, &mut *rng) }; @@ -300,7 +300,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // requires access to ThreadClockSet.clock, which is updated by the race detector validate()?; - let (index, clocks) = global.current_thread_state(thread_mgr); + let (index, clocks) = global.active_thread_state(thread_mgr); let loaded = store_elem.load_impl(index, &clocks, is_seqcst); Ok((loaded, recency)) } @@ -312,7 +312,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, ) -> InterpResult<'tcx> { - let (index, clocks) = global.current_thread_state(thread_mgr); + let (index, clocks) = global.active_thread_state(thread_mgr); self.store_impl(val, index, &clocks.clock, is_seqcst); Ok(()) @@ -520,7 +520,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: validate, )?; if global.track_outdated_loads && recency == LoadRecency::Outdated { - this.emit_diagnostic(NonHaltingDiagnostic::WeakMemoryOutdatedLoad); + this.emit_diagnostic(NonHaltingDiagnostic::WeakMemoryOutdatedLoad { + ptr: place.ptr(), + }); } return Ok(loaded); diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 0c0ac4c6036..9fa786332e3 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -125,7 +125,9 @@ pub enum NonHaltingDiagnostic { Int2Ptr { details: bool, }, - WeakMemoryOutdatedLoad, + WeakMemoryOutdatedLoad { + ptr: Pointer<Option<Provenance>>, + }, } /// Level of Miri specific diagnostics @@ -583,7 +585,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { | AccessedAlloc(..) | FreedAlloc(..) | ProgressReport { .. } - | WeakMemoryOutdatedLoad => ("tracking was triggered".to_string(), DiagLevel::Note), + | WeakMemoryOutdatedLoad { .. } => + ("tracking was triggered".to_string(), DiagLevel::Note), }; let msg = match &e { @@ -610,8 +613,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { ProgressReport { .. } => format!("progress report: current operation being executed is here"), Int2Ptr { .. } => format!("integer-to-pointer cast"), - WeakMemoryOutdatedLoad => - format!("weak memory emulation: outdated value returned from load"), + WeakMemoryOutdatedLoad { ptr } => + format!("weak memory emulation: outdated value returned from load at {ptr}"), }; let notes = match &e { diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 45dadb50f4b..2242768a568 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -9,7 +9,7 @@ use std::thread; use crate::concurrency::thread::TlsAllocAction; use crate::diagnostics::report_leaks; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::{ @@ -100,6 +100,8 @@ pub struct MiriConfig { pub ignore_leaks: bool, /// Environment variables that should always be forwarded from the host. pub forwarded_env_vars: Vec<String>, + /// Additional environment variables that should be set in the interpreted program. + pub set_env_vars: FxHashMap<String, String>, /// Command-line arguments passed to the interpreted program. pub args: Vec<String>, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). @@ -167,6 +169,7 @@ impl Default for MiriConfig { isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, forwarded_env_vars: vec![], + set_env_vars: FxHashMap::default(), args: vec![], seed: None, tracked_pointer_tags: FxHashSet::default(), @@ -383,10 +386,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_ptr = ecx.fn_ptr(FnVal::Instance(entry_instance)); - // Inlining of `DEFAULT` from - // https://github.com/rust-lang/rust/blob/master/compiler/rustc_session/src/config/sigpipe.rs. // Always using DEFAULT is okay since we don't support signals in Miri anyway. - let sigpipe = 2; + // (This means we are effectively ignoring `#[unix_sigpipe]`.) + let sigpipe = rustc_session::config::sigpipe::DEFAULT; ecx.call_function( start_instance, diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index e1c0da9118d..44727e01ea2 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -12,7 +12,6 @@ #![feature(let_chains)] #![feature(lint_reasons)] #![feature(trait_upcasting)] -#![feature(absolute_path)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index abfa7143a73..294ad50c33f 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -2,7 +2,7 @@ use crate::*; use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance, Ty}; -use rustc_span::{BytePos, Loc, Symbol}; +use rustc_span::{hygiene, BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} @@ -45,12 +45,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let mut data = Vec::new(); for frame in this.active_thread_stack().iter().rev() { - let mut span = frame.current_span(); - // Match the behavior of runtime backtrace spans - // by using a non-macro span in our backtrace. See `FunctionCx::debug_loc`. - if span.from_expansion() && !tcx.sess.opts.unstable_opts.debug_macros { - span = rustc_span::hygiene::walk_chain(span, frame.body.span.ctxt()) - } + // Match behavior of debuginfo (`FunctionCx::adjusted_span_and_dbg_scope`). + let span = hygiene::walk_chain_collapsed(frame.current_span(), frame.body.span); data.push((frame.instance, span.lo())); } diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 1779189c9ce..298fefdb0f3 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -44,21 +44,15 @@ impl<'tcx> EnvVars<'tcx> { let forward = ecx.machine.communicate() || config.forwarded_env_vars.iter().any(|v| **v == *name); if forward { - let var_ptr = match ecx.tcx.sess.target.os.as_ref() { - _ if ecx.target_os_is_unix() => - alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, - "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, - unsupported => - throw_unsup_format!( - "environment support for target OS `{}` not yet available", - unsupported - ), - }; - ecx.machine.env_vars.map.insert(name.clone(), var_ptr); + add_env_var(ecx, name, value)?; } } } + for (name, value) in &config.set_env_vars { + add_env_var(ecx, OsStr::new(name), OsStr::new(value))?; + } + // Initialize the `environ` pointer when needed. if ecx.target_os_is_unix() { // This is memory backing an extern static, hence `ExternStatic`, not `Env`. @@ -89,6 +83,24 @@ impl<'tcx> EnvVars<'tcx> { } } +fn add_env_var<'mir, 'tcx>( + ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + name: &OsStr, + value: &OsStr, +) -> InterpResult<'tcx, ()> { + let var_ptr = match ecx.tcx.sess.target.os.as_ref() { + _ if ecx.target_os_is_unix() => alloc_env_var_as_c_str(name, value, ecx)?, + "windows" => alloc_env_var_as_wide_str(name, value, ecx)?, + unsupported => + throw_unsup_format!( + "environment support for target OS `{}` not yet available", + unsupported + ), + }; + ecx.machine.env_vars.map.insert(name.to_os_string(), var_ptr); + Ok(()) +} + fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, @@ -148,10 +160,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.assert_target_os("windows", "GetEnvironmentVariableW"); let name_ptr = this.read_pointer(name_op)?; + let buf_ptr = this.read_pointer(buf_op)?; + let buf_size = this.read_scalar(size_op)?.to_u32()?; // in characters + let name = this.read_os_str_from_wide_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(&name) { Some(&var_ptr) => { - this.set_last_error(Scalar::from_u32(0))?; // make sure this is unambiguously not an error // The offset is used to strip the "{name}=" part of the string. #[rustfmt::skip] let name_offset_bytes = u64::try_from(name.len()).unwrap() @@ -160,14 +174,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let var_ptr = var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?; let var = this.read_os_str_from_wide_str(var_ptr)?; - let buf_ptr = this.read_pointer(buf_op)?; - // `buf_size` represents the size in characters. - let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); - Scalar::from_u32(windows_check_buffer_size( - this.write_os_str_to_wide_str( - &var, buf_ptr, buf_size, /*truncate*/ false, - )?, - )) + Scalar::from_u32(windows_check_buffer_size(this.write_os_str_to_wide_str( + &var, + buf_ptr, + buf_size.into(), + )?)) + // This can in fact return 0. It is up to the caller to set last_error to 0 + // beforehand and check it afterwards to exclude that case. } None => { let envvar_not_found = this.eval_windows("c", "ERROR_ENVVAR_NOT_FOUND"); @@ -363,9 +376,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // If we cannot get the current directory, we return 0 match env::current_dir() { Ok(cwd) => { - this.set_last_error(Scalar::from_u32(0))?; // make sure this is unambiguously not an error + // This can in fact return 0. It is up to the caller to set last_error to 0 + // beforehand and check it afterwards to exclude that case. return Ok(Scalar::from_u32(windows_check_buffer_size( - this.write_path_to_wide_str(&cwd, buf, size, /*truncate*/ false)?, + this.write_path_to_wide_str(&cwd, buf, size)?, ))); } Err(e) => this.set_last_error_from_io_error(e.kind())?, @@ -482,9 +496,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentProcessId"); - this.check_no_isolation("`GetCurrentProcessId`")?; Ok(std::process::id()) } + + #[allow(non_snake_case)] + fn GetUserProfileDirectoryW( + &mut self, + token: &OpTy<'tcx, Provenance>, // HANDLE + buf: &OpTy<'tcx, Provenance>, // LPWSTR + size: &OpTy<'tcx, Provenance>, // LPDWORD + ) -> InterpResult<'tcx, Scalar<Provenance>> // returns BOOL + { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetUserProfileDirectoryW"); + this.check_no_isolation("`GetUserProfileDirectoryW`")?; + + let token = this.read_target_isize(token)?; + let buf = this.read_pointer(buf)?; + let size = this.deref_pointer(size)?; + + if token != -4 { + throw_unsup_format!( + "GetUserProfileDirectoryW: only CURRENT_PROCESS_TOKEN is supported" + ); + } + + // See <https://learn.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getuserprofiledirectoryw> for docs. + Ok(match directories::UserDirs::new() { + Some(dirs) => { + let home = dirs.home_dir(); + let size_avail = if this.ptr_is_null(size.ptr())? { + 0 // if the buf pointer is null, we can't write to it; `size` will be updated to the required length + } else { + this.read_scalar(&size)?.to_u32()? + }; + // Of course we cannot use `windows_check_buffer_size` here since this uses + // a different method for dealing with a too-small buffer than the other functions... + let (success, len) = this.write_path_to_wide_str(home, buf, size_avail.into())?; + // The Windows docs just say that this is written on failure. But std + // seems to rely on it always being written. + this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?; + if success { + Scalar::from_i32(1) // return TRUE + } else { + this.set_last_error(this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER"))?; + Scalar::from_i32(0) // return FALSE + } + } + None => { + // We have to pick some error code. + this.set_last_error(this.eval_windows("c", "ERROR_BAD_USER_PROFILE"))?; + Scalar::from_i32(0) // return FALSE + } + }) + } } diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index 3e8c35d48ae..5fcea9ced69 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -72,11 +72,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { u16vec_to_osstring(u16_vec) } - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does include the null terminator. + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what the + /// Unix APIs usually handle. Returns `(success, full_len)`, where length includes the null + /// terminator. On failure, nothing is written. fn write_os_str_to_c_str( &mut self, os_str: &OsStr, @@ -87,19 +85,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { self.eval_context_mut().write_c_str(bytes, ptr, size) } - /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the - /// Windows APIs usually handle. - /// - /// If `truncate == false` (the usual mode of operation), this function returns `Ok((false, - /// length))` without trying to write if `size` is not large enough to fit the contents of - /// `os_string` plus a null terminator. It returns `Ok((true, length))` if the writing process - /// was successful. The string length returned does include the null terminator. Length is - /// measured in units of `u16.` - /// - /// If `truncate == true`, then in case `size` is not large enough it *will* write the first - /// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`). - /// The return value is still `(false, length)` in that case. - fn write_os_str_to_wide_str( + /// Internal helper to share code between `write_os_str_to_wide_str` and + /// `write_os_str_to_wide_str_truncated`. + fn write_os_str_to_wide_str_helper( &mut self, os_str: &OsStr, ptr: Pointer<Option<Provenance>>, @@ -133,6 +121,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok((written, size_needed)) } + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the + /// Windows APIs usually handle. Returns `(success, full_len)`, where length is measured + /// in units of `u16` and includes the null terminator. On failure, nothing is written. + fn write_os_str_to_wide_str( + &mut self, + os_str: &OsStr, + ptr: Pointer<Option<Provenance>>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ false) + } + + /// Like `write_os_str_to_wide_str`, but on failure as much as possible is written into + /// the buffer (always with a null terminator). + fn write_os_str_to_wide_str_truncated( + &mut self, + os_str: &OsStr, + ptr: Pointer<Option<Provenance>>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ true) + } + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. fn alloc_os_str_as_c_str( &mut self, @@ -160,9 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; - let (written, _) = self - .write_os_str_to_wide_str(os_str, arg_place.ptr(), size, /*truncate*/ false) - .unwrap(); + let (written, _) = self.write_os_str_to_wide_str(os_str, arg_place.ptr(), size).unwrap(); assert!(written); Ok(arg_place.ptr()) } @@ -217,12 +226,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { path: &Path, ptr: Pointer<Option<Provenance>>, size: u64, - truncate: bool, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_wide_str(&os_str, ptr, size, truncate) + this.write_os_str_to_wide_str(&os_str, ptr, size) + } + + /// Write a Path to the machine memory (as a null-terminated sequence of `u16`s), + /// adjusting path separators if needed. + fn write_path_to_wide_str_truncated( + &mut self, + path: &Path, + ptr: Pointer<Option<Provenance>>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let this = self.eval_context_mut(); + let os_str = + this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + this.write_os_str_to_wide_str_truncated(&os_str, ptr, size) } /// Allocate enough memory to store a Path as a null-terminated sequence of bytes, diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 1126c900226..dfdf58470d6 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -1,5 +1,9 @@ +use std::ffi::OsString; +use std::fmt::Write; use std::time::{Duration, SystemTime}; +use chrono::{DateTime, Datelike, Local, Timelike, Utc}; + use crate::concurrency::thread::MachineCallback; use crate::*; @@ -107,6 +111,80 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(0) } + // The localtime() function shall convert the time in seconds since the Epoch pointed to by + // timer into a broken-down time, expressed as a local time. + // https://linux.die.net/man/3/localtime_r + fn localtime_r( + &mut self, + timep: &OpTy<'tcx, Provenance>, + result_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + let this = self.eval_context_mut(); + + this.assert_target_os_is_unix("localtime_r"); + this.check_no_isolation("`localtime_r`")?; + + let timep = this.deref_pointer(timep)?; + let result = this.deref_pointer_as(result_op, this.libc_ty_layout("tm"))?; + + // The input "represents the number of seconds elapsed since the Epoch, + // 1970-01-01 00:00:00 +0000 (UTC)". + let sec_since_epoch: i64 = this + .read_scalar(&timep)? + .to_int(this.libc_ty_layout("time_t").size)? + .try_into() + .unwrap(); + let dt_utc: DateTime<Utc> = + DateTime::from_timestamp(sec_since_epoch, 0).expect("Invalid timestamp"); + // Convert that to local time, then return the broken-down time value. + let dt: DateTime<Local> = DateTime::from(dt_utc); + + // This value is always set to -1, because there is no way to know if dst is in effect with + // chrono crate yet. + // This may not be consistent with libc::localtime_r's result. + let tm_isdst = -1; + + // tm_zone represents the timezone value in the form of: +0730, +08, -0730 or -08. + // This may not be consistent with libc::localtime_r's result. + let offset_in_second = Local::now().offset().local_minus_utc(); + let tm_gmtoff = offset_in_second; + let mut tm_zone = String::new(); + if offset_in_second < 0 { + tm_zone.push('-'); + } else { + tm_zone.push('+'); + } + let offset_hour = offset_in_second.abs() / 3600; + write!(tm_zone, "{:02}", offset_hour).unwrap(); + let offset_min = (offset_in_second.abs() % 3600) / 60; + if offset_min != 0 { + write!(tm_zone, "{:02}", offset_min).unwrap(); + } + + // FIXME: String de-duplication is needed so that we only allocate this string only once + // even when there are multiple calls to this function. + let tm_zone_ptr = + this.alloc_os_str_as_c_str(&OsString::from(tm_zone), MiriMemoryKind::Machine.into())?; + + this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?; + this.write_int_fields_named( + &[ + ("tm_sec", dt.second().into()), + ("tm_min", dt.minute().into()), + ("tm_hour", dt.hour().into()), + ("tm_mday", dt.day().into()), + ("tm_mon", dt.month0().into()), + ("tm_year", dt.year().checked_sub(1900).unwrap().into()), + ("tm_wday", dt.weekday().num_days_from_sunday().into()), + ("tm_yday", dt.ordinal0().into()), + ("tm_isdst", tm_isdst), + ("tm_gmtoff", tm_gmtoff.into()), + ], + &result, + )?; + + Ok(result.ptr()) + } #[allow(non_snake_case, clippy::arithmetic_side_effects)] fn GetSystemTimeAsFileTime( &mut self, diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index c72d3bb3df4..bd299aaa125 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -234,6 +234,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "localtime_r" => { + let [timep, result_op] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?; + let result = this.localtime_r(timep, result_op)?; + this.write_pointer(result, dest)?; + } "clock_gettime" => { let [clk_id, tp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index ec2922d0275..3948216f729 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -23,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // old_address must be a multiple of the page size #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 { // We only support MREMAP_MAYMOVE, so not passing the flag is just a failure - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index d3470893dbb..f52dc23656d 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -53,11 +53,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // First, we do some basic argument validation as required by mmap if (flags & (map_private | map_shared)).count_ones() != 1 { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } if length == 0 { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // // Miri doesn't support MAP_FIXED or any any protections other than PROT_READ|PROT_WRITE. if flags & map_fixed != 0 || prot != prot_read | prot_write { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("ENOTSUP")))?; + this.set_last_error(this.eval_libc("ENOTSUP"))?; return Ok(this.eval_libc("MAP_FAILED")); } @@ -96,11 +96,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let align = this.machine.page_align(); let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); }; if map_length > this.target_usize_max() { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } @@ -131,16 +131,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // as a dealloc. #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if addr.addr().bytes() % this.machine.page_size != 0 { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(Scalar::from_i32(-1)); } let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(Scalar::from_i32(-1)); }; if length > this.target_usize_max() { - this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?; + this.set_last_error(this.eval_libc("EINVAL"))?; return Ok(this.eval_libc("MAP_FAILED")); } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index ec4c6101487..24f7cd18e7a 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -135,6 +135,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(result, dest)?; } + "GetUserProfileDirectoryW" => { + let [token, buf, size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let result = this.GetUserProfileDirectoryW(token, buf, size)?; + this.write_scalar(result, dest)?; + } // File related shims "NtWriteFile" => { @@ -225,15 +231,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Scalar::from_u32(0) // return zero upon failure } Ok(abs_filename) => { - this.set_last_error(Scalar::from_u32(0))?; // make sure this is unambiguously not an error Scalar::from_u32(helpers::windows_check_buffer_size( - this.write_path_to_wide_str( - &abs_filename, - buffer, - size.into(), - /*truncate*/ false, - )?, + this.write_path_to_wide_str(&abs_filename, buffer, size.into())?, )) + // This can in fact return 0. It is up to the caller to set last_error to 0 + // beforehand and check it afterwards to exclude that case. } }; this.write_scalar(result, dest)?; @@ -601,15 +603,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Using the host current_exe is a bit off, but consistent with Linux // (where stdlib reads /proc/self/exe). - // Unfortunately this Windows function has a crazy behavior so we can't just use - // `write_path_to_wide_str`... let path = std::env::current_exe().unwrap(); - let (all_written, size_needed) = this.write_path_to_wide_str( - &path, - filename, - size.into(), - /*truncate*/ true, - )?; + let (all_written, size_needed) = + this.write_path_to_wide_str_truncated(&path, filename, size.into())?; if all_written { // If the function succeeds, the return value is the length of the string that @@ -649,12 +645,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Some(err) => format!("{err}"), None => format!("<unknown error in FormatMessageW: {message_id}>"), }; - let (complete, length) = this.write_os_str_to_wide_str( - OsStr::new(&formatted), - buffer, - size.into(), - /*trunacte*/ false, - )?; + let (complete, length) = + this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?; if !complete { // The API docs don't say what happens when the buffer is not big enough... // Let's just bail. diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index 23c78647b9c..41c20d768f7 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -7,7 +7,8 @@ use rustc_target::spec::abi::Abi; use super::{ bin_op_simd_float_all, conditional_dot_product, convert_float_to_int, horizontal_bin_op, - round_all, test_bits_masked, test_high_bits_masked, unary_op_ps, FloatBinOp, FloatUnaryOp, + mask_load, mask_store, round_all, test_bits_masked, test_high_bits_masked, unary_op_ps, + FloatBinOp, FloatUnaryOp, }; use crate::*; use shims::foreign_items::EmulateForeignItemResult; @@ -347,71 +348,3 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: Ok(EmulateForeignItemResult::NeedsJumping) } } - -/// Conditionally loads from `ptr` according the high bit of each -/// element of `mask`. `ptr` does not need to be aligned. -fn mask_load<'tcx>( - this: &mut crate::MiriInterpCx<'_, 'tcx>, - ptr: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ()> { - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(dest_len, mask_len); - - let mask_item_size = mask.layout.field(this, 0).size; - let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); - - let ptr = this.read_pointer(ptr)?; - for i in 0..dest_len { - let mask = this.project_index(&mask, i)?; - let dest = this.project_index(&dest, i)?; - - if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { - // Size * u64 is implemented as always checked - #[allow(clippy::arithmetic_side_effects)] - let ptr = ptr.wrapping_offset(dest.layout.size * i, &this.tcx); - // Unaligned copy, which is what we want. - this.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; - } else { - this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; - } - } - - Ok(()) -} - -/// Conditionally stores into `ptr` according the high bit of each -/// element of `mask`. `ptr` does not need to be aligned. -fn mask_store<'tcx>( - this: &mut crate::MiriInterpCx<'_, 'tcx>, - ptr: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, - value: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ()> { - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (value, value_len) = this.operand_to_simd(value)?; - - assert_eq!(value_len, mask_len); - - let mask_item_size = mask.layout.field(this, 0).size; - let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); - - let ptr = this.read_pointer(ptr)?; - for i in 0..value_len { - let mask = this.project_index(&mask, i)?; - let value = this.project_index(&value, i)?; - - if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { - // Size * u64 is implemented as always checked - #[allow(clippy::arithmetic_side_effects)] - let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx); - // Unaligned copy, which is what we want. - this.mem_copy(value.ptr(), ptr, value.layout.size, /*nonoverlapping*/ true)?; - } - } - - Ok(()) -} diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs new file mode 100644 index 00000000000..bbf53f9f1e5 --- /dev/null +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -0,0 +1,444 @@ +use crate::rustc_middle::ty::layout::LayoutOf as _; +use rustc_middle::mir; +use rustc_middle::ty::Ty; +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use super::{ + horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb, packusdw, + packuswb, pmulhrsw, psign, shift_simd_by_scalar, shift_simd_by_simd, ShiftOp, +}; +use crate::*; +use shims::foreign_items::EmulateForeignItemResult; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: + crate::MiriInterpCxExt<'mir, 'tcx> +{ + fn emulate_x86_avx2_intrinsic( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx, Provenance>], + dest: &MPlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, EmulateForeignItemResult> { + let this = self.eval_context_mut(); + this.expect_target_feature_for_intrinsic(link_name, "avx2")?; + // Prefix should have already been checked. + let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.avx2.").unwrap(); + + match unprefixed_name { + // Used to implement the _mm256_abs_epi{8,16,32} functions. + // Calculates the absolute value of packed 8/16/32-bit integers. + "pabs.b" | "pabs.w" | "pabs.d" => { + let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + int_abs(this, op, dest)?; + } + // Used to implement the _mm256_h{add,adds,sub}_epi{16,32} functions. + // Horizontally add / add with saturation / subtract adjacent 16/32-bit + // integer values in `left` and `right`. + "phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (which, saturating) = match unprefixed_name { + "phadd.w" | "phadd.d" => (mir::BinOp::Add, false), + "phadd.sw" => (mir::BinOp::Add, true), + "phsub.w" | "phsub.d" => (mir::BinOp::Sub, false), + "phsub.sw" => (mir::BinOp::Sub, true), + _ => unreachable!(), + }; + + horizontal_bin_op(this, which, saturating, left, right, dest)?; + } + // Used to implement `_mm{,_mask}_{i32,i64}gather_{epi32,epi64,pd,ps}` functions + // Gathers elements from `slice` using `offsets * scale` as indices. + // When the highest bit of the corresponding element of `mask` is 0, + // the value is copied from `src` instead. + "gather.d.d" | "gather.d.d.256" | "gather.d.q" | "gather.d.q.256" | "gather.q.d" + | "gather.q.d.256" | "gather.q.q" | "gather.q.q.256" | "gather.d.pd" + | "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps" + | "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => { + let [src, slice, offsets, mask, scale] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + assert_eq!(dest.layout, src.layout); + + let (src, _) = this.operand_to_simd(src)?; + let (offsets, offsets_len) = this.operand_to_simd(offsets)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + // There are cases like dest: i32x4, offsets: i64x2 + let actual_len = dest_len.min(offsets_len); + + assert_eq!(dest_len, mask_len); + + let mask_item_size = mask.layout.field(this, 0).size; + let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + + let scale = this.read_scalar(scale)?.to_i8()?; + if !matches!(scale, 1 | 2 | 4 | 8) { + throw_unsup_format!("invalid gather scale {scale}"); + } + let scale = i64::from(scale); + + let slice = this.read_pointer(slice)?; + for i in 0..actual_len { + let mask = this.project_index(&mask, i)?; + let dest = this.project_index(&dest, i)?; + + if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + let offset = this.project_index(&offsets, i)?; + let offset = + i64::try_from(this.read_scalar(&offset)?.to_int(offset.layout.size)?) + .unwrap(); + let ptr = slice + .wrapping_signed_offset(offset.checked_mul(scale).unwrap(), &this.tcx); + // Unaligned copy, which is what we want. + this.mem_copy( + ptr, + dest.ptr(), + dest.layout.size, + /*nonoverlapping*/ true, + )?; + } else { + this.copy_op(&this.project_index(&src, i)?, &dest)?; + } + } + for i in actual_len..dest_len { + let dest = this.project_index(&dest, i)?; + this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; + } + } + // Used to implement the _mm256_madd_epi16 function. + // Multiplies packed signed 16-bit integers in `left` and `right`, producing + // intermediate signed 32-bit integers. Horizontally add adjacent pairs of + // intermediate 32-bit integers, and pack the results in `dest`. + "pmadd.wd" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(dest_len.checked_mul(2).unwrap(), left_len); + + for i in 0..dest_len { + let j1 = i.checked_mul(2).unwrap(); + let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?; + let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?; + + let j2 = j1.checked_add(1).unwrap(); + let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?; + let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?; + + let dest = this.project_index(&dest, i)?; + + // Multiplications are i16*i16->i32, which will not overflow. + let mul1 = i32::from(left1).checked_mul(right1.into()).unwrap(); + let mul2 = i32::from(left2).checked_mul(right2.into()).unwrap(); + // However, this addition can overflow in the most extreme case + // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000 + let res = mul1.wrapping_add(mul2); + + this.write_scalar(Scalar::from_i32(res), &dest)?; + } + } + // Used to implement the _mm256_maddubs_epi16 function. + // Multiplies packed 8-bit unsigned integers from `left` and packed + // signed 8-bit integers from `right` into 16-bit signed integers. Then, + // the saturating sum of the products with indices `2*i` and `2*i+1` + // produces the output at index `i`. + "pmadd.ub.sw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(dest_len.checked_mul(2).unwrap(), left_len); + + for i in 0..dest_len { + let j1 = i.checked_mul(2).unwrap(); + let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_u8()?; + let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i8()?; + + let j2 = j1.checked_add(1).unwrap(); + let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_u8()?; + let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i8()?; + + let dest = this.project_index(&dest, i)?; + + // Multiplication of a u8 and an i8 into an i16 cannot overflow. + let mul1 = i16::from(left1).checked_mul(right1.into()).unwrap(); + let mul2 = i16::from(left2).checked_mul(right2.into()).unwrap(); + let res = mul1.saturating_add(mul2); + + this.write_scalar(Scalar::from_i16(res), &dest)?; + } + } + // Used to implement the _mm_maskload_epi32, _mm_maskload_epi64, + // _mm256_maskload_epi32 and _mm256_maskload_epi64 functions. + // For the element `i`, if the high bit of the `i`-th element of `mask` + // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is + // loaded. + "maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => { + let [ptr, mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + mask_load(this, ptr, mask, dest)?; + } + // Used to implement the _mm_maskstore_epi32, _mm_maskstore_epi64, + // _mm256_maskstore_epi32 and _mm256_maskstore_epi64 functions. + // For the element `i`, if the high bit of the element `i`-th of `mask` + // is one, it is stored into `ptr.wapping_add(i)`. + // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores. + "maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => { + let [ptr, mask, value] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + mask_store(this, ptr, mask, value)?; + } + // Used to implement the _mm256_mpsadbw_epu8 function. + // Compute the sum of absolute differences of quadruplets of unsigned + // 8-bit integers in `left` and `right`, and store the 16-bit results + // in `right`. Quadruplets are selected from `left` and `right` with + // offsets specified in `imm`. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8 + "mpsadbw" => { + let [left, right, imm] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + mpsadbw(this, left, right, imm, dest)?; + } + // Used to implement the _mm256_mulhrs_epi16 function. + // Multiplies packed 16-bit signed integer values, truncates the 32-bit + // product to the 18 most significant bits by right-shifting, and then + // divides the 18-bit value by 2 (rounding to nearest) by first adding + // 1 and then taking the bits `1..=16`. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16 + "pmul.hr.sw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + pmulhrsw(this, left, right, dest)?; + } + // Used to implement the _mm256_packs_epi16 function. + // Converts two 16-bit integer vectors to a single 8-bit integer + // vector with signed saturation. + "packsswb" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + packsswb(this, left, right, dest)?; + } + // Used to implement the _mm256_packs_epi32 function. + // Converts two 32-bit integer vectors to a single 16-bit integer + // vector with signed saturation. + "packssdw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + packssdw(this, left, right, dest)?; + } + // Used to implement the _mm256_packus_epi16 function. + // Converts two 16-bit signed integer vectors to a single 8-bit + // unsigned integer vector with saturation. + "packuswb" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + packuswb(this, left, right, dest)?; + } + // Used to implement the _mm256_packus_epi32 function. + // Concatenates two 32-bit signed integer vectors and converts + // the result to a 16-bit unsigned integer vector with saturation. + "packusdw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + packusdw(this, left, right, dest)?; + } + // Used to implement the _mm256_permutevar8x32_epi32 and + // _mm256_permutevar8x32_ps function. + // Shuffles `left` using the three low bits of each element of `right` + // as indices. + "permd" | "permps" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let dest = this.project_index(&dest, i)?; + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u32()?; + let left = this.project_index(&left, (right & 0b111).into())?; + + this.copy_op(&left, &dest)?; + } + } + // Used to implement the _mm256_permute2x128_si256 function. + // Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern. + "vperm2i128" => { + let [left, right, imm] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + assert_eq!(left.layout.size.bits(), 256); + assert_eq!(right.layout.size.bits(), 256); + assert_eq!(dest.layout.size.bits(), 256); + + // Transmute to `[i128; 2]` + + let array_layout = + this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.i128, 2))?; + let left = left.transmute(array_layout, this)?; + let right = right.transmute(array_layout, this)?; + let dest = dest.transmute(array_layout, this)?; + + let imm = this.read_scalar(imm)?.to_u8()?; + + for i in 0..2 { + let dest = this.project_index(&dest, i)?; + let src = match (imm >> i.checked_mul(4).unwrap()) & 0b11 { + 0 => this.project_index(&left, 0)?, + 1 => this.project_index(&left, 1)?, + 2 => this.project_index(&right, 0)?, + 3 => this.project_index(&right, 1)?, + _ => unreachable!(), + }; + + this.copy_op(&src, &dest)?; + } + } + // Used to implement the _mm256_sad_epu8 function. + // Compute the absolute differences of packed unsigned 8-bit integers + // in `left` and `right`, then horizontally sum each consecutive 8 + // differences to produce four unsigned 16-bit integers, and pack + // these unsigned 16-bit integers in the low 16 bits of 64-bit elements + // in `dest`. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8 + "psad.bw" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(left_len, dest_len.checked_mul(8).unwrap()); + + for i in 0..dest_len { + let dest = this.project_index(&dest, i)?; + + let mut acc: u16 = 0; + for j in 0..8 { + let src_index = i.checked_mul(8).unwrap().checked_add(j).unwrap(); + + let left = this.project_index(&left, src_index)?; + let left = this.read_scalar(&left)?.to_u8()?; + + let right = this.project_index(&right, src_index)?; + let right = this.read_scalar(&right)?.to_u8()?; + + acc = acc.checked_add(left.abs_diff(right).into()).unwrap(); + } + + this.write_scalar(Scalar::from_u64(acc.into()), &dest)?; + } + } + // Used to implement the _mm256_shuffle_epi8 intrinsic. + // Shuffles bytes from `left` using `right` as pattern. + // Each 128-bit block is shuffled independently. + "pshuf.b" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?; + let dest = this.project_index(&dest, i)?; + + let res = if right & 0x80 == 0 { + // Shuffle each 128-bit (16-byte) block independently. + let j = u64::from(right % 16).checked_add(i & !15).unwrap(); + this.read_scalar(&this.project_index(&left, j)?)? + } else { + // If the highest bit in `right` is 1, write zero. + Scalar::from_u8(0) + }; + + this.write_scalar(res, &dest)?; + } + } + // Used to implement the _mm256_sign_epi{8,16,32} functions. + // Negates elements from `left` when the corresponding element in + // `right` is negative. If an element from `right` is zero, zero + // is writen to the corresponding output element. + // Basically, we multiply `left` with `right.signum()`. + "psign.b" | "psign.w" | "psign.d" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + psign(this, left, right, dest)?; + } + // Used to implement the _mm256_{sll,srl,sra}_epi{16,32,64} functions + // (except _mm256_sra_epi64, which is not available in AVX2). + // Shifts N-bit packed integers in left by the amount in right. + // `right` is as 128-bit vector. but it is interpreted as a single + // 64-bit integer (remaining bits are ignored). + // For logic shifts, when right is larger than N - 1, zero is produced. + // For arithmetic shifts, when right is larger than N - 1, the sign bit + // is copied to remaining bits. + "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" + | "psrl.q" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let which = match unprefixed_name { + "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, + "psrl.w" | "psrl.d" | "psrl.q" => ShiftOp::RightLogic, + "psra.w" | "psra.d" => ShiftOp::RightArith, + _ => unreachable!(), + }; + + shift_simd_by_scalar(this, left, right, which, dest)?; + } + // Used to implement the _mm{,256}_{sllv,srlv,srav}_epi{32,64} functions + // (except _mm{,256}_srav_epi64, which are not available in AVX2). + "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256" + | "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let which = match unprefixed_name { + "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left, + "psrlv.d" | "psrlv.d.256" | "psrlv.q" | "psrlv.q.256" => ShiftOp::RightLogic, + "psrav.d" | "psrav.d.256" => ShiftOp::RightArith, + _ => unreachable!(), + }; + + shift_simd_by_simd(this, left, right, which, dest)?; + } + _ => return Ok(EmulateForeignItemResult::NotSupported), + } + Ok(EmulateForeignItemResult::NeedsJumping) + } +} diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 615821b2e37..cf4d6a04bec 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -14,6 +14,7 @@ use shims::foreign_items::EmulateForeignItemResult; mod aesni; mod avx; +mod avx2; mod sse; mod sse2; mod sse3; @@ -136,6 +137,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this, link_name, abi, args, dest, ); } + name if name.starts_with("avx2.") => { + return avx2::EvalContextExt::emulate_x86_avx2_intrinsic( + this, link_name, abi, args, dest, + ); + } _ => return Ok(EmulateForeignItemResult::NotSupported), } @@ -482,7 +488,7 @@ enum ShiftOp { /// /// For logic shifts, when right is larger than BITS - 1, zero is produced. /// For arithmetic right-shifts, when right is larger than BITS - 1, the sign -/// bit is copied to remaining bits. +/// bit is copied to all bits. fn shift_simd_by_scalar<'tcx>( this: &mut crate::MiriInterpCx<'_, 'tcx>, left: &OpTy<'tcx, Provenance>, @@ -534,6 +540,61 @@ fn shift_simd_by_scalar<'tcx>( Ok(()) } +/// Shifts each element of `left` by the corresponding element of `right`. +/// +/// For logic shifts, when right is larger than BITS - 1, zero is produced. +/// For arithmetic right-shifts, when right is larger than BITS - 1, the sign +/// bit is copied to all bits. +fn shift_simd_by_simd<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + which: ShiftOp, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let left = this.read_scalar(&this.project_index(&left, i)?)?; + let right = this.read_scalar(&this.project_index(&right, i)?)?; + let dest = this.project_index(&dest, i)?; + + // It is ok to saturate the value to u32::MAX because any value + // above BITS - 1 will produce the same result. + let shift = u32::try_from(right.to_uint(dest.layout.size)?).unwrap_or(u32::MAX); + + let res = match which { + ShiftOp::Left => { + let left = left.to_uint(dest.layout.size)?; + let res = left.checked_shl(shift).unwrap_or(0); + // `truncate` is needed as left-shift can make the absolute value larger. + Scalar::from_uint(dest.layout.size.truncate(res), dest.layout.size) + } + ShiftOp::RightLogic => { + let left = left.to_uint(dest.layout.size)?; + let res = left.checked_shr(shift).unwrap_or(0); + // No `truncate` needed as right-shift can only make the absolute value smaller. + Scalar::from_uint(res, dest.layout.size) + } + ShiftOp::RightArith => { + let left = left.to_int(dest.layout.size)?; + // On overflow, copy the sign bit to the remaining bits + let res = left.checked_shr(shift).unwrap_or(left >> 127); + // No `truncate` needed as right-shift can only make the absolute value smaller. + Scalar::from_int(res, dest.layout.size) + } + }; + this.write_scalar(res, &dest)?; + } + + Ok(()) +} + /// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts /// the first value. fn extract_first_u64<'tcx>( @@ -650,7 +711,7 @@ fn convert_float_to_int<'tcx>( let dest = this.project_index(&dest, i)?; let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { - // Fallback to minimum acording to SSE/AVX semantics. + // Fallback to minimum according to SSE/AVX semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); this.write_immediate(*res, &dest)?; @@ -664,6 +725,33 @@ fn convert_float_to_int<'tcx>( Ok(()) } +/// Calculates absolute value of integers in `op` and stores the result in `dest`. +/// +/// In case of overflow (when the operand is the minimum value), the operation +/// will wrap around. +fn int_abs<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + op: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(op_len, dest_len); + + for i in 0..dest_len { + let op = this.read_scalar(&this.project_index(&op, i)?)?; + let dest = this.project_index(&dest, i)?; + + // Converting to a host "i128" works since the input is always signed. + let res = op.to_int(dest.layout.size)?.unsigned_abs(); + + this.write_scalar(Scalar::from_uint(res, dest.layout.size), &dest)?; + } + + Ok(()) +} + /// Splits `op` (which must be a SIMD vector) into 128-bit chuncks. /// /// Returns a tuple where: @@ -874,3 +962,316 @@ fn test_high_bits_masked<'tcx>( Ok((direct, negated)) } + +/// Conditionally loads from `ptr` according the high bit of each +/// element of `mask`. `ptr` does not need to be aligned. +fn mask_load<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + ptr: &OpTy<'tcx, Provenance>, + mask: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, mask_len); + + let mask_item_size = mask.layout.field(this, 0).size; + let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + + let ptr = this.read_pointer(ptr)?; + for i in 0..dest_len { + let mask = this.project_index(&mask, i)?; + let dest = this.project_index(&dest, i)?; + + if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + let ptr = ptr.wrapping_offset(dest.layout.size * i, &this.tcx); + // Unaligned copy, which is what we want. + this.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; + } else { + this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; + } + } + + Ok(()) +} + +/// Conditionally stores into `ptr` according the high bit of each +/// element of `mask`. `ptr` does not need to be aligned. +fn mask_store<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + ptr: &OpTy<'tcx, Provenance>, + mask: &OpTy<'tcx, Provenance>, + value: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (value, value_len) = this.operand_to_simd(value)?; + + assert_eq!(value_len, mask_len); + + let mask_item_size = mask.layout.field(this, 0).size; + let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap(); + + let ptr = this.read_pointer(ptr)?; + for i in 0..value_len { + let mask = this.project_index(&mask, i)?; + let value = this.project_index(&value, i)?; + + if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx); + // Unaligned copy, which is what we want. + this.mem_copy(value.ptr(), ptr, value.layout.size, /*nonoverlapping*/ true)?; + } + } + + Ok(()) +} + +/// Compute the sum of absolute differences of quadruplets of unsigned +/// 8-bit integers in `left` and `right`, and store the 16-bit results +/// in `right`. Quadruplets are selected from `left` and `right` with +/// offsets specified in `imm`. +/// +/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_epi16> +/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8> +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn mpsadbw<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + imm: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + assert_eq!(left.layout, right.layout); + assert_eq!(left.layout.size, dest.layout.size); + + let (num_chunks, op_items_per_chunk, left) = split_simd_to_128bit_chunks(this, left)?; + let (_, _, right) = split_simd_to_128bit_chunks(this, right)?; + let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?; + + assert_eq!(op_items_per_chunk, dest_items_per_chunk.checked_mul(2).unwrap()); + + let imm = this.read_scalar(imm)?.to_uint(imm.layout.size)?; + // Bit 2 of `imm` specifies the offset for indices of `left`. + // The offset is 0 when the bit is 0 or 4 when the bit is 1. + let left_offset = u64::try_from((imm >> 2) & 1).unwrap().checked_mul(4).unwrap(); + // Bits 0..=1 of `imm` specify the offset for indices of + // `right` in blocks of 4 elements. + let right_offset = u64::try_from(imm & 0b11).unwrap().checked_mul(4).unwrap(); + + for i in 0..num_chunks { + let left = this.project_index(&left, i)?; + let right = this.project_index(&right, i)?; + let dest = this.project_index(&dest, i)?; + + for j in 0..dest_items_per_chunk { + let left_offset = left_offset.checked_add(j).unwrap(); + let mut res: u16 = 0; + for k in 0..4 { + let left = this + .read_scalar(&this.project_index(&left, left_offset.checked_add(k).unwrap())?)? + .to_u8()?; + let right = this + .read_scalar( + &this.project_index(&right, right_offset.checked_add(k).unwrap())?, + )? + .to_u8()?; + res = res.checked_add(left.abs_diff(right).into()).unwrap(); + } + this.write_scalar(Scalar::from_u16(res), &this.project_index(&dest, j)?)?; + } + } + + Ok(()) +} + +/// Multiplies packed 16-bit signed integer values, truncates the 32-bit +/// product to the 18 most significant bits by right-shifting, and then +/// divides the 18-bit value by 2 (rounding to nearest) by first adding +/// 1 and then taking the bits `1..=16`. +/// +/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16> +/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16> +fn pmulhrsw<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?; + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; + let dest = this.project_index(&dest, i)?; + + let res = + (i32::from(left).checked_mul(right.into()).unwrap() >> 14).checked_add(1).unwrap() >> 1; + + // The result of this operation can overflow a signed 16-bit integer. + // When `left` and `right` are -0x8000, the result is 0x8000. + #[allow(clippy::cast_possible_truncation)] + let res = res as i16; + + this.write_scalar(Scalar::from_i16(res), &dest)?; + } + + Ok(()) +} + +fn pack_generic<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, + f: impl Fn(Scalar<Provenance>) -> InterpResult<'tcx, Scalar<Provenance>>, +) -> InterpResult<'tcx, ()> { + assert_eq!(left.layout, right.layout); + assert_eq!(left.layout.size, dest.layout.size); + + let (num_chunks, op_items_per_chunk, left) = split_simd_to_128bit_chunks(this, left)?; + let (_, _, right) = split_simd_to_128bit_chunks(this, right)?; + let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?; + + assert_eq!(dest_items_per_chunk, op_items_per_chunk.checked_mul(2).unwrap()); + + for i in 0..num_chunks { + let left = this.project_index(&left, i)?; + let right = this.project_index(&right, i)?; + let dest = this.project_index(&dest, i)?; + + for j in 0..op_items_per_chunk { + let left = this.read_scalar(&this.project_index(&left, j)?)?; + let right = this.read_scalar(&this.project_index(&right, j)?)?; + let left_dest = this.project_index(&dest, j)?; + let right_dest = + this.project_index(&dest, j.checked_add(op_items_per_chunk).unwrap())?; + + let left_res = f(left)?; + let right_res = f(right)?; + + this.write_scalar(left_res, &left_dest)?; + this.write_scalar(right_res, &right_dest)?; + } + } + + Ok(()) +} + +/// Converts two 16-bit integer vectors to a single 8-bit integer +/// vector with signed saturation. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn packsswb<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + pack_generic(this, left, right, dest, |op| { + let op = op.to_i16()?; + let res = i8::try_from(op).unwrap_or(if op < 0 { i8::MIN } else { i8::MAX }); + Ok(Scalar::from_i8(res)) + }) +} + +/// Converts two 16-bit signed integer vectors to a single 8-bit +/// unsigned integer vector with saturation. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn packuswb<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + pack_generic(this, left, right, dest, |op| { + let op = op.to_i16()?; + let res = u8::try_from(op).unwrap_or(if op < 0 { 0 } else { u8::MAX }); + Ok(Scalar::from_u8(res)) + }) +} + +/// Converts two 32-bit integer vectors to a single 16-bit integer +/// vector with signed saturation. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn packssdw<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + pack_generic(this, left, right, dest, |op| { + let op = op.to_i32()?; + let res = i16::try_from(op).unwrap_or(if op < 0 { i16::MIN } else { i16::MAX }); + Ok(Scalar::from_i16(res)) + }) +} + +/// Converts two 32-bit integer vectors to a single 16-bit integer +/// vector with unsigned saturation. +/// +/// Each 128-bit chunk is treated independently (i.e., the value for +/// the is i-th 128-bit chunk of `dest` is calculated with the i-th +/// 128-bit chunks of `left` and `right`). +fn packusdw<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + pack_generic(this, left, right, dest, |op| { + let op = op.to_i32()?; + let res = u16::try_from(op).unwrap_or(if op < 0 { 0 } else { u16::MAX }); + Ok(Scalar::from_u16(res)) + }) +} + +/// Negates elements from `left` when the corresponding element in +/// `right` is negative. If an element from `right` is zero, zero +/// is writen to the corresponding output element. +/// In other words, multiplies `left` with `right.signum()`. +fn psign<'tcx>( + this: &mut crate::MiriInterpCx<'_, 'tcx>, + left: &OpTy<'tcx, Provenance>, + right: &OpTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.mplace_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let dest = this.project_index(&dest, i)?; + let left = this.read_immediate(&this.project_index(&left, i)?)?; + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_int(dest.layout.size)?; + + let res = this.wrapping_binary_op( + mir::BinOp::Mul, + &left, + &ImmTy::from_int(right.signum(), dest.layout), + )?; + + this.write_immediate(*res, &dest)?; + } + + Ok(()) +} diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index b8c0dfb1c7f..17608837319 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -182,7 +182,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: }; let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { - // Fallback to minimum acording to SSE semantics. + // Fallback to minimum according to SSE semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 9db30d7ddca..c9ed751d36c 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -3,8 +3,8 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use super::{ - bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, shift_simd_by_scalar, - FloatBinOp, ShiftOp, + bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, packssdw, packsswb, + packuswb, shift_simd_by_scalar, FloatBinOp, ShiftOp, }; use crate::*; use shims::foreign_items::EmulateForeignItemResult; @@ -176,29 +176,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - // left and right are i16x8, dest is i8x16 - assert_eq!(left_len, 8); - assert_eq!(right_len, 8); - assert_eq!(dest_len, 16); - - for i in 0..left_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; - let left_dest = this.project_index(&dest, i)?; - let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?; - - let left_res = - i8::try_from(left).unwrap_or(if left < 0 { i8::MIN } else { i8::MAX }); - let right_res = - i8::try_from(right).unwrap_or(if right < 0 { i8::MIN } else { i8::MAX }); - - this.write_scalar(Scalar::from_i8(left_res), &left_dest)?; - this.write_scalar(Scalar::from_i8(right_res), &right_dest)?; - } + packsswb(this, left, right, dest)?; } // Used to implement the _mm_packus_epi16 function. // Converts two 16-bit signed integer vectors to a single 8-bit @@ -207,28 +185,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - // left and right are i16x8, dest is u8x16 - assert_eq!(left_len, 8); - assert_eq!(right_len, 8); - assert_eq!(dest_len, 16); - - for i in 0..left_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; - let left_dest = this.project_index(&dest, i)?; - let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?; - - let left_res = u8::try_from(left).unwrap_or(if left < 0 { 0 } else { u8::MAX }); - let right_res = - u8::try_from(right).unwrap_or(if right < 0 { 0 } else { u8::MAX }); - - this.write_scalar(Scalar::from_u8(left_res), &left_dest)?; - this.write_scalar(Scalar::from_u8(right_res), &right_dest)?; - } + packuswb(this, left, right, dest)?; } // Used to implement the _mm_packs_epi32 function. // Converts two 32-bit integer vectors to a single 16-bit integer @@ -237,29 +194,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - // left and right are i32x4, dest is i16x8 - assert_eq!(left_len, 4); - assert_eq!(right_len, 4); - assert_eq!(dest_len, 8); - - for i in 0..left_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i32()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i32()?; - let left_dest = this.project_index(&dest, i)?; - let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?; - - let left_res = - i16::try_from(left).unwrap_or(if left < 0 { i16::MIN } else { i16::MAX }); - let right_res = - i16::try_from(right).unwrap_or(if right < 0 { i16::MIN } else { i16::MAX }); - - this.write_scalar(Scalar::from_i16(left_res), &left_dest)?; - this.write_scalar(Scalar::from_i16(right_res), &right_dest)?; - } + packssdw(this, left, right, dest)?; } // Used to implement _mm_min_sd and _mm_max_sd functions. // Note that the semantics are a bit different from Rust simd_min @@ -420,7 +355,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: }; let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { - // Fallback to minimum acording to SSE semantics. + // Fallback to minimum according to SSE semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); @@ -447,7 +382,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let res0 = this.float_to_float_or_int(&right0, dest0.layout)?; this.write_immediate(*res0, &dest0)?; - // Copy remianing from `left` + // Copy remaining from `left` for i in 1..dest_len { this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index 16a82eed99b..19bc27421d3 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -1,7 +1,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; -use super::{conditional_dot_product, round_all, round_first, test_bits_masked}; +use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked}; use crate::*; use shims::foreign_items::EmulateForeignItemResult; @@ -68,27 +68,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(left_len, right_len); - assert_eq!(dest_len, left_len.checked_mul(2).unwrap()); - - for i in 0..left_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i32()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i32()?; - let left_dest = this.project_index(&dest, i)?; - let right_dest = this.project_index(&dest, i.checked_add(left_len).unwrap())?; - - let left_res = - u16::try_from(left).unwrap_or(if left < 0 { 0 } else { u16::MAX }); - let right_res = - u16::try_from(right).unwrap_or(if right < 0 { 0 } else { u16::MAX }); - - this.write_scalar(Scalar::from_u16(left_res), &left_dest)?; - this.write_scalar(Scalar::from_u16(right_res), &right_dest)?; - } + packusdw(this, left, right, dest)?; } // Used to implement the _mm_dp_ps and _mm_dp_pd functions. // Conditionally multiplies the packed floating-point elements in @@ -176,40 +156,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right, imm] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(left_len, right_len); - assert_eq!(left_len, dest_len.checked_mul(2).unwrap()); - - let imm = this.read_scalar(imm)?.to_u8()?; - // Bit 2 of `imm` specifies the offset for indices of `left`. - // The offset is 0 when the bit is 0 or 4 when the bit is 1. - let left_offset = u64::from((imm >> 2) & 1).checked_mul(4).unwrap(); - // Bits 0..=1 of `imm` specify the offset for indices of - // `right` in blocks of 4 elements. - let right_offset = u64::from(imm & 0b11).checked_mul(4).unwrap(); - - for i in 0..dest_len { - let left_offset = left_offset.checked_add(i).unwrap(); - let mut res: u16 = 0; - for j in 0..4 { - let left = this - .read_scalar( - &this.project_index(&left, left_offset.checked_add(j).unwrap())?, - )? - .to_u8()?; - let right = this - .read_scalar( - &this - .project_index(&right, right_offset.checked_add(j).unwrap())?, - )? - .to_u8()?; - res = res.checked_add(left.abs_diff(right).into()).unwrap(); - } - this.write_scalar(Scalar::from_u16(res), &this.project_index(&dest, i)?)?; - } + mpsadbw(this, left, right, imm, dest)?; } // Used to implement the _mm_testz_si128, _mm_testc_si128 // and _mm_testnzc_si128 functions. diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index dd5d064b20f..4f8e52dbb7d 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -2,7 +2,7 @@ use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; -use super::horizontal_bin_op; +use super::{horizontal_bin_op, int_abs, pmulhrsw, psign}; use crate::*; use shims::foreign_items::EmulateForeignItemResult; @@ -28,20 +28,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: "pabs.b.128" | "pabs.w.128" | "pabs.d.128" => { let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(op_len, dest_len); - - for i in 0..dest_len { - let op = this.read_scalar(&this.project_index(&op, i)?)?; - let dest = this.project_index(&dest, i)?; - - // Converting to a host "i128" works since the input is always signed. - let res = op.to_int(dest.layout.size)?.unsigned_abs(); - - this.write_scalar(Scalar::from_uint(res, dest.layout.size), &dest)?; - } + int_abs(this, op, dest)?; } // Used to implement the _mm_shuffle_epi8 intrinsic. // Shuffles bytes from `left` using `right` as pattern. @@ -136,30 +123,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(dest_len, left_len); - assert_eq!(dest_len, right_len); - - for i in 0..dest_len { - let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?; - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?; - let dest = this.project_index(&dest, i)?; - - let res = (i32::from(left).checked_mul(right.into()).unwrap() >> 14) - .checked_add(1) - .unwrap() - >> 1; - - // The result of this operation can overflow a signed 16-bit integer. - // When `left` and `right` are -0x8000, the result is 0x8000. - #[allow(clippy::cast_possible_truncation)] - let res = res as i16; - - this.write_scalar(Scalar::from_i16(res), &dest)?; - } + pmulhrsw(this, left, right, dest)?; } // Used to implement the _mm_sign_epi{8,16,32} functions. // Negates elements from `left` when the corresponding element in @@ -170,28 +134,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.mplace_to_simd(dest)?; - - assert_eq!(dest_len, left_len); - assert_eq!(dest_len, right_len); - - for i in 0..dest_len { - let dest = this.project_index(&dest, i)?; - let left = this.read_immediate(&this.project_index(&left, i)?)?; - let right = this - .read_scalar(&this.project_index(&right, i)?)? - .to_int(dest.layout.size)?; - - let res = this.wrapping_binary_op( - mir::BinOp::Mul, - &left, - &ImmTy::from_int(right.signum(), dest.layout), - )?; - - this.write_immediate(*res, &dest)?; - } + psign(this, left, right, dest)?; } _ => return Ok(EmulateForeignItemResult::NotSupported), } diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs index e188a1f0c34..c656a509644 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs @@ -8,7 +8,7 @@ use std::mem; pub fn safe(x: &i32, y: &mut Cell<i32>) { //~[stack]^ ERROR: protect y.set(1); - let _ = *x; + let _load = *x; } fn main() { diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.rs b/src/tools/miri/tests/fail/coroutine-pinned-moved.rs index 005ae7e9132..46ec58810a6 100644 --- a/src/tools/miri/tests/fail/coroutine-pinned-moved.rs +++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ ops::{Coroutine, CoroutineState}, @@ -7,6 +7,7 @@ use std::{ }; fn firstn() -> impl Coroutine<Yield = u64, Return = ()> { + #[coroutine] static move || { let mut num = 0; let num = &mut num; diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs index f9983f48c61..f4349286801 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - let _ = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer + let _ref = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer } fn main() { diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 27e5a865069..73c3ff1ee05 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/storage_dead_dangling.rs:LL:CC | -LL | let _ = unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) +LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/many-seeds/tls-leak.rs b/src/tools/miri/tests/many-seeds/tls-leak.rs new file mode 100644 index 00000000000..3b243633439 --- /dev/null +++ b/src/tools/miri/tests/many-seeds/tls-leak.rs @@ -0,0 +1,26 @@ +//! Regression test for <https://github.com/rust-lang/rust/issues/123583>. +use std::thread; + +fn with_thread_local1() { + thread_local! { static X: Box<u8> = Box::new(0); } + X.with(|_x| {}) +} + +fn with_thread_local2() { + thread_local! { static Y: Box<u8> = Box::new(0); } + Y.with(|_y| {}) +} + +fn main() { + // Here we have two threads racing on initializing the thread-local and adding it to the global + // dtor list (on targets that have such a list, i.e., targets without target_thread_local). + let t = thread::spawn(with_thread_local1); + with_thread_local1(); + t.join().unwrap(); + + // Here we have one thread running the destructors racing with another thread initializing a + // thread-local. The second thread adds a destructor that could be picked up by the first. + let t = thread::spawn(|| { /* immediately just run destructors */ }); + with_thread_local2(); // initialize thread-local + t.join().unwrap(); +} diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs index abb384b0a85..f710daf5277 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs @@ -213,6 +213,50 @@ fn test_posix_gettimeofday() { assert_eq!(is_error, -1); } +fn test_localtime_r() { + use std::ffi::CStr; + use std::{env, ptr}; + + // Set timezone to GMT. + let key = "TZ"; + env::set_var(key, "GMT"); + + const TIME_SINCE_EPOCH: libc::time_t = 1712475836; + let custom_time_ptr = &TIME_SINCE_EPOCH; + let mut tm = libc::tm { + tm_sec: 0, + tm_min: 0, + tm_hour: 0, + tm_mday: 0, + tm_mon: 0, + tm_year: 0, + tm_wday: 0, + tm_yday: 0, + tm_isdst: 0, + tm_gmtoff: 0, + tm_zone: std::ptr::null_mut::<libc::c_char>(), + }; + let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; + + assert_eq!(tm.tm_sec, 56); + assert_eq!(tm.tm_min, 43); + assert_eq!(tm.tm_hour, 7); + assert_eq!(tm.tm_mday, 7); + assert_eq!(tm.tm_mon, 3); + assert_eq!(tm.tm_year, 124); + assert_eq!(tm.tm_wday, 0); + assert_eq!(tm.tm_yday, 97); + assert_eq!(tm.tm_isdst, -1); + assert_eq!(tm.tm_gmtoff, 0); + unsafe { assert_eq!(CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00") }; + + // The returned value is the pointer passed in. + assert!(ptr::eq(res, &mut tm)); + + //Remove timezone setting. + env::remove_var(key); +} + fn test_isatty() { // Testing whether our isatty shim returns the right value would require controlling whether // these streams are actually TTYs, which is hard. @@ -365,6 +409,7 @@ fn main() { test_posix_realpath_errors(); test_thread_local_errno(); + test_localtime_r(); test_isatty(); diff --git a/src/tools/miri/tests/pass/adjacent-allocs.rs b/src/tools/miri/tests/pass/adjacent-allocs.rs index cbf41d68b57..8be4bdac7e1 100644 --- a/src/tools/miri/tests/pass/adjacent-allocs.rs +++ b/src/tools/miri/tests/pass/adjacent-allocs.rs @@ -30,7 +30,7 @@ fn test1() { // See https://github.com/rust-lang/miri/issues/1866#issuecomment-985770125 { let m = 0u64; - let _ = &m as *const u64; + let _ptr = &m as *const u64; } let iptr = ptr as usize; diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout index c9cab268168..e6644b4453f 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout @@ -1,5 +1,5 @@ $DIR/backtrace-api-v0.rs:24:14 (func_d) -$DIR/backtrace-api-v0.rs:20:5 (func_c) +$DIR/backtrace-api-v0.rs:14:9 (func_c) $DIR/backtrace-api-v0.rs:9:5 (func_b::<u8>) $DIR/backtrace-api-v0.rs:5:5 (func_a) $DIR/backtrace-api-v0.rs:29:18 (main) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout index e145c167e88..11efd2f0752 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stdout @@ -1,5 +1,5 @@ $DIR/backtrace-api-v1.rs:27:9 (func_d) -$DIR/backtrace-api-v1.rs:20:5 (func_c) +$DIR/backtrace-api-v1.rs:14:9 (func_c) $DIR/backtrace-api-v1.rs:9:5 (func_b::<u8>) $DIR/backtrace-api-v1.rs:5:5 (func_a) $DIR/backtrace-api-v1.rs:34:18 (main) diff --git a/src/tools/miri/tests/pass/const-addrs.rs b/src/tools/miri/tests/pass/const-addrs.rs index 6c14f0b679c..727c67ebfb5 100644 --- a/src/tools/miri/tests/pass/const-addrs.rs +++ b/src/tools/miri/tests/pass/const-addrs.rs @@ -4,7 +4,7 @@ // deallocated. // In Miri we explicitly store previously-assigned AllocIds for each const and ensure // that we only hand out a finite number of AllocIds per const. -// MIR inlining will put every evaluation of the const we're repeatedly evaluting into the same +// MIR inlining will put every evaluation of the const we're repeatedly evaluating into the same // stack frame, breaking this test. //@compile-flags: -Zinline-mir=no #![feature(strict_provenance)] diff --git a/src/tools/miri/tests/pass/coroutine.rs b/src/tools/miri/tests/pass/coroutine.rs index 7e1f64df04d..7822c136d91 100644 --- a/src/tools/miri/tests/pass/coroutine.rs +++ b/src/tools/miri/tests/pass/coroutine.rs @@ -1,6 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -#![feature(coroutines, coroutine_trait, never_type)] +#![feature(coroutines, coroutine_trait, never_type, stmt_expr_attributes)] use std::fmt::Debug; use std::mem::ManuallyDrop; @@ -43,94 +43,144 @@ fn basic() { panic!() } - finish(1, false, || yield 1); + finish( + 1, + false, + #[coroutine] + || yield 1, + ); - finish(3, false, || { - let mut x = 0; - yield 1; - x += 1; - yield 1; - x += 1; - yield 1; - assert_eq!(x, 2); - }); + finish( + 3, + false, + #[coroutine] + || { + let mut x = 0; + yield 1; + x += 1; + yield 1; + x += 1; + yield 1; + assert_eq!(x, 2); + }, + ); - finish(7 * 8 / 2, false, || { - for i in 0..8 { - yield i; - } - }); + finish( + 7 * 8 / 2, + false, + #[coroutine] + || { + for i in 0..8 { + yield i; + } + }, + ); - finish(1, false, || { - if true { - yield 1; - } else { - } - }); + finish( + 1, + false, + #[coroutine] + || { + if true { + yield 1; + } else { + } + }, + ); - finish(1, false, || { - if false { - } else { - yield 1; - } - }); + finish( + 1, + false, + #[coroutine] + || { + if false { + } else { + yield 1; + } + }, + ); - finish(2, false, || { - if { - yield 1; - false - } { + finish( + 2, + false, + #[coroutine] + || { + if { + yield 1; + false + } { + yield 1; + panic!() + } yield 1; - panic!() - } - yield 1; - }); + }, + ); // also test self-referential coroutines assert_eq!( - finish(5, true, static || { - let mut x = 5; - let y = &mut x; - *y = 5; - yield *y; - *y = 10; - x - }), + finish( + 5, + true, + #[coroutine] + static || { + let mut x = 5; + let y = &mut x; + *y = 5; + yield *y; + *y = 10; + x + } + ), 10 ); assert_eq!( - finish(5, true, || { - let mut x = Box::new(5); - let y = &mut *x; - *y = 5; - yield *y; - *y = 10; - *x - }), + finish( + 5, + true, + #[coroutine] + || { + let mut x = Box::new(5); + let y = &mut *x; + *y = 5; + yield *y; + *y = 10; + *x + } + ), 10 ); let b = true; - finish(1, false, || { - yield 1; - if b { - return; - } - #[allow(unused)] - let x = never(); - #[allow(unreachable_code)] - yield 2; - drop(x); - }); - - finish(3, false, || { - yield 1; - #[allow(unreachable_code)] - let _x: (String, !) = (String::new(), { + finish( + 1, + false, + #[coroutine] + || { + yield 1; + if b { + return; + } + #[allow(unused)] + let x = never(); + #[allow(unreachable_code)] yield 2; - return; - }); - }); + drop(x); + }, + ); + + finish( + 3, + false, + #[coroutine] + || { + yield 1; + #[allow(unreachable_code)] + let _x: (String, !) = (String::new(), { + yield 2; + return; + }); + }, + ); } fn smoke_resume_arg() { @@ -172,7 +222,8 @@ fn smoke_resume_arg() { } drain( - &mut |mut b| { + &mut #[coroutine] + |mut b| { while b != 0 { b = yield (b + 1); } @@ -181,21 +232,35 @@ fn smoke_resume_arg() { vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))], ); - expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))])); + expect_drops(2, || { + drain( + &mut #[coroutine] + |a| yield a, + vec![(DropMe, Yielded(DropMe))], + ) + }); expect_drops(6, || { drain( - &mut |a| yield yield a, + &mut #[coroutine] + |a| yield yield a, vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))], ) }); #[allow(unreachable_code)] - expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))])); + expect_drops(2, || { + drain( + &mut #[coroutine] + |a| yield return a, + vec![(DropMe, Complete(DropMe))], + ) + }); expect_drops(2, || { drain( - &mut |a: DropMe| { + &mut #[coroutine] + |a: DropMe| { if false { yield () } else { a } }, vec![(DropMe, Complete(DropMe))], @@ -205,7 +270,8 @@ fn smoke_resume_arg() { expect_drops(4, || { drain( #[allow(unused_assignments, unused_variables)] - &mut |mut a: DropMe| { + &mut #[coroutine] + |mut a: DropMe| { a = yield; a = yield; a = yield; @@ -228,7 +294,8 @@ fn uninit_fields() { } fn run<T>(x: bool, y: bool) { - let mut c = || { + let mut c = #[coroutine] + || { if x { let _a: T; if y { diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index ddc4bdcf082..ff995f38196 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -69,7 +69,7 @@ fn basic() { } let baz: &dyn Baz = &1; - let _: &dyn fmt::Debug = baz; + let _up: &dyn fmt::Debug = baz; assert_eq!(*baz, 1); assert_eq!(baz.a(), 100); assert_eq!(baz.b(), 200); @@ -79,7 +79,7 @@ fn basic() { assert_eq!(baz.w(), 21); let bar: &dyn Bar = baz; - let _: &dyn fmt::Debug = bar; + let _up: &dyn fmt::Debug = bar; assert_eq!(*bar, 1); assert_eq!(bar.a(), 100); assert_eq!(bar.b(), 200); @@ -88,14 +88,14 @@ fn basic() { assert_eq!(bar.w(), 21); let foo: &dyn Foo = baz; - let _: &dyn fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); assert_eq!(foo.z(), 11); assert_eq!(foo.y(), 12); let foo: &dyn Foo = bar; - let _: &dyn fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); assert_eq!(foo.z(), 11); @@ -168,7 +168,7 @@ fn diamond() { } let baz: &dyn Baz = &1; - let _: &dyn fmt::Debug = baz; + let _up: &dyn fmt::Debug = baz; assert_eq!(*baz, 1); assert_eq!(baz.a(), 100); assert_eq!(baz.b(), 200); @@ -180,7 +180,7 @@ fn diamond() { assert_eq!(baz.v(), 31); let bar1: &dyn Bar1 = baz; - let _: &dyn fmt::Debug = bar1; + let _up: &dyn fmt::Debug = bar1; assert_eq!(*bar1, 1); assert_eq!(bar1.a(), 100); assert_eq!(bar1.b(), 200); @@ -189,7 +189,7 @@ fn diamond() { assert_eq!(bar1.w(), 21); let bar2: &dyn Bar2 = baz; - let _: &dyn fmt::Debug = bar2; + let _up: &dyn fmt::Debug = bar2; assert_eq!(*bar2, 1); assert_eq!(bar2.a(), 100); assert_eq!(bar2.c(), 300); @@ -198,17 +198,17 @@ fn diamond() { assert_eq!(bar2.v(), 31); let foo: &dyn Foo = baz; - let _: &dyn fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); let foo: &dyn Foo = bar1; - let _: &dyn fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); let foo: &dyn Foo = bar2; - let _: &dyn fmt::Debug = foo; + let _up: &dyn fmt::Debug = foo; assert_eq!(*foo, 1); assert_eq!(foo.a(), 100); } diff --git a/src/tools/miri/tests/pass/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/intrinsics-x86-avx2.rs new file mode 100644 index 00000000000..80d125bb856 --- /dev/null +++ b/src/tools/miri/tests/pass/intrinsics-x86-avx2.rs @@ -0,0 +1,1613 @@ +// Ignore everything except x86 and x86_64 +// Any new targets that are added to CI should be ignored here. +// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) +//@ignore-target-aarch64 +//@ignore-target-arm +//@ignore-target-avr +//@ignore-target-s390x +//@ignore-target-thumbv7em +//@ignore-target-wasm32 +//@compile-flags: -C target-feature=+avx2 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; +use std::mem::transmute; + +fn main() { + assert!(is_x86_feature_detected!("avx2")); + + unsafe { + test_avx2(); + } +} + +#[target_feature(enable = "avx2")] +unsafe fn test_avx2() { + // Mostly copied from library/stdarch/crates/core_arch/src/x86/avx2.rs + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_abs_epi32() { + #[rustfmt::skip] + let a = _mm256_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let r = _mm256_abs_epi32(a); + #[rustfmt::skip] + let e = _mm256_setr_epi32( + 0, 1, 1, i32::MAX, + i32::MAX.wrapping_add(1), 100, 100, 32, + ); + assert_eq_m256i(r, e); + } + test_mm256_abs_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_abs_epi16() { + #[rustfmt::skip] + let a = _mm256_setr_epi16( + 0, 1, -1, 2, -2, 3, -3, 4, + -4, 5, -5, i16::MAX, i16::MIN, 100, -100, -32, + ); + let r = _mm256_abs_epi16(a); + #[rustfmt::skip] + let e = _mm256_setr_epi16( + 0, 1, 1, 2, 2, 3, 3, 4, + 4, 5, 5, i16::MAX, i16::MAX.wrapping_add(1), 100, 100, 32, + ); + assert_eq_m256i(r, e); + } + test_mm256_abs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_abs_epi8() { + #[rustfmt::skip] + let a = _mm256_setr_epi8( + 0, 1, -1, 2, -2, 3, -3, 4, + -4, 5, -5, i8::MAX, i8::MIN, 100, -100, -32, + 0, 1, -1, 2, -2, 3, -3, 4, + -4, 5, -5, i8::MAX, i8::MIN, 100, -100, -32, + ); + let r = _mm256_abs_epi8(a); + #[rustfmt::skip] + let e = _mm256_setr_epi8( + 0, 1, 1, 2, 2, 3, 3, 4, + 4, 5, 5, i8::MAX, i8::MAX.wrapping_add(1), 100, 100, 32, + 0, 1, 1, 2, 2, 3, 3, 4, + 4, 5, 5, i8::MAX, i8::MAX.wrapping_add(1), 100, 100, 32, + ); + assert_eq_m256i(r, e); + } + test_mm256_abs_epi8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hadd_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_hadd_epi16(a, b); + let e = _mm256_setr_epi16(4, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8); + assert_eq_m256i(r, e); + + // Test wrapping on overflow + let a = _mm256_setr_epi16( + i16::MAX, + 1, + i16::MAX, + 2, + i16::MAX, + 3, + i16::MAX, + 4, + i16::MAX, + 5, + i16::MAX, + 6, + i16::MAX, + 7, + i16::MAX, + 8, + ); + let b = _mm256_setr_epi16( + i16::MIN, + -1, + i16::MIN, + -2, + i16::MIN, + -3, + i16::MIN, + -4, + i16::MIN, + -5, + i16::MIN, + -6, + i16::MIN, + -7, + i16::MIN, + -8, + ); + let expected = _mm256_setr_epi16( + i16::MIN, + i16::MIN + 1, + i16::MIN + 2, + i16::MIN + 3, + i16::MAX, + i16::MAX - 1, + i16::MAX - 2, + i16::MAX - 3, + i16::MIN + 4, + i16::MIN + 5, + i16::MIN + 6, + i16::MIN + 7, + i16::MAX - 4, + i16::MAX - 5, + i16::MAX - 6, + i16::MAX - 7, + ); + let r = _mm256_hadd_epi16(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hadd_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hadd_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(4); + let r = _mm256_hadd_epi32(a, b); + let e = _mm256_setr_epi32(4, 4, 8, 8, 4, 4, 8, 8); + assert_eq_m256i(r, e); + + // Test wrapping on overflow + let a = _mm256_setr_epi32(i32::MAX, 1, i32::MAX, 2, i32::MAX, 3, i32::MAX, 4); + let b = _mm256_setr_epi32(i32::MIN, -1, i32::MIN, -2, i32::MIN, -3, i32::MIN, -4); + let expected = _mm256_setr_epi32( + i32::MIN, + i32::MIN + 1, + i32::MAX, + i32::MAX - 1, + i32::MIN + 2, + i32::MIN + 3, + i32::MAX - 2, + i32::MAX - 3, + ); + let r = _mm256_hadd_epi32(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hadd_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hadds_epi16() { + let a = _mm256_set1_epi16(2); + let a = _mm256_insert_epi16::<0>(a, 0x7fff); + let a = _mm256_insert_epi16::<1>(a, 1); + let b = _mm256_set1_epi16(4); + let r = _mm256_hadds_epi16(a, b); + let e = _mm256_setr_epi16(0x7FFF, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8); + assert_eq_m256i(r, e); + + // Test saturating on overflow + let a = _mm256_setr_epi16( + i16::MAX, + 1, + i16::MAX, + 2, + i16::MAX, + 3, + i16::MAX, + 4, + i16::MAX, + 5, + i16::MAX, + 6, + i16::MAX, + 7, + i16::MAX, + 8, + ); + let b = _mm256_setr_epi16( + i16::MIN, + -1, + i16::MIN, + -2, + i16::MIN, + -3, + i16::MIN, + -4, + i16::MIN, + -5, + i16::MIN, + -6, + i16::MIN, + -7, + i16::MIN, + -8, + ); + let expected = _mm256_setr_epi16( + i16::MAX, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MIN, + ); + let r = _mm256_hadds_epi16(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hadds_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hsub_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_hsub_epi16(a, b); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + + // Test wrapping on overflow + let a = _mm256_setr_epi16( + i16::MAX, + -1, + i16::MAX, + -2, + i16::MAX, + -3, + i16::MAX, + -4, + i16::MAX, + -5, + i16::MAX, + -6, + i16::MAX, + -7, + i16::MAX, + -8, + ); + let b = _mm256_setr_epi16( + i16::MIN, + 1, + i16::MIN, + 2, + i16::MIN, + 3, + i16::MIN, + 4, + i16::MIN, + 5, + i16::MIN, + 6, + i16::MIN, + 7, + i16::MIN, + 8, + ); + let expected = _mm256_setr_epi16( + i16::MIN, + i16::MIN + 1, + i16::MIN + 2, + i16::MIN + 3, + i16::MAX, + i16::MAX - 1, + i16::MAX - 2, + i16::MAX - 3, + i16::MIN + 4, + i16::MIN + 5, + i16::MIN + 6, + i16::MIN + 7, + i16::MAX - 4, + i16::MAX - 5, + i16::MAX - 6, + i16::MAX - 7, + ); + let r = _mm256_hsub_epi16(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hsub_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hsub_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(4); + let r = _mm256_hsub_epi32(a, b); + let e = _mm256_set1_epi32(0); + assert_eq_m256i(r, e); + + // Test wrapping on overflow + let a = _mm256_setr_epi32(i32::MAX, -1, i32::MAX, -2, i32::MAX, -3, i32::MAX, -4); + let b = _mm256_setr_epi32(i32::MIN, 1, i32::MIN, 2, i32::MIN, 3, i32::MIN, 4); + let expected = _mm256_setr_epi32( + i32::MIN, + i32::MIN + 1, + i32::MAX, + i32::MAX - 1, + i32::MIN + 2, + i32::MIN + 3, + i32::MAX - 2, + i32::MAX - 3, + ); + let r = _mm256_hsub_epi32(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hsub_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_hsubs_epi16() { + let a = _mm256_set1_epi16(2); + let a = _mm256_insert_epi16::<0>(a, 0x7fff); + let a = _mm256_insert_epi16::<1>(a, -1); + let b = _mm256_set1_epi16(4); + let r = _mm256_hsubs_epi16(a, b); + let e = _mm256_insert_epi16::<0>(_mm256_set1_epi16(0), 0x7FFF); + assert_eq_m256i(r, e); + + // Test saturating on overflow + let a = _mm256_setr_epi16( + i16::MAX, + -1, + i16::MAX, + -2, + i16::MAX, + -3, + i16::MAX, + -4, + i16::MAX, + -5, + i16::MAX, + -6, + i16::MAX, + -7, + i16::MAX, + -8, + ); + let b = _mm256_setr_epi16( + i16::MIN, + 1, + i16::MIN, + 2, + i16::MIN, + 3, + i16::MIN, + 4, + i16::MIN, + 5, + i16::MIN, + 6, + i16::MIN, + 7, + i16::MIN, + 8, + ); + let expected = _mm256_setr_epi16( + i16::MAX, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MAX, + i16::MIN, + i16::MIN, + i16::MIN, + i16::MIN, + ); + let r = _mm256_hsubs_epi16(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_hsubs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i32gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm_i32gather_epi32::<4>(arr.as_ptr(), _mm_setr_epi32(0, 16, 32, 48)); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 32, 48)); + } + test_mm_i32gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i32gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm_mask_i32gather_epi32::<4>( + _mm_set1_epi32(256), + arr.as_ptr(), + _mm_setr_epi32(0, 16, 64, 96), + _mm_setr_epi32(-1, -1, -1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 64, 256)); + } + test_mm_mask_i32gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i32gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = + _mm256_i32gather_epi32::<4>(arr.as_ptr(), _mm256_setr_epi32(0, 16, 32, 48, 1, 2, 3, 4)); + assert_eq_m256i(r, _mm256_setr_epi32(0, 16, 32, 48, 1, 2, 3, 4)); + } + test_mm256_i32gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i32gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm256_mask_i32gather_epi32::<4>( + _mm256_set1_epi32(256), + arr.as_ptr(), + _mm256_setr_epi32(0, 16, 64, 96, 0, 0, 0, 0), + _mm256_setr_epi32(-1, -1, -1, 0, 0, 0, 0, 0), + ); + assert_eq_m256i(r, _mm256_setr_epi32(0, 16, 64, 256, 256, 256, 256, 256)); + } + test_mm256_mask_i32gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i32gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm_i32gather_ps::<4>(arr.as_ptr(), _mm_setr_epi32(0, 16, 32, 48)); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 32.0, 48.0)); + } + test_mm_i32gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i32gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm_mask_i32gather_ps::<4>( + _mm_set1_ps(256.0), + arr.as_ptr(), + _mm_setr_epi32(0, 16, 64, 96), + _mm_setr_ps(-1.0, -1.0, -1.0, 0.0), + ); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 64.0, 256.0)); + } + test_mm_mask_i32gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i32gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = + _mm256_i32gather_ps::<4>(arr.as_ptr(), _mm256_setr_epi32(0, 16, 32, 48, 1, 2, 3, 4)); + assert_eq_m256(r, _mm256_setr_ps(0.0, 16.0, 32.0, 48.0, 1.0, 2.0, 3.0, 4.0)); + } + test_mm256_i32gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i32gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm256_mask_i32gather_ps::<4>( + _mm256_set1_ps(256.0), + arr.as_ptr(), + _mm256_setr_epi32(0, 16, 64, 96, 0, 0, 0, 0), + _mm256_setr_ps(-1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0), + ); + assert_eq_m256(r, _mm256_setr_ps(0.0, 16.0, 64.0, 256.0, 256.0, 256.0, 256.0, 256.0)); + } + test_mm256_mask_i32gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i32gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm_i32gather_epi64::<8>(arr.as_ptr(), _mm_setr_epi32(0, 16, 0, 0)); + assert_eq_m128i(r, _mm_setr_epi64x(0, 16)); + } + test_mm_i32gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i32gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm_mask_i32gather_epi64::<8>( + _mm_set1_epi64x(256), + arr.as_ptr(), + _mm_setr_epi32(16, 16, 16, 16), + _mm_setr_epi64x(-1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi64x(16, 256)); + } + test_mm_mask_i32gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i32gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm256_i32gather_epi64::<8>(arr.as_ptr(), _mm_setr_epi32(0, 16, 32, 48)); + assert_eq_m256i(r, _mm256_setr_epi64x(0, 16, 32, 48)); + } + test_mm256_i32gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i32gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm256_mask_i32gather_epi64::<8>( + _mm256_set1_epi64x(256), + arr.as_ptr(), + _mm_setr_epi32(0, 16, 64, 96), + _mm256_setr_epi64x(-1, -1, -1, 0), + ); + assert_eq_m256i(r, _mm256_setr_epi64x(0, 16, 64, 256)); + } + test_mm256_mask_i32gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i32gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm_i32gather_pd::<8>(arr.as_ptr(), _mm_setr_epi32(0, 16, 0, 0)); + assert_eq_m128d(r, _mm_setr_pd(0.0, 16.0)); + } + test_mm_i32gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i32gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm_mask_i32gather_pd::<8>( + _mm_set1_pd(256.0), + arr.as_ptr(), + _mm_setr_epi32(16, 16, 16, 16), + _mm_setr_pd(-1.0, 0.0), + ); + assert_eq_m128d(r, _mm_setr_pd(16.0, 256.0)); + } + test_mm_mask_i32gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i32gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm256_i32gather_pd::<8>(arr.as_ptr(), _mm_setr_epi32(0, 16, 32, 48)); + assert_eq_m256d(r, _mm256_setr_pd(0.0, 16.0, 32.0, 48.0)); + } + test_mm256_i32gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i32gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm256_mask_i32gather_pd::<8>( + _mm256_set1_pd(256.0), + arr.as_ptr(), + _mm_setr_epi32(0, 16, 64, 96), + _mm256_setr_pd(-1.0, -1.0, -1.0, 0.0), + ); + assert_eq_m256d(r, _mm256_setr_pd(0.0, 16.0, 64.0, 256.0)); + } + test_mm256_mask_i32gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i64gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm_i64gather_epi32::<4>(arr.as_ptr(), _mm_setr_epi64x(0, 16)); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 0, 0)); + } + test_mm_i64gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i64gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm_mask_i64gather_epi32::<4>( + _mm_set1_epi32(256), + arr.as_ptr(), + _mm_setr_epi64x(0, 16), + _mm_setr_epi32(-1, 0, -1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi32(0, 256, 0, 0)); + } + test_mm_mask_i64gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i64gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm256_i64gather_epi32::<4>(arr.as_ptr(), _mm256_setr_epi64x(0, 16, 32, 48)); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 32, 48)); + } + test_mm256_i64gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i64gather_epi32() { + let arr: [i32; 128] = core::array::from_fn(|i| i as i32); + // A multiplier of 4 is word-addressing + let r = _mm256_mask_i64gather_epi32::<4>( + _mm_set1_epi32(256), + arr.as_ptr(), + _mm256_setr_epi64x(0, 16, 64, 96), + _mm_setr_epi32(-1, -1, -1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi32(0, 16, 64, 256)); + } + test_mm256_mask_i64gather_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i64gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm_i64gather_ps::<4>(arr.as_ptr(), _mm_setr_epi64x(0, 16)); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 0.0, 0.0)); + } + test_mm_i64gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i64gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm_mask_i64gather_ps::<4>( + _mm_set1_ps(256.0), + arr.as_ptr(), + _mm_setr_epi64x(0, 16), + _mm_setr_ps(-1.0, 0.0, -1.0, 0.0), + ); + assert_eq_m128(r, _mm_setr_ps(0.0, 256.0, 0.0, 0.0)); + } + test_mm_mask_i64gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i64gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm256_i64gather_ps::<4>(arr.as_ptr(), _mm256_setr_epi64x(0, 16, 32, 48)); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 32.0, 48.0)); + } + test_mm256_i64gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i64gather_ps() { + let arr: [f32; 128] = core::array::from_fn(|i| i as f32); + // A multiplier of 4 is word-addressing for f32s + let r = _mm256_mask_i64gather_ps::<4>( + _mm_set1_ps(256.0), + arr.as_ptr(), + _mm256_setr_epi64x(0, 16, 64, 96), + _mm_setr_ps(-1.0, -1.0, -1.0, 0.0), + ); + assert_eq_m128(r, _mm_setr_ps(0.0, 16.0, 64.0, 256.0)); + } + test_mm256_mask_i64gather_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i64gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm_i64gather_epi64::<8>(arr.as_ptr(), _mm_setr_epi64x(0, 16)); + assert_eq_m128i(r, _mm_setr_epi64x(0, 16)); + } + test_mm_i64gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i64gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm_mask_i64gather_epi64::<8>( + _mm_set1_epi64x(256), + arr.as_ptr(), + _mm_setr_epi64x(16, 16), + _mm_setr_epi64x(-1, 0), + ); + assert_eq_m128i(r, _mm_setr_epi64x(16, 256)); + } + test_mm_mask_i64gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i64gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm256_i64gather_epi64::<8>(arr.as_ptr(), _mm256_setr_epi64x(0, 16, 32, 48)); + assert_eq_m256i(r, _mm256_setr_epi64x(0, 16, 32, 48)); + } + test_mm256_i64gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i64gather_epi64() { + let arr: [i64; 128] = core::array::from_fn(|i| i as i64); + // A multiplier of 8 is word-addressing for i64s + let r = _mm256_mask_i64gather_epi64::<8>( + _mm256_set1_epi64x(256), + arr.as_ptr(), + _mm256_setr_epi64x(0, 16, 64, 96), + _mm256_setr_epi64x(-1, -1, -1, 0), + ); + assert_eq_m256i(r, _mm256_setr_epi64x(0, 16, 64, 256)); + } + test_mm256_mask_i64gather_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_i64gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm_i64gather_pd::<8>(arr.as_ptr(), _mm_setr_epi64x(0, 16)); + assert_eq_m128d(r, _mm_setr_pd(0.0, 16.0)); + } + test_mm_i64gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_mask_i64gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm_mask_i64gather_pd::<8>( + _mm_set1_pd(256.0), + arr.as_ptr(), + _mm_setr_epi64x(16, 16), + _mm_setr_pd(-1.0, 0.0), + ); + assert_eq_m128d(r, _mm_setr_pd(16.0, 256.0)); + } + test_mm_mask_i64gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_i64gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm256_i64gather_pd::<8>(arr.as_ptr(), _mm256_setr_epi64x(0, 16, 32, 48)); + assert_eq_m256d(r, _mm256_setr_pd(0.0, 16.0, 32.0, 48.0)); + } + test_mm256_i64gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mask_i64gather_pd() { + let arr: [f64; 128] = core::array::from_fn(|i| i as f64); + // A multiplier of 8 is word-addressing for f64s + let r = _mm256_mask_i64gather_pd::<8>( + _mm256_set1_pd(256.0), + arr.as_ptr(), + _mm256_setr_epi64x(0, 16, 64, 96), + _mm256_setr_pd(-1.0, -1.0, -1.0, 0.0), + ); + assert_eq_m256d(r, _mm256_setr_pd(0.0, 16.0, 64.0, 256.0)); + } + test_mm256_mask_i64gather_pd(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_madd_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_madd_epi16(a, b); + let e = _mm256_set1_epi32(16); + assert_eq_m256i(r, e); + } + test_mm256_madd_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maddubs_epi16() { + let a = _mm256_set1_epi8(2); + let b = _mm256_set1_epi8(4); + let r = _mm256_maddubs_epi16(a, b); + let e = _mm256_set1_epi16(16); + assert_eq_m256i(r, e); + } + test_mm256_maddubs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_maskload_epi32() { + let nums = [1, 2, 3, 4]; + let a = &nums as *const i32; + let mask = _mm_setr_epi32(-1, 0, 0, -1); + let r = _mm_maskload_epi32(a, mask); + let e = _mm_setr_epi32(1, 0, 0, 4); + assert_eq_m128i(r, e); + + // Unaligned pointer + let a = Unaligned::new([1i32, 2, 3, 4]); + let mask = _mm_setr_epi32(0, !0, 0, !0); + let r = _mm_maskload_epi32(a.as_ptr().cast(), mask); + let e = _mm_setr_epi32(0, 2, 0, 4); + assert_eq_m128i(r, e); + + // Only loading first element, so slice can be short. + let a = &[2i32]; + let mask = _mm_setr_epi32(!0, 0, 0, 0); + let r = _mm_maskload_epi32(a.as_ptr(), mask); + let e = _mm_setr_epi32(2, 0, 0, 0); + assert_eq_m128i(r, e); + + // Only loading last element, so slice can be short. + let a = &[2i32]; + let mask = _mm_setr_epi32(0, 0, 0, !0); + let r = _mm_maskload_epi32(a.as_ptr().wrapping_sub(3), mask); + let e = _mm_setr_epi32(0, 0, 0, 2); + assert_eq_m128i(r, e); + } + test_mm_maskload_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maskload_epi32() { + let nums = [1, 2, 3, 4, 5, 6, 7, 8]; + let a = &nums as *const i32; + let mask = _mm256_setr_epi32(-1, 0, 0, -1, 0, -1, -1, 0); + let r = _mm256_maskload_epi32(a, mask); + let e = _mm256_setr_epi32(1, 0, 0, 4, 0, 6, 7, 0); + assert_eq_m256i(r, e); + + // Unaligned pointer + let a = Unaligned::new([1i32, 2, 3, 4, 5, 6, 7, 8]); + let mask = _mm256_setr_epi32(0, !0, 0, !0, 0, !0, 0, !0); + let r = _mm256_maskload_epi32(a.as_ptr().cast(), mask); + let e = _mm256_setr_epi32(0, 2, 0, 4, 0, 6, 0, 8); + assert_eq_m256i(r, e); + + // Only loading first element, so slice can be short. + let a = &[2i32]; + let mask = _mm256_setr_epi32(!0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm256_maskload_epi32(a.as_ptr(), mask); + let e = _mm256_setr_epi32(2, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + + // Only loading last element, so slice can be short. + let a = &[2i32]; + let mask = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, !0); + let r = _mm256_maskload_epi32(a.as_ptr().wrapping_sub(7), mask); + let e = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, 2); + assert_eq_m256i(r, e); + } + test_mm256_maskload_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_maskload_epi64() { + let nums = [1_i64, 2_i64]; + let a = &nums as *const i64; + let mask = _mm_setr_epi64x(0, -1); + let r = _mm_maskload_epi64(a, mask); + let e = _mm_setr_epi64x(0, 2); + assert_eq_m128i(r, e); + + // Unaligned pointer + let a = Unaligned::new([1i64, 2]); + let mask = _mm_setr_epi64x(0, !0); + let r = _mm_maskload_epi64(a.as_ptr().cast(), mask); + let e = _mm_setr_epi64x(0, 2); + assert_eq_m128i(r, e); + + // Only loading first element, so slice can be short. + let a = &[2i64]; + let mask = _mm_setr_epi64x(!0, 0); + let r = _mm_maskload_epi64(a.as_ptr(), mask); + let e = _mm_setr_epi64x(2, 0); + assert_eq_m128i(r, e); + + // Only loading last element, so slice can be short. + let a = &[2i64]; + let mask = _mm_setr_epi64x(0, !0); + let r = _mm_maskload_epi64(a.as_ptr().wrapping_sub(1), mask); + let e = _mm_setr_epi64x(0, 2); + assert_eq_m128i(r, e); + } + test_mm_maskload_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maskload_epi64() { + let nums = [1_i64, 2_i64, 3_i64, 4_i64]; + let a = &nums as *const i64; + let mask = _mm256_setr_epi64x(0, -1, -1, 0); + let r = _mm256_maskload_epi64(a, mask); + let e = _mm256_setr_epi64x(0, 2, 3, 0); + assert_eq_m256i(r, e); + + // Unaligned pointer + let a = Unaligned::new([1i64, 2, 3, 4]); + let mask = _mm256_setr_epi64x(0, !0, 0, !0); + let r = _mm256_maskload_epi64(a.as_ptr().cast(), mask); + let e = _mm256_setr_epi64x(0, 2, 0, 4); + assert_eq_m256i(r, e); + + // Only loading first element, so slice can be short. + let a = &[2i64]; + let mask = _mm256_setr_epi64x(!0, 0, 0, 0); + let r = _mm256_maskload_epi64(a.as_ptr(), mask); + let e = _mm256_setr_epi64x(2, 0, 0, 0); + assert_eq_m256i(r, e); + + // Only loading last element, so slice can be short. + let a = &[2i64]; + let mask = _mm256_setr_epi64x(0, 0, 0, !0); + let r = _mm256_maskload_epi64(a.as_ptr().wrapping_sub(3), mask); + let e = _mm256_setr_epi64x(0, 0, 0, 2); + assert_eq_m256i(r, e); + } + test_mm256_maskload_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_maskstore_epi32() { + let a = _mm_setr_epi32(1, 2, 3, 4); + let mut arr = [-1, -1, -1, -1]; + let mask = _mm_setr_epi32(-1, 0, 0, -1); + _mm_maskstore_epi32(arr.as_mut_ptr(), mask, a); + let e = [1, -1, -1, 4]; + assert_eq!(arr, e); + + // Unaligned pointer + let mut r = Unaligned::new([0i32; 4]); + let mask = _mm_setr_epi32(0, !0, 0, !0); + let a = _mm_setr_epi32(1, 2, 3, 4); + _mm_maskstore_epi32(r.as_mut_ptr().cast(), mask, a); + let e = [0i32, 2, 0, 4]; + assert_eq!(r.read(), e); + + // Only storing first element, so slice can be short. + let mut r = [0i32]; + let mask = _mm_setr_epi32(!0, 0, 0, 0); + let a = _mm_setr_epi32(1, 2, 3, 4); + _mm_maskstore_epi32(r.as_mut_ptr(), mask, a); + let e = [1i32]; + assert_eq!(r, e); + + // Only storing last element, so slice can be short. + let mut r = [0i32]; + let mask = _mm_setr_epi32(0, 0, 0, !0); + let a = _mm_setr_epi32(1, 2, 3, 4); + _mm_maskstore_epi32(r.as_mut_ptr().wrapping_sub(3), mask, a); + let e = [4i32]; + assert_eq!(r, e); + } + test_mm_maskstore_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maskstore_epi32() { + let a = _mm256_setr_epi32(1, 0x6d726f, 3, 42, 0x777161, 6, 7, 8); + let mut arr = [-1, -1, -1, 0x776173, -1, 0x68657265, -1, -1]; + let mask = _mm256_setr_epi32(-1, 0, 0, -1, 0, -1, -1, 0); + _mm256_maskstore_epi32(arr.as_mut_ptr(), mask, a); + let e = [1, -1, -1, 42, -1, 6, 7, -1]; + assert_eq!(arr, e); + + // Unaligned pointer + let mut r = Unaligned::new([0i32; 8]); + let mask = _mm256_setr_epi32(0, !0, 0, !0, 0, !0, 0, !0); + let a = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); + _mm256_maskstore_epi32(r.as_mut_ptr().cast(), mask, a); + let e = [0i32, 2, 0, 4, 0, 6, 0, 8]; + assert_eq!(r.read(), e); + + // Only storing first element, so slice can be short. + let mut r = [0i32]; + let mask = _mm256_setr_epi32(!0, 0, 0, 0, 0, 0, 0, 0); + let a = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); + _mm256_maskstore_epi32(r.as_mut_ptr(), mask, a); + let e = [1i32]; + assert_eq!(r, e); + + // Only storing last element, so slice can be short. + let mut r = [0i32]; + let mask = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, !0); + let a = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); + _mm256_maskstore_epi32(r.as_mut_ptr().wrapping_sub(7), mask, a); + let e = [8i32]; + assert_eq!(r, e); + } + test_mm256_maskstore_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_maskstore_epi64() { + let a = _mm_setr_epi64x(1_i64, 2_i64); + let mut arr = [-1_i64, -1_i64]; + let mask = _mm_setr_epi64x(0, -1); + _mm_maskstore_epi64(arr.as_mut_ptr(), mask, a); + let e = [-1, 2]; + assert_eq!(arr, e); + + // Unaligned pointer + let mut r = Unaligned::new([0i64; 2]); + let mask = _mm_setr_epi64x(0, !0); + let a = _mm_setr_epi64x(1, 2); + _mm_maskstore_epi64(r.as_mut_ptr().cast(), mask, a); + let e = [0i64, 2]; + assert_eq!(r.read(), e); + + // Only storing first element, so slice can be short. + let mut r = [0i64]; + let mask = _mm_setr_epi64x(!0, 0); + let a = _mm_setr_epi64x(1, 2); + _mm_maskstore_epi64(r.as_mut_ptr(), mask, a); + let e = [1i64]; + assert_eq!(r, e); + + // Only storing last element, so slice can be short. + let mut r = [0i64]; + let mask = _mm_setr_epi64x(0, !0); + let a = _mm_setr_epi64x(1, 2); + _mm_maskstore_epi64(r.as_mut_ptr().wrapping_sub(1), mask, a); + let e = [2i64]; + assert_eq!(r, e); + } + test_mm_maskstore_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_maskstore_epi64() { + let a = _mm256_setr_epi64x(1_i64, 2_i64, 3_i64, 4_i64); + let mut arr = [-1_i64, -1_i64, -1_i64, -1_i64]; + let mask = _mm256_setr_epi64x(0, -1, -1, 0); + _mm256_maskstore_epi64(arr.as_mut_ptr(), mask, a); + let e = [-1, 2, 3, -1]; + assert_eq!(arr, e); + + // Unaligned pointer + let mut r = Unaligned::new([0i64; 4]); + let mask = _mm256_setr_epi64x(0, !0, 0, !0); + let a = _mm256_setr_epi64x(1, 2, 3, 4); + _mm256_maskstore_epi64(r.as_mut_ptr().cast(), mask, a); + let e = [0i64, 2, 0, 4]; + assert_eq!(r.read(), e); + + // Only storing first element, so slice can be short. + let mut r = [0i64]; + let mask = _mm256_setr_epi64x(!0, 0, 0, 0); + let a = _mm256_setr_epi64x(1, 2, 3, 4); + _mm256_maskstore_epi64(r.as_mut_ptr(), mask, a); + let e = [1i64]; + assert_eq!(r, e); + + // Only storing last element, so slice can be short. + let mut r = [0i64]; + let mask = _mm256_setr_epi64x(0, 0, 0, !0); + let a = _mm256_setr_epi64x(1, 2, 3, 4); + _mm256_maskstore_epi64(r.as_mut_ptr().wrapping_sub(3), mask, a); + let e = [4i64]; + assert_eq!(r, e); + } + test_mm256_maskstore_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mpsadbw_epu8() { + let a = _mm256_setr_epi8( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 2, 4, 6, 8, 10, 12, 14, 16, + 18, 20, 22, 24, 26, 28, 30, + ); + + let r = _mm256_mpsadbw_epu8::<0b000>(a, a); + let e = _mm256_setr_epi16(0, 4, 8, 12, 16, 20, 24, 28, 0, 8, 16, 24, 32, 40, 48, 56); + assert_eq_m256i(r, e); + + let r = _mm256_mpsadbw_epu8::<0b001>(a, a); + let e = _mm256_setr_epi16(16, 12, 8, 4, 0, 4, 8, 12, 32, 24, 16, 8, 0, 8, 16, 24); + assert_eq_m256i(r, e); + + let r = _mm256_mpsadbw_epu8::<0b100>(a, a); + let e = _mm256_setr_epi16(16, 20, 24, 28, 32, 36, 40, 44, 32, 40, 48, 56, 64, 72, 80, 88); + assert_eq_m256i(r, e); + + let r = _mm256_mpsadbw_epu8::<0b101>(a, a); + let e = _mm256_setr_epi16(0, 4, 8, 12, 16, 20, 24, 28, 0, 8, 16, 24, 32, 40, 48, 56); + assert_eq_m256i(r, e); + + let r = _mm256_mpsadbw_epu8::<0b111>(a, a); + let e = _mm256_setr_epi16(32, 28, 24, 20, 16, 12, 8, 4, 64, 56, 48, 40, 32, 24, 16, 8); + assert_eq_m256i(r, e); + } + test_mm256_mpsadbw_epu8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_mulhrs_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_mullo_epi16(a, b); + let e = _mm256_set1_epi16(8); + assert_eq_m256i(r, e); + } + test_mm256_mulhrs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_packs_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_packs_epi16(a, b); + #[rustfmt::skip] + let e = _mm256_setr_epi8( + 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, + ); + + assert_eq_m256i(r, e); + } + test_mm256_packs_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_packs_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(4); + let r = _mm256_packs_epi32(a, b); + let e = _mm256_setr_epi16(2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 2, 4, 4, 4, 4); + + assert_eq_m256i(r, e); + } + test_mm256_packs_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_packus_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(4); + let r = _mm256_packus_epi16(a, b); + #[rustfmt::skip] + let e = _mm256_setr_epi8( + 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, + ); + + assert_eq_m256i(r, e); + } + test_mm256_packus_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_packus_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(4); + let r = _mm256_packus_epi32(a, b); + let e = _mm256_setr_epi16(2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 2, 4, 4, 4, 4); + + assert_eq_m256i(r, e); + } + test_mm256_packus_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_permutevar8x32_epi32() { + let a = _mm256_setr_epi32(100, 200, 300, 400, 500, 600, 700, 800); + let b = _mm256_setr_epi32(5, 0, 5, 1, 7, 6, 3, 4); + let expected = _mm256_setr_epi32(600, 100, 600, 200, 800, 700, 400, 500); + let r = _mm256_permutevar8x32_epi32(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_permutevar8x32_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_permute2x128_si256() { + let a = _mm256_setr_epi64x(100, 200, 500, 600); + let b = _mm256_setr_epi64x(300, 400, 700, 800); + let r = _mm256_permute2x128_si256::<0b00_01_00_11>(a, b); + let e = _mm256_setr_epi64x(700, 800, 500, 600); + assert_eq_m256i(r, e); + } + test_mm256_permute2x128_si256(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_permutevar8x32_ps() { + let a = _mm256_setr_ps(1., 2., 3., 4., 5., 6., 7., 8.); + let b = _mm256_setr_epi32(5, 0, 5, 1, 7, 6, 3, 4); + let r = _mm256_permutevar8x32_ps(a, b); + let e = _mm256_setr_ps(6., 1., 6., 2., 8., 7., 4., 5.); + assert_eq_m256(r, e); + } + test_mm256_permutevar8x32_ps(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sad_epu8() { + let a = _mm256_set1_epi8(2); + let b = _mm256_set1_epi8(4); + let r = _mm256_sad_epu8(a, b); + let e = _mm256_set1_epi64x(16); + assert_eq_m256i(r, e); + } + test_mm256_sad_epu8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_shuffle_epi8() { + #[rustfmt::skip] + let a = _mm256_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + ); + #[rustfmt::skip] + let b = _mm256_setr_epi8( + 4, 128u8 as i8, 4, 3, 24, 12, 6, 19, + 12, 5, 5, 10, 4, 1, 8, 0, + 4, 128u8 as i8, 4, 3, 24, 12, 6, 19, + 12, 5, 5, 10, 4, 1, 8, 0, + ); + #[rustfmt::skip] + let expected = _mm256_setr_epi8( + 5, 0, 5, 4, 9, 13, 7, 4, + 13, 6, 6, 11, 5, 2, 9, 1, + 21, 0, 21, 20, 25, 29, 23, 20, + 29, 22, 22, 27, 21, 18, 25, 17, + ); + let r = _mm256_shuffle_epi8(a, b); + assert_eq_m256i(r, expected); + } + test_mm256_shuffle_epi8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sign_epi16() { + let a = _mm256_set1_epi16(2); + let b = _mm256_set1_epi16(-1); + let r = _mm256_sign_epi16(a, b); + let e = _mm256_set1_epi16(-2); + assert_eq_m256i(r, e); + } + test_mm256_sign_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sign_epi32() { + let a = _mm256_set1_epi32(2); + let b = _mm256_set1_epi32(-1); + let r = _mm256_sign_epi32(a, b); + let e = _mm256_set1_epi32(-2); + assert_eq_m256i(r, e); + } + test_mm256_sign_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sign_epi8() { + let a = _mm256_set1_epi8(2); + let b = _mm256_set1_epi8(-1); + let r = _mm256_sign_epi8(a, b); + let e = _mm256_set1_epi8(-2); + assert_eq_m256i(r, e); + } + test_mm256_sign_epi8(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sll_epi16() { + let a = _mm256_setr_epi16( + 0x88, -0x88, 0x99, -0x99, 0xAA, -0xAA, 0xBB, -0xBB, 0xCC, -0xCC, 0xDD, -0xDD, 0xEE, + -0xEE, 0xFF, -0xFF, + ); + let r = _mm256_sll_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi16( + 0x880, -0x880, 0x990, -0x990, 0xAA0, -0xAA0, 0xBB0, -0xBB0, 0xCC0, -0xCC0, 0xDD0, + -0xDD0, 0xEE0, -0xEE0, 0xFF0, -0xFF0, + ), + ); + let r = _mm256_sll_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sll_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m256i(r, _mm256_set1_epi16(0)); + let r = _mm256_sll_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi16(0)); + } + test_mm256_sll_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sll_epi32() { + let a = + _mm256_setr_epi32(0xCCCC, -0xCCCC, 0xDDDD, -0xDDDD, 0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm256_sll_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi32( + 0xCCCC0, -0xCCCC0, 0xDDDD0, -0xDDDD0, 0xEEEE0, -0xEEEE0, 0xFFFF0, -0xFFFF0, + ), + ); + let r = _mm256_sll_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sll_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m256i(r, _mm256_set1_epi32(0)); + let r = _mm256_sll_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi32(0)); + } + test_mm256_sll_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sll_epi64() { + let a = _mm256_set_epi64x(0xEEEEEEEE, -0xEEEEEEEE, 0xFFFFFFFF, -0xFFFFFFFF); + let r = _mm256_sll_epi64(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i(r, _mm256_set_epi64x(0xEEEEEEEE0, -0xEEEEEEEE0, 0xFFFFFFFF0, -0xFFFFFFFF0)); + let r = _mm256_sll_epi64(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sll_epi64(a, _mm_set_epi64x(0, 64)); + assert_eq_m256i(r, _mm256_set1_epi64x(0)); + let r = _mm256_sll_epi64(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi64x(0)); + } + test_mm256_sll_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sra_epi16() { + let a = _mm256_setr_epi16( + 0x88, -0x88, 0x99, -0x99, 0xAA, -0xAA, 0xBB, -0xBB, 0xCC, -0xCC, 0xDD, -0xDD, 0xEE, + -0xEE, 0xFF, -0xFF, + ); + let r = _mm256_sra_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi16( + 0x8, -0x9, 0x9, -0xA, 0xA, -0xB, 0xB, -0xC, 0xC, -0xD, 0xD, -0xE, 0xE, -0xF, 0xF, + -0x10, + ), + ); + let r = _mm256_sra_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sra_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m256i( + r, + _mm256_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1), + ); + let r = _mm256_sra_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i( + r, + _mm256_setr_epi16(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1), + ); + } + test_mm256_sra_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sra_epi32() { + let a = + _mm256_setr_epi32(0xCCCC, -0xCCCC, 0xDDDD, -0xDDDD, 0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm256_sra_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi32(0xCCC, -0xCCD, 0xDDD, -0xDDE, 0xEEE, -0xEEF, 0xFFF, -0x1000), + ); + let r = _mm256_sra_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_sra_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m256i(r, _mm256_setr_epi32(0, -1, 0, -1, 0, -1, 0, -1)); + let r = _mm256_sra_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_setr_epi32(0, -1, 0, -1, 0, -1, 0, -1)); + } + test_mm256_sra_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srl_epi16() { + let a = _mm256_setr_epi16( + 0x88, -0x88, 0x99, -0x99, 0xAA, -0xAA, 0xBB, -0xBB, 0xCC, -0xCC, 0xDD, -0xDD, 0xEE, + -0xEE, 0xFF, -0xFF, + ); + let r = _mm256_srl_epi16(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi16( + 0x8, 0xFF7, 0x9, 0xFF6, 0xA, 0xFF5, 0xB, 0xFF4, 0xC, 0xFF3, 0xD, 0xFF2, 0xE, 0xFF1, + 0xF, 0xFF0, + ), + ); + let r = _mm256_srl_epi16(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_srl_epi16(a, _mm_set_epi64x(0, 16)); + assert_eq_m256i(r, _mm256_set1_epi16(0)); + let r = _mm256_srl_epi16(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi16(0)); + } + test_mm256_srl_epi16(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srl_epi32() { + let a = + _mm256_setr_epi32(0xCCCC, -0xCCCC, 0xDDDD, -0xDDDD, 0xEEEE, -0xEEEE, 0xFFFF, -0xFFFF); + let r = _mm256_srl_epi32(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_setr_epi32( + 0xCCC, 0xFFFF333, 0xDDD, 0xFFFF222, 0xEEE, 0xFFFF111, 0xFFF, 0xFFFF000, + ), + ); + let r = _mm256_srl_epi32(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_srl_epi32(a, _mm_set_epi64x(0, 32)); + assert_eq_m256i(r, _mm256_set1_epi32(0)); + let r = _mm256_srl_epi32(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi32(0)); + } + test_mm256_srl_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srl_epi64() { + let a = _mm256_set_epi64x(0xEEEEEEEE, -0xEEEEEEEE, 0xFFFFFFFF, -0xFFFFFFFF); + let r = _mm256_srl_epi64(a, _mm_set_epi64x(0, 4)); + assert_eq_m256i( + r, + _mm256_set_epi64x(0xEEEEEEE, 0xFFFFFFFF1111111, 0xFFFFFFF, 0xFFFFFFFF0000000), + ); + let r = _mm256_srl_epi64(a, _mm_set_epi64x(4, 0)); + assert_eq_m256i(r, a); + let r = _mm256_srl_epi64(a, _mm_set_epi64x(0, 64)); + assert_eq_m256i(r, _mm256_set1_epi64x(0)); + let r = _mm256_srl_epi64(a, _mm_set_epi64x(0, i64::MAX)); + assert_eq_m256i(r, _mm256_set1_epi64x(0)); + } + test_mm256_srl_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_sllv_epi32() { + let a = _mm_set_epi32(1, 2, 3, 4); + let b = _mm_set_epi32(4, 3, 2, 1); + let r = _mm_sllv_epi32(a, b); + let e = _mm_set_epi32(16, 16, 12, 8); + assert_eq_m128i(r, e); + } + test_mm_sllv_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sllv_epi32() { + let a = _mm256_set_epi32(1, 2, 3, 4, 5, 6, 7, 8); + let b = _mm256_set_epi32(8, 7, 6, 5, 4, 3, 2, 1); + let r = _mm256_sllv_epi32(a, b); + let e = _mm256_set_epi32(256, 256, 192, 128, 80, 48, 28, 16); + assert_eq_m256i(r, e); + } + test_mm256_sllv_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_sllv_epi64() { + let a = _mm_set_epi64x(2, 3); + let b = _mm_set_epi64x(1, 2); + let r = _mm_sllv_epi64(a, b); + let e = _mm_set_epi64x(4, 12); + assert_eq_m128i(r, e); + } + test_mm_sllv_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_sllv_epi64() { + let a = _mm256_set_epi64x(1, 2, 3, 4); + let b = _mm256_set_epi64x(4, 3, 2, 1); + let r = _mm256_sllv_epi64(a, b); + let e = _mm256_set_epi64x(16, 16, 12, 8); + assert_eq_m256i(r, e); + } + test_mm256_sllv_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_srav_epi32() { + let a = _mm_set_epi32(16, -32, 64, -128); + let b = _mm_set_epi32(4, 3, 2, 1); + let r = _mm_srav_epi32(a, b); + let e = _mm_set_epi32(1, -4, 16, -64); + assert_eq_m128i(r, e); + } + test_mm_srav_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srav_epi32() { + let a = _mm256_set_epi32(256, -512, 1024, -2048, 4096, -8192, 16384, -32768); + let b = _mm256_set_epi32(8, 7, 6, 5, 4, 3, 2, 1); + let r = _mm256_srav_epi32(a, b); + let e = _mm256_set_epi32(1, -4, 16, -64, 256, -1024, 4096, -16384); + assert_eq_m256i(r, e); + } + test_mm256_srav_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_srlv_epi32() { + let a = _mm_set_epi32(16, 32, 64, 128); + let b = _mm_set_epi32(4, 3, 2, 1); + let r = _mm_srlv_epi32(a, b); + let e = _mm_set_epi32(1, 4, 16, 64); + assert_eq_m128i(r, e); + } + test_mm_srlv_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srlv_epi32() { + let a = _mm256_set_epi32(256, 512, 1024, 2048, 4096, 8192, 16384, 32768); + let b = _mm256_set_epi32(8, 7, 6, 5, 4, 3, 2, 1); + let r = _mm256_srlv_epi32(a, b); + let e = _mm256_set_epi32(1, 4, 16, 64, 256, 1024, 4096, 16384); + assert_eq_m256i(r, e); + } + test_mm256_srlv_epi32(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm_srlv_epi64() { + let a = _mm_set_epi64x(4, 8); + let b = _mm_set_epi64x(2, 1); + let r = _mm_srlv_epi64(a, b); + let e = _mm_set_epi64x(1, 4); + assert_eq_m128i(r, e); + } + test_mm_srlv_epi64(); + + #[target_feature(enable = "avx2")] + unsafe fn test_mm256_srlv_epi64() { + let a = _mm256_set_epi64x(16, 32, 64, 128); + let b = _mm256_set_epi64x(4, 3, 2, 1); + let r = _mm256_srlv_epi64(a, b); + let e = _mm256_set_epi64x(1, 4, 16, 64); + assert_eq_m256i(r, e); + } + test_mm256_srlv_epi64(); +} + +#[target_feature(enable = "sse2")] +unsafe fn _mm_setr_epi64x(a: i64, b: i64) -> __m128i { + _mm_set_epi64x(b, a) +} + +#[track_caller] +#[target_feature(enable = "sse")] +unsafe fn assert_eq_m128(a: __m128, b: __m128) { + let r = _mm_cmpeq_ps(a, b); + if _mm_movemask_ps(r) != 0b1111 { + panic!("{:?} != {:?}", a, b); + } +} + +#[track_caller] +#[target_feature(enable = "sse2")] +unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { + if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { + panic!("{:?} != {:?}", a, b); + } +} + +#[track_caller] +#[target_feature(enable = "sse2")] +unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) { + assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b)) +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256(a: __m256, b: __m256) { + let cmp = _mm256_cmp_ps::<_CMP_EQ_OQ>(a, b); + if _mm256_movemask_ps(cmp) != 0b11111111 { + panic!("{:?} != {:?}", a, b); + } +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256d(a: __m256d, b: __m256d) { + let cmp = _mm256_cmp_pd::<_CMP_EQ_OQ>(a, b); + if _mm256_movemask_pd(cmp) != 0b1111 { + panic!("{:?} != {:?}", a, b); + } +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) { + assert_eq!(transmute::<_, [u64; 4]>(a), transmute::<_, [u64; 4]>(b)) +} + +/// Stores `T` in an unaligned address +struct Unaligned<T: Copy> { + buf: Vec<u8>, + offset: bool, + _marker: std::marker::PhantomData<T>, +} + +impl<T: Copy> Unaligned<T> { + fn new(value: T) -> Self { + // Allocate extra byte for unalignment headroom + let len = std::mem::size_of::<T>(); + let mut buf = Vec::<u8>::with_capacity(len + 1); + // Force the address to be a non-multiple of 2, so it is as unaligned as it can get. + let offset = (buf.as_ptr() as usize % 2) == 0; + let value_ptr: *const T = &value; + unsafe { + buf.as_mut_ptr().add(offset.into()).copy_from_nonoverlapping(value_ptr.cast(), len); + } + Self { buf, offset, _marker: std::marker::PhantomData } + } + + fn as_ptr(&self) -> *const T { + unsafe { self.buf.as_ptr().add(self.offset.into()).cast() } + } + + fn as_mut_ptr(&mut self) -> *mut T { + unsafe { self.buf.as_mut_ptr().add(self.offset.into()).cast() } + } + + fn read(&self) -> T { + unsafe { self.as_ptr().read_unaligned() } + } +} diff --git a/src/tools/miri/tests/pass/issues/issue-miri-1909.rs b/src/tools/miri/tests/pass/issues/issue-miri-1909.rs index ce2114e760a..8a2e67cdd09 100644 --- a/src/tools/miri/tests/pass/issues/issue-miri-1909.rs +++ b/src/tools/miri/tests/pass/issues/issue-miri-1909.rs @@ -9,7 +9,7 @@ use std::alloc::System; /// `ptr` must be valid for writes of `len` bytes unsafe fn volatile_write_zeroize_mem(ptr: *mut u8, len: usize) { for i in 0..len { - // ptr as usize + i can't overlow because `ptr` is valid for writes of `len` + // ptr as usize + i can't overflow because `ptr` is valid for writes of `len` let ptr_new: *mut u8 = ((ptr as usize) + i) as *mut u8; // SAFETY: `ptr` is valid for writes of `len` bytes, so `ptr_new` is valid for a // byte write diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs index cdb441b450b..1fc713d48dc 100644 --- a/src/tools/miri/tests/pass/portable-simd.rs +++ b/src/tools/miri/tests/pass/portable-simd.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -#![feature(portable_simd, adt_const_params, inline_const, core_intrinsics)] +#![feature(portable_simd, adt_const_params, core_intrinsics)] #![allow(incomplete_features, internal_features)] use std::intrinsics::simd as intrinsics; use std::ptr; diff --git a/src/tools/miri/tests/pass/shims/env/home.rs b/src/tools/miri/tests/pass/shims/env/home.rs index 9eb9c3af569..c237f9ed9ff 100644 --- a/src/tools/miri/tests/pass/shims/env/home.rs +++ b/src/tools/miri/tests/pass/shims/env/home.rs @@ -1,9 +1,9 @@ -//@ignore-target-windows: home_dir is not supported on Windows //@compile-flags: -Zmiri-disable-isolation use std::env; fn main() { env::remove_var("HOME"); // make sure we enter the interesting codepath + env::remove_var("USERPROFILE"); // Windows also looks as this env var #[allow(deprecated)] env::home_dir().unwrap(); } diff --git a/src/tools/miri/tests/pass/shims/env/var-set.rs b/src/tools/miri/tests/pass/shims/env/var-set.rs new file mode 100644 index 00000000000..2875b6c815a --- /dev/null +++ b/src/tools/miri/tests/pass/shims/env/var-set.rs @@ -0,0 +1,7 @@ +// Test a value set on the host (MIRI_ENV_VAR_TEST) and one that is not. +//@compile-flags: -Zmiri-env-set=MIRI_ENV_VAR_TEST=test_value_1 -Zmiri-env-set=TEST_VAR_2=test_value_2 + +fn main() { + assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("test_value_1".to_owned())); + assert_eq!(std::env::var("TEST_VAR_2"), Ok("test_value_2".to_owned())); +} diff --git a/src/tools/miri/tests/pass/shims/path.rs b/src/tools/miri/tests/pass/shims/path.rs index 9fc6e7faefb..cadbeb476bd 100644 --- a/src/tools/miri/tests/pass/shims/path.rs +++ b/src/tools/miri/tests/pass/shims/path.rs @@ -1,5 +1,4 @@ //@compile-flags: -Zmiri-disable-isolation -#![feature(absolute_path)] use std::path::{absolute, Path}; #[track_caller] diff --git a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs index c4b15c8758b..259fc72d392 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs @@ -1,6 +1,6 @@ // See https://github.com/rust-lang/unsafe-code-guidelines/issues/148: // this fails when Stacked Borrows is strictly applied even to `!Unpin` types. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ ops::{Coroutine, CoroutineState}, @@ -8,6 +8,7 @@ use std::{ }; fn firstn() -> impl Coroutine<Yield = u64, Return = ()> { + #[coroutine] static move || { let mut num = 0; let num = &mut num; diff --git a/src/tools/miri/tests/pass/track-caller-attribute.rs b/src/tools/miri/tests/pass/track-caller-attribute.rs index d88bcc98858..c3803af3cc8 100644 --- a/src/tools/miri/tests/pass/track-caller-attribute.rs +++ b/src/tools/miri/tests/pass/track-caller-attribute.rs @@ -232,7 +232,7 @@ fn test_coroutine() { } #[rustfmt::skip] - let coroutine = #[track_caller] |arg: String| { + let coroutine = #[track_caller] #[coroutine] |arg: String| { yield ("first", arg.clone(), Location::caller()); yield ("second", arg.clone(), Location::caller()); }; @@ -255,7 +255,7 @@ fn test_coroutine() { assert_eq!(mono_loc.column(), 42); #[rustfmt::skip] - let non_tracked_coroutine = || { yield Location::caller(); }; + let non_tracked_coroutine = #[coroutine] || { yield Location::caller(); }; let non_tracked_line = line!() - 1; // This is the line of the coroutine, not its caller let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) { CoroutineState::Yielded(val) => val, @@ -263,7 +263,7 @@ fn test_coroutine() { }; assert_eq!(non_tracked_loc.file(), file!()); assert_eq!(non_tracked_loc.line(), non_tracked_line); - assert_eq!(non_tracked_loc.column(), 44); + assert_eq!(non_tracked_loc.column(), 57); } fn main() { diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 3ea35c7940c..61a24c97e77 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -5,5 +5,6 @@ edition = "2021" [dependencies] object = "0.34.0" +similar = "2.5.0" wasmparser = "0.118.2" regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs new file mode 100644 index 00000000000..54532c6e35b --- /dev/null +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -0,0 +1,81 @@ +use similar::TextDiff; +use std::path::Path; + +#[cfg(test)] +mod tests; + +pub fn diff() -> Diff { + Diff::new() +} + +#[derive(Debug)] +pub struct Diff { + expected: Option<String>, + expected_name: Option<String>, + actual: Option<String>, + actual_name: Option<String>, +} + +impl Diff { + /// Construct a bare `diff` invocation. + pub fn new() -> Self { + Self { expected: None, expected_name: None, actual: None, actual_name: None } + } + + /// Specify the expected output for the diff from a file. + pub fn expected_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + let path = path.as_ref(); + let content = std::fs::read_to_string(path).expect("failed to read file"); + let name = path.to_string_lossy().to_string(); + + self.expected = Some(content); + self.expected_name = Some(name); + self + } + + /// Specify the expected output for the diff from a given text string. + pub fn expected_text<T: AsRef<[u8]>>(&mut self, name: &str, text: T) -> &mut Self { + self.expected = Some(String::from_utf8_lossy(text.as_ref()).to_string()); + self.expected_name = Some(name.to_string()); + self + } + + /// Specify the actual output for the diff from a file. + pub fn actual_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + let path = path.as_ref(); + let content = std::fs::read_to_string(path).expect("failed to read file"); + let name = path.to_string_lossy().to_string(); + + self.actual = Some(content); + self.actual_name = Some(name); + self + } + + /// Specify the actual output for the diff from a given text string. + pub fn actual_text<T: AsRef<[u8]>>(&mut self, name: &str, text: T) -> &mut Self { + self.actual = Some(String::from_utf8_lossy(text.as_ref()).to_string()); + self.actual_name = Some(name.to_string()); + self + } + + /// Executes the diff process, prints any differences to the standard error. + #[track_caller] + pub fn run(&self) { + let expected = self.expected.as_ref().expect("expected text not set"); + let actual = self.actual.as_ref().expect("actual text not set"); + let expected_name = self.expected_name.as_ref().unwrap(); + let actual_name = self.actual_name.as_ref().unwrap(); + + let output = TextDiff::from_lines(expected, actual) + .unified_diff() + .header(expected_name, actual_name) + .to_string(); + + if !output.is_empty() { + panic!( + "test failed: `{}` is different from `{}`\n\n{}", + expected_name, actual_name, output + ) + } + } +} diff --git a/src/tools/run-make-support/src/diff/tests.rs b/src/tools/run-make-support/src/diff/tests.rs new file mode 100644 index 00000000000..e6d72544b7e --- /dev/null +++ b/src/tools/run-make-support/src/diff/tests.rs @@ -0,0 +1,39 @@ +#[cfg(test)] +mod tests { + use crate::*; + + #[test] + fn test_diff() { + let expected = "foo\nbar\nbaz\n"; + let actual = "foo\nbar\nbaz\n"; + diff().expected_text("EXPECTED_TEXT", expected).actual_text("ACTUAL_TEXT", actual).run(); + } + + #[test] + fn test_should_panic() { + let expected = "foo\nbar\nbaz\n"; + let actual = "foo\nbaz\nbar\n"; + + let output = std::panic::catch_unwind(|| { + diff() + .expected_text("EXPECTED_TEXT", expected) + .actual_text("ACTUAL_TEXT", actual) + .run(); + }) + .unwrap_err(); + + let expected_output = "\ +test failed: `EXPECTED_TEXT` is different from `ACTUAL_TEXT` + +--- EXPECTED_TEXT ++++ ACTUAL_TEXT +@@ -1,3 +1,3 @@ + foo ++baz + bar +-baz +"; + + assert_eq!(output.downcast_ref::<String>().unwrap(), expected_output); + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index e723e824ed6..76e8838d27c 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -5,6 +5,7 @@ pub mod cc; pub mod clang; +pub mod diff; pub mod llvm_readobj; pub mod run; pub mod rustc; @@ -20,6 +21,7 @@ pub use wasmparser; pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; +pub use diff::{diff, Diff}; pub use llvm_readobj::{llvm_readobj, LlvmReadobj}; pub use run::{run, run_fail}; pub use rustc::{aux_build, rustc, Rustc}; diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 9bf41c6e2e9..ddaae3236c2 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -148,6 +148,13 @@ impl Rustc { self } + /// Specify the print request. + pub fn print(&mut self, request: &str) -> &mut Self { + self.cmd.arg("--print"); + self.cmd.arg(request); + self + } + /// Add an extra argument to the linker invocation, via `-Clink-arg`. pub fn link_arg(&mut self, link_arg: &str) -> &mut Self { self.cmd.arg(format!("-Clink-arg={link_arg}")); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index d50088e6cf1..c92d4e78ffa 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -3869,7 +3869,7 @@ use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo" }; @@ -3901,7 +3901,7 @@ use std::ops::Coroutine; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { println!("2"); yield; println!("4"); @@ -4007,7 +4007,7 @@ use std::pin::Pin; fn main() { let ret = "foo"; - let mut coroutine = move || { + let mut coroutine = #[coroutine] move || { yield 1; return ret }; diff --git a/src/tools/rustfmt/tests/source/immovable_coroutines.rs b/src/tools/rustfmt/tests/source/immovable_coroutines.rs index 3b94af0c96c..539049577a0 100644 --- a/src/tools/rustfmt/tests/source/immovable_coroutines.rs +++ b/src/tools/rustfmt/tests/source/immovable_coroutines.rs @@ -1,7 +1,8 @@ #![feature(coroutines)] unsafe fn foo() { - let mut ga = static || { + let mut ga = #[coroutine] + static || { yield 1; }; } diff --git a/src/tools/rustfmt/tests/target/immovable_coroutines.rs b/src/tools/rustfmt/tests/target/immovable_coroutines.rs index f52cfa00f97..539049577a0 100644 --- a/src/tools/rustfmt/tests/target/immovable_coroutines.rs +++ b/src/tools/rustfmt/tests/target/immovable_coroutines.rs @@ -1,7 +1,8 @@ #![feature(coroutines)] unsafe fn foo() { - let mut ga = static || { + let mut ga = #[coroutine] + static || { yield 1; }; } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index f0ed0ae806f..9b3c0d0f1a5 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -189,7 +189,6 @@ run-make/no-builtins-attribute/Makefile run-make/no-builtins-lto/Makefile run-make/no-cdylib-as-rdylib/Makefile run-make/no-duplicate-libs/Makefile -run-make/no-input-file/Makefile run-make/no-intermediate-extras/Makefile run-make/obey-crate-type-flag/Makefile run-make/optimization-remarks-dir-pgo/Makefile @@ -317,7 +316,6 @@ run-make/unstable-flag-required/Makefile run-make/use-suggestions-rust-2018/Makefile run-make/used-cdylib-macos/Makefile run-make/used/Makefile -run-make/valid-print-requests/Makefile run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile diff --git a/tests/codegen/const_scalar_pair.rs b/tests/codegen/const_scalar_pair.rs index 0aa430a8efa..f142896c31f 100644 --- a/tests/codegen/const_scalar_pair.rs +++ b/tests/codegen/const_scalar_pair.rs @@ -1,7 +1,5 @@ //@ compile-flags: --crate-type=lib -Copt-level=0 -Zmir-opt-level=0 -C debuginfo=2 -#![feature(inline_const)] - // Test that we don't generate a memory allocation for the constant // and read the fields from that, but instead just create the value pair directly. pub fn foo() -> (i32, i32) { diff --git a/tests/codegen/coroutine-debug-msvc.rs b/tests/codegen/coroutine-debug-msvc.rs index fb1b46fe497..e2296db1d59 100644 --- a/tests/codegen/coroutine-debug-msvc.rs +++ b/tests/codegen/coroutine-debug-msvc.rs @@ -11,7 +11,7 @@ use std::ops::Coroutine; fn coroutine_test() -> impl Coroutine<Yield = i32, Return = ()> { - || { + #[coroutine] || { yield 0; let s = String::from("foo"); yield 1; diff --git a/tests/codegen/coroutine-debug.rs b/tests/codegen/coroutine-debug.rs index 7eaee669559..914515f58b8 100644 --- a/tests/codegen/coroutine-debug.rs +++ b/tests/codegen/coroutine-debug.rs @@ -11,7 +11,7 @@ use std::ops::Coroutine; fn coroutine_test() -> impl Coroutine<Yield = i32, Return = ()> { - || { + #[coroutine] || { yield 0; let s = String::from("foo"); yield 1; diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index 2b27dab078d..ebcbcae8563 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -197,7 +197,7 @@ pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> { x } -// CHECK: @struct_return(ptr noalias nocapture noundef sret([32 x i8]) align 4 dereferenceable(32){{( %_0)?}}) +// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias nocapture noundef{{( writable)?}} sret([32 x i8]) align 4 dereferenceable(32){{( %_0)?}}) #[no_mangle] pub fn struct_return() -> S { S { diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 76cdf7e191e..04a91bb87f7 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -4,7 +4,6 @@ #![crate_type = "lib"] #![feature(core_intrinsics)] #![feature(custom_mir)] -#![feature(inline_const)] #![allow(unreachable_code)] use std::intrinsics::{transmute, transmute_unchecked}; diff --git a/tests/codegen/issues/issue-96274.rs b/tests/codegen/issues/issue-96274.rs index d278796dd02..ffefd5f43f8 100644 --- a/tests/codegen/issues/issue-96274.rs +++ b/tests/codegen/issues/issue-96274.rs @@ -1,7 +1,6 @@ //@ compile-flags: -O #![crate_type = "lib"] -#![feature(inline_const)] use std::mem::MaybeUninit; diff --git a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs index c9be4f6d383..d978f2d2525 100644 --- a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs +++ b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs @@ -260,7 +260,7 @@ pub struct IntDoubleInt { #[no_mangle] pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} -// CHECK: define void @f_ret_int_double_int_s(ptr noalias nocapture noundef sret([24 x i8]) align 8 dereferenceable(24) %_0) +// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias nocapture noundef{{( writable)?}} sret([24 x i8]) align 8 dereferenceable(24) %_0) #[no_mangle] pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { IntDoubleInt { a: 1, b: 2., c: 3 } diff --git a/tests/codegen/maybeuninit-rvo.rs b/tests/codegen/maybeuninit-rvo.rs index 954514c736b..cc5da39a9ca 100644 --- a/tests/codegen/maybeuninit-rvo.rs +++ b/tests/codegen/maybeuninit-rvo.rs @@ -1,4 +1,6 @@ //@ compile-flags: -O +//@ needs-unwind +//@ min-llvm-version: 18 #![feature(c_unwind)] #![crate_type = "lib"] @@ -23,8 +25,8 @@ extern "C-unwind" { } pub fn new_from_uninit_unwind() -> Foo { - // CHECK-LABEL: new_from_uninit - // CHECK: call void @llvm.memcpy. + // CHECK-LABEL: new_from_uninit_unwind + // CHECK-NOT: call void @llvm.memcpy. let mut x = std::mem::MaybeUninit::uninit(); unsafe { init_unwind(x.as_mut_ptr()); diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs index ca781a99296..6c3d991af9f 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs @@ -5,7 +5,7 @@ //@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static #![crate_type="lib"] -#![feature(inline_const, type_alias_impl_trait)] +#![feature(type_alias_impl_trait)] extern crate core; diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index 488be2a8629..c416f4d28bb 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -4,7 +4,6 @@ #![crate_type = "lib"] #![allow(non_camel_case_types)] #![feature(repr_simd, intrinsics)] -#![feature(inline_const)] #[repr(simd)] #[derive(Copy, Clone)] diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index ef9faab590b..255708d365e 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -43,11 +43,11 @@ Number of file 0 mappings: 9 = ((c4 - c5) - c6) Function name: coroutine::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 1c, 01, 1f, 05, 02, 10, 01, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 29, 01, 1f, 05, 02, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 21, 28) to (start + 1, 31) +- Code(Counter(0)) at (prev + 21, 41) to (start + 1, 31) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) diff --git a/tests/coverage/coroutine.coverage b/tests/coverage/coroutine.coverage index bd3d4e46880..68b52d19831 100644 --- a/tests/coverage/coroutine.coverage +++ b/tests/coverage/coroutine.coverage @@ -1,4 +1,4 @@ - LL| |#![feature(coroutines, coroutine_trait)] + LL| |#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] LL| | LL| |use std::ops::{Coroutine, CoroutineState}; LL| |use std::pin::Pin; @@ -18,7 +18,7 @@ LL| | LL| 1|fn main() { LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| let mut coroutine = || { + LL| 1| let mut coroutine = #[coroutine] || { LL| 1| yield get_u32(is_true); LL| 1| return "foo"; LL| 1| }; diff --git a/tests/coverage/coroutine.rs b/tests/coverage/coroutine.rs index 2aa689466fc..7f72e0d8bd4 100644 --- a/tests/coverage/coroutine.rs +++ b/tests/coverage/coroutine.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -18,7 +18,7 @@ fn get_u32(val: bool) -> Result<u32, String> { fn main() { let is_true = std::env::args().len() == 1; - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield get_u32(is_true); return "foo"; }; diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index 9cc67dfe88a..0347aaaa367 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -41,21 +41,21 @@ Number of file 0 mappings: 16 - Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2) Function name: yield::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 1c, 01, 10, 05, 02, 10, 01, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 29, 01, 10, 05, 02, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 8, 28) to (start + 1, 16) +- Code(Counter(0)) at (prev + 8, 41) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) Function name: yield::main::{closure#1} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 1c, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 29, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 16) +- Code(Counter(0)) at (prev + 22, 41) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) - Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) diff --git a/tests/coverage/yield.coverage b/tests/coverage/yield.coverage index d7e455f211e..e2fc9196d24 100644 --- a/tests/coverage/yield.coverage +++ b/tests/coverage/yield.coverage @@ -1,11 +1,11 @@ - LL| |#![feature(coroutines, coroutine_trait)] + LL| |#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] LL| |#![allow(unused_assignments)] LL| | LL| |use std::ops::{Coroutine, CoroutineState}; LL| |use std::pin::Pin; LL| | LL| 1|fn main() { - LL| 1| let mut coroutine = || { + LL| 1| let mut coroutine = #[coroutine] || { LL| 1| yield 1; LL| 1| return "foo"; LL| 1| }; @@ -19,7 +19,7 @@ LL| 0| _ => panic!("unexpected value from resume"), LL| | } LL| | - LL| 1| let mut coroutine = || { + LL| 1| let mut coroutine = #[coroutine] || { LL| 1| yield 1; LL| 1| yield 2; LL| 0| yield 3; diff --git a/tests/coverage/yield.rs b/tests/coverage/yield.rs index b7e2ba31b59..64ea2706604 100644 --- a/tests/coverage/yield.rs +++ b/tests/coverage/yield.rs @@ -1,11 +1,11 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![allow(unused_assignments)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; return "foo"; }; @@ -19,7 +19,7 @@ fn main() { _ => panic!("unexpected value from resume"), } - let mut coroutine = || { + let mut coroutine = #[coroutine] || { yield 1; yield 2; yield 3; diff --git a/tests/crashes/123461.rs b/tests/crashes/123461.rs deleted file mode 100644 index 6dbfb5c8092..00000000000 --- a/tests/crashes/123461.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: #123461 - -fn main() { - let _: [_; unsafe { std::mem::transmute(|o_b: Option<_>| {}) }]; -} diff --git a/tests/debuginfo/collapse-debuginfo-external-attr.rs b/tests/debuginfo/collapse-debuginfo-external-attr.rs index fba609bf89e..4d4fa92726f 100644 --- a/tests/debuginfo/collapse-debuginfo-external-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-external-attr.rs @@ -1,5 +1,4 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that local macro debug info is not collapsed with #[collapse_debuginfo(external)] diff --git a/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs index 51aa1f8ce19..ab0ae8fef4d 100644 --- a/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs @@ -1,10 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that macro attribute #[collapse_debuginfo(no)] // overrides "collapse_macro_debuginfo=external" flag -//@ compile-flags:-g -Z collapse_macro_debuginfo=external +//@ compile-flags:-g -C collapse_macro_debuginfo=external // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/collapse-debuginfo-external-flag.rs b/tests/debuginfo/collapse-debuginfo-external-flag.rs index f9ef1ae8a25..b8e73d227b3 100644 --- a/tests/debuginfo/collapse-debuginfo-external-flag.rs +++ b/tests/debuginfo/collapse-debuginfo-external-flag.rs @@ -1,9 +1,8 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that println macro debug info is collapsed with "collapse_macro_debuginfo=external" flag -//@ compile-flags:-g -Z collapse_macro_debuginfo=external +//@ compile-flags:-g -C collapse_macro_debuginfo=external // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs b/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs index e67e1d83cdc..1aafcffa304 100644 --- a/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs +++ b/tests/debuginfo/collapse-debuginfo-in-non-collapse-macro.rs @@ -1,11 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo. // When nested macros instantiations are tagged with collapse_debuginfo attribute, // debug info should be corrected to the first outer macro instantiation // without collapse_debuginfo attribute. -// collapse_debuginfo feature enabled. //@ compile-flags:-g @@ -61,7 +59,7 @@ fn myprintln_impl(text: &str) { println!("{}", text) } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! myprintln { ($($arg:tt)*) => {{ myprintln_impl($($arg)*); diff --git a/tests/debuginfo/collapse-debuginfo-no-attr-flag.rs b/tests/debuginfo/collapse-debuginfo-no-attr-flag.rs deleted file mode 100644 index fbc7d03e0df..00000000000 --- a/tests/debuginfo/collapse-debuginfo-no-attr-flag.rs +++ /dev/null @@ -1,61 +0,0 @@ -//@ ignore-lldb -#![feature(collapse_debuginfo)] - -// Test that line numbers are not replaced with those of the outermost expansion site when the -// `collapse_debuginfo` is active, `-Zdebug-macros` is provided and `#[collapse_debuginfo]` not -// being used. - -//@ compile-flags:-g -Zdebug-macros - -// === GDB TESTS =================================================================================== - -// gdb-command:run -// gdb-command:next -// gdb-command:frame -// gdb-check:[...]#loc1[...] -// gdb-command:next -// gdb-command:frame -// gdb-check:[...]#loc2[...] -// gdb-command:next -// gdb-command:frame -// gdb-check:[...]#loc3[...] -// gdb-command:next -// gdb-command:frame -// gdb-check:[...]#loc4[...] -// gdb-command:continue - -fn one() { - println!("one"); -} -fn two() { - println!("two"); -} -fn three() { - println!("three"); -} -fn four() { - println!("four"); -} - -macro_rules! outer { - ($b:block) => { - one(); // #loc1 - inner!(); - $b - }; -} - -macro_rules! inner { - () => { - two(); // #loc2 - }; -} - -fn main() { - let ret = 0; // #break - outer!({ - three(); // #loc3 - four(); // #loc4 - }); - std::process::exit(ret); -} diff --git a/tests/debuginfo/collapse-debuginfo-no-attr.rs b/tests/debuginfo/collapse-debuginfo-no-attr.rs index 4ea1b2cf7a4..6f0d041024f 100644 --- a/tests/debuginfo/collapse-debuginfo-no-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-no-attr.rs @@ -1,10 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] -// Test that line numbers are not replaced with those of the outermost expansion site when the -// `collapse_debuginfo` feature is active and the attribute is not provided. +// Test that line numbers are not replaced with those of the outermost expansion site when +// `#[collapse_debuginfo]` attribute us not used. -//@ compile-flags:-g -Z collapse_macro_debuginfo=no +//@ compile-flags:-g // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/collapse-debuginfo-with-attr-flag.rs b/tests/debuginfo/collapse-debuginfo-with-attr-flag.rs index b585cdf13e0..8da084126ca 100644 --- a/tests/debuginfo/collapse-debuginfo-with-attr-flag.rs +++ b/tests/debuginfo/collapse-debuginfo-with-attr-flag.rs @@ -1,11 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] -// Test that line numbers are not replaced with those of the outermost expansion site when the -// `collapse_debuginfo` is active and `-Zdebug-macros` is provided, despite `#[collapse_debuginfo]` -// being used. +// Test that line numbers are not replaced with those of the outermost expansion site when +// `-C collapse-macro-debuginfo=false` is passed, despite `#[collapse_debuginfo]` being used. -//@ compile-flags:-g -Zdebug-macros +//@ compile-flags:-g -C collapse-macro-debuginfo=false // === GDB TESTS =================================================================================== @@ -37,7 +35,7 @@ fn four() { println!("four"); } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! outer { ($b:block) => { one(); // #loc1 @@ -46,7 +44,7 @@ macro_rules! outer { }; } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! inner { () => { two(); // #loc2 diff --git a/tests/debuginfo/collapse-debuginfo-with-attr.rs b/tests/debuginfo/collapse-debuginfo-with-attr.rs index e7698c5f629..fa664687796 100644 --- a/tests/debuginfo/collapse-debuginfo-with-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-with-attr.rs @@ -1,5 +1,4 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that line numbers are replaced with those of the outermost expansion site when the // `collapse_debuginfo` feature is active and the attribute is provided. @@ -33,7 +32,7 @@ fn four() { println!("four"); } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! outer { ($b:block) => { one(); @@ -42,7 +41,7 @@ macro_rules! outer { }; } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! inner { () => { two(); diff --git a/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs index 2c3ecf3f5af..ef92f87ef46 100644 --- a/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs +++ b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs @@ -1,10 +1,9 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that line numbers are replaced with those of the outermost expansion site when the -// `collapse_debuginfo` feature is active and the command line flag is provided. +// the command line flag is passed. -//@ compile-flags:-g -Z collapse_macro_debuginfo=yes +//@ compile-flags:-g -C collapse_macro_debuginfo=yes // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/coroutine-locals.rs b/tests/debuginfo/coroutine-locals.rs index 54b5cd577c8..c019998040b 100644 --- a/tests/debuginfo/coroutine-locals.rs +++ b/tests/debuginfo/coroutine-locals.rs @@ -46,7 +46,7 @@ // lldb-command:v c // lldb-check:(int) c = 6 -#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] +#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)] #![omit_gdb_pretty_printer_section] use std::ops::Coroutine; @@ -54,7 +54,8 @@ use std::pin::Pin; fn main() { let mut a = 5; - let mut b = || { + let mut b = #[coroutine] + || { let c = 6; // Live across multiple yield points let d = 7; // Live across only one yield point @@ -76,4 +77,6 @@ fn main() { _zzz(); // #break } -fn _zzz() {()} +fn _zzz() { + () +} diff --git a/tests/debuginfo/coroutine-objects.rs b/tests/debuginfo/coroutine-objects.rs index 9e1bd5d62e7..e13f20455a8 100644 --- a/tests/debuginfo/coroutine-objects.rs +++ b/tests/debuginfo/coroutine-objects.rs @@ -63,7 +63,7 @@ // cdb-check: b : Returned [Type: enum2$<coroutine_objects::main::coroutine_env$0>] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *] -#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] +#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)] #![omit_gdb_pretty_printer_section] use std::ops::Coroutine; @@ -71,7 +71,8 @@ use std::pin::Pin; fn main() { let mut a = 5; - let mut b = || { + let mut b = #[coroutine] + || { let mut c = 6; let mut d = 7; diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs index 1e4be432445..2b0c2593676 100644 --- a/tests/debuginfo/function-names.rs +++ b/tests/debuginfo/function-names.rs @@ -83,7 +83,7 @@ #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] -#![feature(adt_const_params, coroutines, coroutine_trait)] +#![feature(adt_const_params, coroutines, coroutine_trait, stmt_expr_attributes)] #![allow(incomplete_features)] use std::ops::Coroutine; @@ -111,7 +111,8 @@ fn main() { closure(); // Coroutine - let mut coroutine = || { + let mut coroutine = #[coroutine] + || { yield; return; }; diff --git a/tests/debuginfo/issue-57822.rs b/tests/debuginfo/issue-57822.rs index 93e1a2558f6..995779a6a9c 100644 --- a/tests/debuginfo/issue-57822.rs +++ b/tests/debuginfo/issue-57822.rs @@ -26,7 +26,7 @@ // lldb-command:v b // lldbg-check:(issue_57822::main::{coroutine_env#3}) b = -#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] +#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)] #![omit_gdb_pretty_printer_section] use std::ops::Coroutine; @@ -38,11 +38,13 @@ fn main() { let g = move || f(); let mut y = 2; - let mut a = move || { + let mut a = #[coroutine] + move || { y += 1; yield; }; - let mut b = move || { + let mut b = #[coroutine] + move || { Pin::new(&mut a).resume(()); yield; }; diff --git a/tests/debuginfo/lexical-scope-with-macro.rs b/tests/debuginfo/lexical-scope-with-macro.rs index 76c923524fb..7ea3dc62e45 100644 --- a/tests/debuginfo/lexical-scope-with-macro.rs +++ b/tests/debuginfo/lexical-scope-with-macro.rs @@ -1,7 +1,7 @@ //@ min-lldb-version: 310 //@ ignore-lldb FIXME #48807 -//@ compile-flags:-g -Zdebug-macros +//@ compile-flags:-g // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs index 71ff9798079..5f8d8287168 100644 --- a/tests/debuginfo/macro-stepping.rs +++ b/tests/debuginfo/macro-stepping.rs @@ -87,6 +87,7 @@ extern crate macro_stepping; // exports new_scope!() // lldb-command:frame select // lldb-check:[...] #inc-loc3 [...] +#[collapse_debuginfo(yes)] macro_rules! foo { () => { let a = 1; opaque(a); @@ -95,6 +96,7 @@ macro_rules! foo { }; } +#[collapse_debuginfo(yes)] macro_rules! foo2 { () => { foo!(); diff --git a/tests/debuginfo/skip_second_statement.rs b/tests/debuginfo/skip_second_statement.rs index e0f3325bcff..ba182de0385 100644 --- a/tests/debuginfo/skip_second_statement.rs +++ b/tests/debuginfo/skip_second_statement.rs @@ -2,9 +2,8 @@ // Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo. // Performed step-over and step-into debug stepping through call statements. -// collapse_debuginfo feature disabled. -//@ compile-flags:-g +//@ compile-flags:-g -C collapse-macro-debuginfo=yes // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/skip_second_statement_collapse.rs b/tests/debuginfo/skip_second_statement_collapse.rs index f1a74b629e4..db90cee8bfb 100644 --- a/tests/debuginfo/skip_second_statement_collapse.rs +++ b/tests/debuginfo/skip_second_statement_collapse.rs @@ -1,9 +1,7 @@ //@ ignore-lldb -#![feature(collapse_debuginfo)] // Test that statement, skipped/added/reordered by macros, is correctly processed in debuginfo // Performed step-over and step-into debug stepping through call statements. -// collapse_debuginfo feature enabled. //@ compile-flags:-g @@ -94,7 +92,7 @@ fn myprintln_impl(text: &str) { println!("{}", text) } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! myprintln { ($($arg:tt)*) => {{ myprintln_impl($($arg)*); diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs index fe6abc54687..e9a53b7aacb 100644 --- a/tests/mir-opt/building/custom/arrays.rs +++ b/tests/mir-opt/building/custom/arrays.rs @@ -1,5 +1,5 @@ // skip-filecheck -#![feature(custom_mir, core_intrinsics, inline_const)] +#![feature(custom_mir, core_intrinsics)] extern crate core; use core::intrinsics::mir::*; diff --git a/tests/mir-opt/building/custom/consts.rs b/tests/mir-opt/building/custom/consts.rs index 42abf5019e5..1a410177fa5 100644 --- a/tests/mir-opt/building/custom/consts.rs +++ b/tests/mir-opt/building/custom/consts.rs @@ -1,5 +1,5 @@ // skip-filecheck -#![feature(custom_mir, core_intrinsics, inline_const)] +#![feature(custom_mir, core_intrinsics)] extern crate core; use core::intrinsics::mir::*; diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs index bc72ed8dfe3..eb97bcc73b7 100644 --- a/tests/mir-opt/building/custom/operators.rs +++ b/tests/mir-opt/building/custom/operators.rs @@ -1,6 +1,6 @@ // skip-filecheck //@ compile-flags: --crate-type=lib -#![feature(custom_mir, core_intrinsics, inline_const)] +#![feature(custom_mir, core_intrinsics)] use std::intrinsics::mir::*; // EMIT_MIR operators.f.built.after.mir diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs index afd8746af5f..2b7271f63ff 100644 --- a/tests/mir-opt/const_prop/invalid_constant.rs +++ b/tests/mir-opt/const_prop/invalid_constant.rs @@ -4,7 +4,6 @@ // Verify that we can pretty print invalid constants. #![feature(adt_const_params)] -#![feature(inline_const)] #![allow(incomplete_features)] #[derive(Copy, Clone)] diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir index 7214b01c601..7e033916fd3 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` 0 coroutine_drop -fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () { +fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12:7}) -> () { let mut _0: (); let mut _2: (); let _3: std::string::String; diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir index 00769a493b5..613ef2909b5 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` 0 coroutine_drop -fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () { +fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12:7}) -> () { let mut _0: (); let mut _2: (); let _3: std::string::String; diff --git a/tests/mir-opt/coroutine_drop_cleanup.rs b/tests/mir-opt/coroutine_drop_cleanup.rs index 69984c737fe..33fdd2dd0d9 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.rs +++ b/tests/mir-opt/coroutine_drop_cleanup.rs @@ -1,5 +1,5 @@ // skip-filecheck -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] // EMIT_MIR_FOR_EACH_PANIC_STRATEGY @@ -8,7 +8,8 @@ // EMIT_MIR coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.mir fn main() { - let gen = || { + let gen = #[coroutine] + || { let _s = String::new(); yield; }; diff --git a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir index 8369a3e60dd..4731aed335d 100644 --- a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir +++ b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` before StateTransform -fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:23:16: 23:18}, _2: ()) -> () +fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:24:5: 24:7}, _2: ()) -> () yields () { let mut _0: (); diff --git a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir index 1773db1abff..14e1782b860 100644 --- a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir +++ b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` before StateTransform -fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:23:16: 23:18}, _2: ()) -> () +fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:24:5: 24:7}, _2: ()) -> () yields () { let mut _0: (); diff --git a/tests/mir-opt/coroutine_storage_dead_unwind.rs b/tests/mir-opt/coroutine_storage_dead_unwind.rs index 253be1ff698..ce9bad483af 100644 --- a/tests/mir-opt/coroutine_storage_dead_unwind.rs +++ b/tests/mir-opt/coroutine_storage_dead_unwind.rs @@ -6,7 +6,7 @@ // Basic block and local names can safely change, but the StorageDead statements // should not go away. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] struct Foo(i32); @@ -20,7 +20,8 @@ fn take<T>(_x: T) {} // EMIT_MIR coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir fn main() { - let _gen = || { + let _gen = #[coroutine] + || { let a = Foo(5); let b = Bar(6); yield; diff --git a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir index 165aa3a05cb..f8b3f68d21e 100644 --- a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir @@ -4,7 +4,7 @@ _0: CoroutineSavedTy { ty: HasDrop, source_info: SourceInfo { - span: $DIR/coroutine_tiny.rs:21:13: 21:15 (#0), + span: $DIR/coroutine_tiny.rs:22:13: 22:15 (#0), scope: scope[0], }, ignore_for_traits: false, @@ -21,7 +21,7 @@ }, } */ -fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}>, _2: u8) -> CoroutineState<(), ()> { +fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}>, _2: u8) -> CoroutineState<(), ()> { debug _x => _10; let mut _0: std::ops::CoroutineState<(), ()>; let _3: HasDrop; @@ -34,18 +34,18 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24 let _10: u8; let mut _11: u32; scope 1 { - debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24})) as variant#3).0: HasDrop); + debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop); } bb0: { - _11 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}))); + _11 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}))); switchInt(move _11) -> [0: bb1, 3: bb5, otherwise: bb6]; } bb1: { _10 = move _2; nop; - (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24})) as variant#3).0: HasDrop) = HasDrop; + (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop) = HasDrop; StorageLive(_4); goto -> bb2; } @@ -58,7 +58,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24 StorageDead(_4); StorageDead(_6); StorageDead(_7); - discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}))) = 3; + discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}))) = 3; return; } diff --git a/tests/mir-opt/coroutine_tiny.rs b/tests/mir-opt/coroutine_tiny.rs index 9728425f232..81e9940541b 100644 --- a/tests/mir-opt/coroutine_tiny.rs +++ b/tests/mir-opt/coroutine_tiny.rs @@ -5,7 +5,7 @@ //@ compile-flags: -C panic=abort //@ no-prefer-dynamic -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] struct HasDrop; @@ -17,7 +17,8 @@ fn callee() {} // EMIT_MIR coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir fn main() { - let _gen = |_x: u8| { + let _gen = #[coroutine] + |_x: u8| { let _d = HasDrop; loop { yield; diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 859082c3111..07031a298bc 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -4,24 +4,24 @@ fn main() -> () { let mut _0: (); let _1: std::ops::CoroutineState<i32, bool>; - let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>; - let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; - let mut _4: {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; + let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>; + let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _4: {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _5: bool; scope 1 { debug _r => _1; } + scope 2 (inlined g) { + } -+ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) { ++ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new) { + debug pointer => _3; -+ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) { ++ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new_unchecked) { + debug pointer => _3; + } + } + scope 5 (inlined g::{closure#0}) { + debug a => _5; -+ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; ++ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _7: u32; + let mut _8: i32; + } @@ -32,22 +32,22 @@ StorageLive(_3); StorageLive(_4); - _4 = g() -> [return: bb1, unwind unreachable]; -+ _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; ++ _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; + StorageLive(_6); + StorageLive(_7); -+ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}); ++ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}); + _7 = discriminant((*_6)); + switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; } bb1: { - _3 = &mut _4; -- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new(move _3) -> [return: bb2, unwind unreachable]; +- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new(move _3) -> [return: bb2, unwind unreachable]; + StorageDead(_4); + _0 = const (); + StorageDead(_1); @@ -56,7 +56,7 @@ bb2: { - StorageDead(_3); -- _1 = <{coroutine@$DIR/inline_coroutine.rs:19:5: 19:8} as Coroutine<bool>>::resume(move _2, const false) -> [return: bb3, unwind unreachable]; +- _1 = <{coroutine@$DIR/inline_coroutine.rs:20:5: 20:8} as Coroutine<bool>>::resume(move _2, const false) -> [return: bb3, unwind unreachable]; + StorageDead(_7); + StorageDead(_6); + StorageDead(_5); diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index 44b06c34972..ab6c62b0baf 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -4,24 +4,24 @@ fn main() -> () { let mut _0: (); let _1: std::ops::CoroutineState<i32, bool>; - let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>; - let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; - let mut _4: {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; + let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>; + let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _4: {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _5: bool; scope 1 { debug _r => _1; } + scope 2 (inlined g) { + } -+ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) { ++ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new) { + debug pointer => _3; -+ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) { ++ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new_unchecked) { + debug pointer => _3; + } + } + scope 5 (inlined g::{closure#0}) { + debug a => _5; -+ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; ++ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}; + let mut _7: u32; + let mut _8: i32; + } @@ -32,22 +32,22 @@ StorageLive(_3); StorageLive(_4); - _4 = g() -> [return: bb1, unwind continue]; -+ _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; ++ _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; + StorageLive(_6); + StorageLive(_7); -+ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}); ++ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}); + _7 = discriminant((*_6)); + switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11]; } bb1: { - _3 = &mut _4; -- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new(move _3) -> [return: bb2, unwind: bb5]; +- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new(move _3) -> [return: bb2, unwind: bb5]; + StorageDead(_4); + _0 = const (); + StorageDead(_1); @@ -56,7 +56,7 @@ - bb2: { - StorageDead(_3); -- _1 = <{coroutine@$DIR/inline_coroutine.rs:19:5: 19:8} as Coroutine<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb5]; +- _1 = <{coroutine@$DIR/inline_coroutine.rs:20:5: 20:8} as Coroutine<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb5]; + bb2 (cleanup): { + drop(_4) -> [return: bb3, unwind terminate(cleanup)]; } diff --git a/tests/mir-opt/inline/inline_coroutine.rs b/tests/mir-opt/inline/inline_coroutine.rs index 180f9d4a6fd..07f8fb20f7e 100644 --- a/tests/mir-opt/inline/inline_coroutine.rs +++ b/tests/mir-opt/inline/inline_coroutine.rs @@ -16,5 +16,6 @@ fn main() { #[inline] pub fn g() -> impl Coroutine<bool> { #[inline] - |a| { yield if a { 7 } else { 13 } } + #[coroutine] + |a| yield if a { 7 } else { 13 } } diff --git a/tests/pretty/stmt_expr_attributes.rs b/tests/pretty/stmt_expr_attributes.rs index 5076adf5aa4..5eb7d2fcae3 100644 --- a/tests/pretty/stmt_expr_attributes.rs +++ b/tests/pretty/stmt_expr_attributes.rs @@ -1,6 +1,5 @@ //@ pp-exact -#![feature(inline_const)] #![feature(inline_const_pat)] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs index 92d6895143c..97ff12877f1 100644 --- a/tests/run-make/compiler-builtins/rmake.rs +++ b/tests/run-make/compiler-builtins/rmake.rs @@ -63,7 +63,10 @@ fn main() { .env("RUSTC", rustc) .env("RUSTFLAGS", "-Copt-level=0 -Cdebug-assertions=yes") .env("CARGO_TARGET_DIR", &target_dir) - .env("RUSTC_BOOTSTRAP", "1"); + .env("RUSTC_BOOTSTRAP", "1") + // Visual Studio 2022 requires that the LIB env var be set so it can + // find the Windows SDK. + .env("LIB", std::env::var("LIB").unwrap_or_default()); set_host_rpath(&mut cmd); let status = cmd.status().unwrap(); diff --git a/tests/run-make/no-input-file/Makefile b/tests/run-make/no-input-file/Makefile deleted file mode 100644 index a754573a524..00000000000 --- a/tests/run-make/no-input-file/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --print crate-name 2>&1 | diff - no-input-file.stderr diff --git a/tests/run-make/no-input-file/rmake.rs b/tests/run-make/no-input-file/rmake.rs new file mode 100644 index 00000000000..26df7e80dfb --- /dev/null +++ b/tests/run-make/no-input-file/rmake.rs @@ -0,0 +1,9 @@ +extern crate run_make_support; + +use run_make_support::{diff, rustc}; + +fn main() { + let output = rustc().print("crate-name").run_fail_assert_exit_code(1); + + diff().expected_file("no-input-file.stderr").actual_text("output", output.stderr).run(); +} diff --git a/tests/run-make/valid-print-requests/Makefile b/tests/run-make/valid-print-requests/Makefile deleted file mode 100644 index 99430e98d1c..00000000000 --- a/tests/run-make/valid-print-requests/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --print uwu 2>&1 | diff - valid-print-requests.stderr diff --git a/tests/run-make/valid-print-requests/valid-print-requests.stderr b/tests/run-make/valid-print-requests/valid-print-requests.stderr deleted file mode 100644 index 22bb102f9c9..00000000000 --- a/tests/run-make/valid-print-requests/valid-print-requests.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: unknown print request `uwu`. Valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` - diff --git a/tests/ui/associated-types/issue-25700.stderr b/tests/ui/associated-types/issue-25700.stderr index fb0e63c207a..8d40e6905e0 100644 --- a/tests/ui/associated-types/issue-25700.stderr +++ b/tests/ui/associated-types/issue-25700.stderr @@ -12,7 +12,10 @@ note: if `S<()>` implemented `Clone`, you could clone the value --> $DIR/issue-25700.rs:1:1 | LL | struct S<T: 'static>(#[allow(dead_code)] Option<&'static T>); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(t); + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/async-await/async-outside-of-await-issue-121096.stderr b/tests/ui/async-await/async-outside-of-await-issue-121096.stderr index b0677a83864..d7caf6b3c0d 100644 --- a/tests/ui/async-await/async-outside-of-await-issue-121096.stderr +++ b/tests/ui/async-await/async-outside-of-await-issue-121096.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/async-outside-of-await-issue-121096.rs:7:7 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | }.await | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 928eb0b821d..a98bb0764c0 100644 --- a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -141,7 +141,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:68:19 | LL | fn foo13() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await(); | ^^^^^ only allowed inside `async` functions and blocks @@ -149,7 +149,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:73:19 | LL | fn foo14() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await()?; | ^^^^^ only allowed inside `async` functions and blocks @@ -157,7 +157,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:78:19 | LL | fn foo15() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await; | ^^^^^ only allowed inside `async` functions and blocks @@ -165,7 +165,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:82:19 | LL | fn foo16() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await?; | ^^^^^ only allowed inside `async` functions and blocks @@ -173,7 +173,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:87:23 | LL | fn foo() -> Result<(), ()> { - | --- this is not `async` + | -------------------------- this is not `async` LL | let _ = bar().await?; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/coroutine-not-future.rs b/tests/ui/async-await/coroutine-not-future.rs index 2993f58378a..45227435507 100644 --- a/tests/ui/async-await/coroutine-not-future.rs +++ b/tests/ui/async-await/coroutine-not-future.rs @@ -1,5 +1,5 @@ //@ edition:2018 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::future::Future; use std::ops::Coroutine; @@ -9,6 +9,7 @@ fn returns_async_block() -> impl Future<Output = ()> { async {} } fn returns_coroutine() -> impl Coroutine<(), Yield = (), Return = ()> { + #[coroutine] || { let _: () = yield (); } @@ -23,9 +24,12 @@ fn main() { takes_future(returns_async_block()); takes_future(async {}); takes_coroutine(returns_coroutine()); - takes_coroutine(|| { - let _: () = yield (); - }); + takes_coroutine( + #[coroutine] + || { + let _: () = yield (); + }, + ); // async futures are not coroutines: takes_coroutine(async_fn()); @@ -38,8 +42,11 @@ fn main() { // coroutines are not futures: takes_future(returns_coroutine()); //~^ ERROR is not a future - takes_future(|ctx| { - //~^ ERROR is not a future - ctx = yield (); - }); + takes_future( + #[coroutine] + |ctx| { + //~^ ERROR is not a future + ctx = yield (); + }, + ); } diff --git a/tests/ui/async-await/coroutine-not-future.stderr b/tests/ui/async-await/coroutine-not-future.stderr index 580217fb4f8..403e547a753 100644 --- a/tests/ui/async-await/coroutine-not-future.stderr +++ b/tests/ui/async-await/coroutine-not-future.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `impl Future<Output = ()>: Coroutine<_>` is not satisfied - --> $DIR/coroutine-not-future.rs:31:21 + --> $DIR/coroutine-not-future.rs:35:21 | LL | takes_coroutine(async_fn()); | --------------- ^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future<Output = ()>` @@ -7,13 +7,13 @@ LL | takes_coroutine(async_fn()); | required by a bound introduced by this call | note: required by a bound in `takes_coroutine` - --> $DIR/coroutine-not-future.rs:18:39 + --> $DIR/coroutine-not-future.rs:19:39 | LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` error[E0277]: the trait bound `impl Future<Output = ()>: Coroutine<_>` is not satisfied - --> $DIR/coroutine-not-future.rs:33:21 + --> $DIR/coroutine-not-future.rs:37:21 | LL | takes_coroutine(returns_async_block()); | --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future<Output = ()>` @@ -21,27 +21,27 @@ LL | takes_coroutine(returns_async_block()); | required by a bound introduced by this call | note: required by a bound in `takes_coroutine` - --> $DIR/coroutine-not-future.rs:18:39 + --> $DIR/coroutine-not-future.rs:19:39 | LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` -error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:35:21: 35:29}: Coroutine<_>` is not satisfied - --> $DIR/coroutine-not-future.rs:35:21 +error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:39:21: 39:29}: Coroutine<_>` is not satisfied + --> $DIR/coroutine-not-future.rs:39:21 | LL | takes_coroutine(async {}); - | --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:35:21: 35:29}` + | --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:39:21: 39:29}` | | | required by a bound introduced by this call | note: required by a bound in `takes_coroutine` - --> $DIR/coroutine-not-future.rs:18:39 + --> $DIR/coroutine-not-future.rs:19:39 | LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` error[E0277]: `impl Coroutine<Yield = (), Return = ()>` is not a future - --> $DIR/coroutine-not-future.rs:39:18 + --> $DIR/coroutine-not-future.rs:43:18 | LL | takes_future(returns_coroutine()); | ------------ ^^^^^^^^^^^^^^^^^^^ `impl Coroutine<Yield = (), Return = ()>` is not a future @@ -50,26 +50,26 @@ LL | takes_future(returns_coroutine()); | = help: the trait `Future` is not implemented for `impl Coroutine<Yield = (), Return = ()>` note: required by a bound in `takes_future` - --> $DIR/coroutine-not-future.rs:17:26 + --> $DIR/coroutine-not-future.rs:18:26 | LL | fn takes_future(_f: impl Future<Output = ()>) {} | ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future` -error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` is not a future - --> $DIR/coroutine-not-future.rs:41:18 +error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future + --> $DIR/coroutine-not-future.rs:47:9 | -LL | takes_future(|ctx| { - | _____------------_^ - | | | - | | required by a bound introduced by this call +LL | takes_future( + | ------------ required by a bound introduced by this call +LL | #[coroutine] +LL | / |ctx| { LL | | -LL | | ctx = yield (); -LL | | }); - | |_____^ `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` is not a future +LL | | ctx = yield (); +LL | | }, + | |_________^ `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future | - = help: the trait `Future` is not implemented for `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` + = help: the trait `Future` is not implemented for `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` note: required by a bound in `takes_future` - --> $DIR/coroutine-not-future.rs:17:26 + --> $DIR/coroutine-not-future.rs:18:26 | LL | fn takes_future(_f: impl Future<Output = ()>) {} | ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future` diff --git a/tests/ui/async-await/issues/issue-51751.stderr b/tests/ui/async-await/issues/issue-51751.stderr index ba256b19948..ab12e0427b4 100644 --- a/tests/ui/async-await/issues/issue-51751.stderr +++ b/tests/ui/async-await/issues/issue-51751.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51751.rs:9:27 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | let result = inc(10000); LL | let finished = result.await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-62009-1.stderr b/tests/ui/async-await/issues/issue-62009-1.stderr index 02933f4f2f2..f8a4b5d9af8 100644 --- a/tests/ui/async-await/issues/issue-62009-1.stderr +++ b/tests/ui/async-await/issues/issue-62009-1.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:6:23 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | async { let (); }.await; | ^^^^^ only allowed inside `async` functions and blocks @@ -10,7 +10,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:10:7 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | }.await; | ^^^^^ only allowed inside `async` functions and blocks @@ -19,7 +19,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:12:16 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | (|_| 2333).await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-62009-2.stderr b/tests/ui/async-await/issues/issue-62009-2.stderr index 80a831cc547..0004f99f901 100644 --- a/tests/ui/async-await/issues/issue-62009-2.stderr +++ b/tests/ui/async-await/issues/issue-62009-2.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-2.rs:8:23 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | (async || 2333)().await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs b/tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs index f937311a5a0..6b7dfc1235e 100644 --- a/tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs +++ b/tests/ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs @@ -6,15 +6,13 @@ //@ error-pattern:coroutine resumed after completion //@ edition:2018 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] -use std::{ - ops::Coroutine, - pin::Pin, -}; +use std::{ops::Coroutine, pin::Pin}; fn main() { - let mut g = || { + let mut g = #[coroutine] + || { yield; }; Pin::new(&mut g).resume(()); // Yields once. diff --git a/tests/ui/async-await/issues/non-async-enclosing-span.stderr b/tests/ui/async-await/issues/non-async-enclosing-span.stderr index 91a9e5aa6ca..9c26de1c504 100644 --- a/tests/ui/async-await/issues/non-async-enclosing-span.stderr +++ b/tests/ui/async-await/issues/non-async-enclosing-span.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/non-async-enclosing-span.rs:9:28 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | let x = move || {}; LL | let y = do_the_thing().await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/non-trivial-drop.rs b/tests/ui/async-await/non-trivial-drop.rs index 71b88124219..95de3c5b005 100644 --- a/tests/ui/async-await/non-trivial-drop.rs +++ b/tests/ui/async-await/non-trivial-drop.rs @@ -8,7 +8,7 @@ fn main() { } fn foo() { - || { + #[coroutine] || { yield drop(Config { nickname: NonCopy, b: NonCopy2, diff --git a/tests/ui/attributes/collapse-debuginfo-invalid.rs b/tests/ui/attributes/collapse-debuginfo-invalid.rs index 42d8982c118..d6b3554a5a8 100644 --- a/tests/ui/attributes/collapse-debuginfo-invalid.rs +++ b/tests/ui/attributes/collapse-debuginfo-invalid.rs @@ -1,84 +1,83 @@ -#![feature(collapse_debuginfo)] #![feature(stmt_expr_attributes)] #![feature(type_alias_impl_trait)] #![no_std] // Test that the `#[collapse_debuginfo]` attribute can only be used on macro definitions. -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions extern crate std; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions use std::collections::HashMap; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions static FOO: u32 = 3; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions const BAR: u32 = 3; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions fn foo() { - let _ = #[collapse_debuginfo] || { }; + let _ = #[collapse_debuginfo(yes)] || { }; //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions let _ = 3; - let _ = #[collapse_debuginfo] 3; + let _ = #[collapse_debuginfo(yes)] 3; //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions match (3, 4) { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions _ => (), } } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions mod bar { } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions type Map = HashMap<u32, u32>; -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions enum Foo { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions Variant, } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions struct Bar { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions field: u32, } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions union Qux { a: u32, b: u16 } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions trait Foobar { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions type Bar; } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions type AFoobar = impl Foobar; @@ -90,19 +89,19 @@ fn constraining() -> AFoobar { Bar { field: 3 } } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions impl Bar { - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions const FOO: u32 = 3; - #[collapse_debuginfo] + #[collapse_debuginfo(yes)] //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions fn bar(&self) {} } -#[collapse_debuginfo] +#[collapse_debuginfo(yes)] macro_rules! finally { ($e:expr) => { $e } } diff --git a/tests/ui/attributes/collapse-debuginfo-invalid.stderr b/tests/ui/attributes/collapse-debuginfo-invalid.stderr index 01c47609108..7cbbd1d647e 100644 --- a/tests/ui/attributes/collapse-debuginfo-invalid.stderr +++ b/tests/ui/attributes/collapse-debuginfo-invalid.stderr @@ -1,152 +1,152 @@ error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:8:1 + --> $DIR/collapse-debuginfo-invalid.rs:7:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | extern crate std; | ----------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:12:1 + --> $DIR/collapse-debuginfo-invalid.rs:11:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | use std::collections::HashMap; | ------------------------------ not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:16:1 + --> $DIR/collapse-debuginfo-invalid.rs:15:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | static FOO: u32 = 3; | -------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:20:1 + --> $DIR/collapse-debuginfo-invalid.rs:19:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | const BAR: u32 = 3; | ------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:24:1 + --> $DIR/collapse-debuginfo-invalid.rs:23:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / fn foo() { -LL | | let _ = #[collapse_debuginfo] || { }; +LL | | let _ = #[collapse_debuginfo(yes)] || { }; LL | | -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] ... | LL | | } LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:27:13 + --> $DIR/collapse-debuginfo-invalid.rs:26:13 | -LL | let _ = #[collapse_debuginfo] || { }; - | ^^^^^^^^^^^^^^^^^^^^^ ------ not a macro definition +LL | let _ = #[collapse_debuginfo(yes)] || { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:29:5 + --> $DIR/collapse-debuginfo-invalid.rs:28:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | let _ = 3; | ---------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:32:13 + --> $DIR/collapse-debuginfo-invalid.rs:31:13 | -LL | let _ = #[collapse_debuginfo] 3; - | ^^^^^^^^^^^^^^^^^^^^^ - not a macro definition +LL | let _ = #[collapse_debuginfo(yes)] 3; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:35:9 + --> $DIR/collapse-debuginfo-invalid.rs:34:9 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | _ => (), | ------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:41:1 + --> $DIR/collapse-debuginfo-invalid.rs:40:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / mod bar { LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:46:1 + --> $DIR/collapse-debuginfo-invalid.rs:45:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | type Map = HashMap<u32, u32>; | ----------------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:50:1 + --> $DIR/collapse-debuginfo-invalid.rs:49:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / enum Foo { -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] LL | | LL | | Variant, LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:53:5 + --> $DIR/collapse-debuginfo-invalid.rs:52:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | Variant, | ------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:58:1 + --> $DIR/collapse-debuginfo-invalid.rs:57:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / struct Bar { -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] LL | | LL | | field: u32, LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:61:5 + --> $DIR/collapse-debuginfo-invalid.rs:60:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | field: u32, | ---------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:66:1 + --> $DIR/collapse-debuginfo-invalid.rs:65:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / union Qux { LL | | a: u32, @@ -155,35 +155,35 @@ LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:73:1 + --> $DIR/collapse-debuginfo-invalid.rs:72:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / trait Foobar { -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] LL | | LL | | type Bar; LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:81:1 + --> $DIR/collapse-debuginfo-invalid.rs:80:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | type AFoobar = impl Foobar; | --------------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:93:1 + --> $DIR/collapse-debuginfo-invalid.rs:92:1 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / impl Bar { -LL | | #[collapse_debuginfo] +LL | | #[collapse_debuginfo(yes)] LL | | LL | | const FOO: u32 = 3; ... | @@ -192,28 +192,28 @@ LL | | } | |_- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:76:5 + --> $DIR/collapse-debuginfo-invalid.rs:75:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | type Bar; | --------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:96:5 + --> $DIR/collapse-debuginfo-invalid.rs:95:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | const FOO: u32 = 3; | ------------------- not a macro definition error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:100:5 + --> $DIR/collapse-debuginfo-invalid.rs:99:5 | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn bar(&self) {} | ---------------- not a macro definition diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs new file mode 100644 index 00000000000..7f95fa7ebbe --- /dev/null +++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs @@ -0,0 +1,8 @@ +//@ aux-crate: sigpipe_utils=sigpipe-utils.rs + +#![feature(unix_sigpipe)] + +#[unix_sigpipe = "inherit"] +fn main() { + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +} diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs new file mode 100644 index 00000000000..d96e8b8ef84 --- /dev/null +++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs @@ -0,0 +1,8 @@ +//@ aux-crate: sigpipe_utils=sigpipe-utils.rs + +#![feature(unix_sigpipe)] + +#[unix_sigpipe = "inherit"] +fn main() { + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore); +} diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs index db3407a7d55..694fa460e9b 100644 --- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs +++ b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs @@ -1,14 +1,29 @@ +//@ ignore-cross-compile because aux-bin does not yet support it +//@ only-unix because SIGPIPE is a unix thing +//@ aux-bin: assert-inherit-sig_dfl.rs +//@ aux-bin: assert-inherit-sig_ign.rs //@ run-pass -//@ aux-build:sigpipe-utils.rs -#![feature(unix_sigpipe)] +#![feature(rustc_private, unix_sigpipe)] -#[unix_sigpipe = "inherit"] +extern crate libc; + +// By default the Rust runtime resets SIGPIPE to SIG_DFL before exec:ing child +// processes so opt-out of that with `#[unix_sigpipe = "sig_dfl"]`. See +// https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L359-L384 +#[unix_sigpipe = "sig_dfl"] fn main() { - extern crate sigpipe_utils; + // First expect SIG_DFL in a child process with #[unix_sigpipe = "inherit"]. + assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_dfl"); + + // With SIG_IGN we expect #[unix_sigpipe = "inherit"] to also get SIG_IGN. + unsafe { + libc::signal(libc::SIGPIPE, libc::SIG_IGN); + } + assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_ign"); +} - // #[unix_sigpipe = "inherit"] is active, so SIGPIPE shall NOT be ignored, - // instead the default handler shall be installed. (We assume that the - // process that runs these tests have the default handler.) - sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +fn assert_inherit_sigpipe_disposition(aux_bin: &str) { + let mut cmd = std::process::Command::new(aux_bin); + assert!(cmd.status().unwrap().success()); } diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr index dcf1c02bcee..4c1de72798c 100644 --- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr +++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr @@ -23,6 +23,13 @@ LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) } | | value moved here | move occurs because `x` has type `T`, which does not implement the `Copy` trait | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/typeck-auto-trait-no-supertraits-2.rs:8:9 + | +LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) } + | ^ - you could clone this value + | | + | consider constraining this type parameter with `Clone` help: consider further restricting this bound | LL | fn copy<T: Magic + Copy>(x: T) -> (T, T) { (x, x) } diff --git a/tests/ui/binop/binop-consume-args.stderr b/tests/ui/binop/binop-consume-args.stderr index 6fbbb55437e..1b59216b3c7 100644 --- a/tests/ui/binop/binop-consume-args.stderr +++ b/tests/ui/binop/binop-consume-args.stderr @@ -8,6 +8,13 @@ LL | lhs + rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:5:8 + | +LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs + rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -26,6 +33,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:5:30 + | +LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs + rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn add<A: Add<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -41,6 +55,13 @@ LL | lhs - rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:11:8 + | +LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs - rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -59,6 +80,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:11:30 + | +LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs - rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn sub<A: Sub<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -74,6 +102,13 @@ LL | lhs * rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:17:8 + | +LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs * rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -92,6 +127,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:17:30 + | +LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs * rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn mul<A: Mul<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -107,6 +149,13 @@ LL | lhs / rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:23:8 + | +LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs / rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -125,6 +174,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:23:30 + | +LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs / rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn div<A: Div<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -140,6 +196,13 @@ LL | lhs % rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:29:8 + | +LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs % rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -158,6 +221,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:29:30 + | +LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs % rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn rem<A: Rem<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -173,6 +243,13 @@ LL | lhs & rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:35:11 + | +LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs & rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -191,6 +268,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:35:36 + | +LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs & rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn bitand<A: BitAnd<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -206,6 +290,13 @@ LL | lhs | rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:41:10 + | +LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs | rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -224,6 +315,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:41:34 + | +LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs | rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn bitor<A: BitOr<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -239,6 +337,13 @@ LL | lhs ^ rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:47:11 + | +LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs ^ rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -257,6 +362,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:47:36 + | +LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs ^ rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn bitxor<A: BitXor<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -272,6 +384,13 @@ LL | lhs << rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:53:8 + | +LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs << rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -290,6 +409,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:53:30 + | +LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs << rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn shl<A: Shl<B, Output=()>, B: Copy>(lhs: A, rhs: B) { @@ -305,6 +431,13 @@ LL | lhs >> rhs; LL | drop(lhs); | ^^^ value used here after move | +help: if `A` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:59:8 + | +LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs >> rhs; + | --- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL help: consider further restricting this bound @@ -323,6 +456,13 @@ LL | drop(lhs); LL | drop(rhs); | ^^^ value used here after move | +help: if `B` implemented `Clone`, you could clone the value + --> $DIR/binop-consume-args.rs:59:30 + | +LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) { + | ^ consider constraining this type parameter with `Clone` +LL | lhs >> rhs; + | --- you could clone this value help: consider restricting type parameter `B` | LL | fn shr<A: Shr<B, Output=()>, B: Copy>(lhs: A, rhs: B) { diff --git a/tests/ui/binop/binop-move-semantics.stderr b/tests/ui/binop/binop-move-semantics.stderr index 1dd8c9a87d4..83c27590e90 100644 --- a/tests/ui/binop/binop-move-semantics.stderr +++ b/tests/ui/binop/binop-move-semantics.stderr @@ -11,6 +11,13 @@ LL | | x; | |_____value used here after move | `x` moved due to usage in operator | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:5:16 + | +LL | fn double_move<T: Add<Output=()>>(x: T) { + | ^ consider constraining this type parameter with `Clone` +LL | x + | - you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: consider further restricting this bound @@ -51,6 +58,14 @@ LL | x ... LL | use_mut(n); use_imm(m); | - borrow later used here + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:17:18 + | +LL | fn move_borrowed<T: Add<Output=()>>(x: T, mut y: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let m = &x; + | -- you could clone this value error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/binop-move-semantics.rs:23:5 @@ -65,6 +80,15 @@ LL | y; | ^ move out of `y` occurs here LL | use_mut(n); use_imm(m); | - borrow later used here + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:17:18 + | +LL | fn move_borrowed<T: Add<Output=()>>(x: T, mut y: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let m = &x; +LL | let n = &mut y; + | ------ you could clone this value error[E0507]: cannot move out of `*m` which is behind a mutable reference --> $DIR/binop-move-semantics.rs:30:5 @@ -80,12 +104,29 @@ LL | | *n; | note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:26:24 + | +LL | fn illegal_dereference<T: Add<Output=()>>(mut x: T, y: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | *m + | -- you could clone this value error[E0507]: cannot move out of `*n` which is behind a shared reference --> $DIR/binop-move-semantics.rs:32:5 | LL | *n; | ^^ move occurs because `*n` has type `T`, which does not implement the `Copy` trait + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/binop-move-semantics.rs:26:24 + | +LL | fn illegal_dereference<T: Add<Output=()>>(mut x: T, y: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | *n; + | -- you could clone this value error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable --> $DIR/binop-move-semantics.rs:54:5 diff --git a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr index dd22d7e2e2e..98ffa7f6ffa 100644 --- a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr +++ b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr @@ -2,56 +2,86 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:14:13 | LL | x => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | mut x => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | ref mut x => { + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:20:13 | LL | E::Foo(x) => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | E::Foo(mut x) => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | E::Foo(ref mut x) => { + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:26:13 | LL | S { bar: x } => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | S { bar: mut x } => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | S { bar: ref mut x } => { + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:32:13 | LL | (x,) => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | (mut x,) => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | (ref mut x,) => { + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:38:13 | LL | [x,_,_] => { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | [mut x,_,_] => { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | [ref mut x,_,_] => { + | ~~~~~~~~~ error: aborting due to 5 previous errors diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr index 01647011207..9915acfe065 100644 --- a/tests/ui/borrowck/borrowck-move-by-capture.stderr +++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr @@ -11,6 +11,12 @@ LL | let _h = to_fn_once(move || -> isize { *bar }); | | variable moved due to use in closure | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait | `bar` is moved here + | +help: clone the value before moving it into the closure + | +LL ~ let value = bar.clone(); +LL ~ let _h = to_fn_once(move || -> isize { value }); + | error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr index 86bddacbdc7..b4b60d40d91 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr @@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/borrowck-move-out-of-static-item.rs:3:1 | LL | struct Foo { - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | test(BAR); + | --- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr index 4d9477f8581..cc6c3bdeb10 100644 --- a/tests/ui/borrowck/borrowck-move-subcomponent.stderr +++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr @@ -14,7 +14,10 @@ note: if `S` implemented `Clone`, you could clone the value --> $DIR/borrowck-move-subcomponent.rs:6:1 | LL | struct S { - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let pb = &a; + | -- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-overloaded-call.stderr b/tests/ui/borrowck/borrowck-overloaded-call.stderr index 1602058c183..c3b7b0b6080 100644 --- a/tests/ui/borrowck/borrowck-overloaded-call.stderr +++ b/tests/ui/borrowck/borrowck-overloaded-call.stderr @@ -34,7 +34,10 @@ note: if `SFnOnce` implemented `Clone`, you could clone the value --> $DIR/borrowck-overloaded-call.rs:41:1 | LL | struct SFnOnce { - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | s(" world".to_string()); + | - you could clone this value error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr index f0eaf4bac7d..19f040556f8 100644 --- a/tests/ui/borrowck/clone-on-ref.stderr +++ b/tests/ui/borrowck/clone-on-ref.stderr @@ -32,6 +32,13 @@ LL | LL | println!("{b}"); | --- borrow later used here | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/clone-on-ref.rs:11:8 + | +LL | fn bar<T: std::fmt::Display>(x: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let a = &x; + | -- you could clone this value help: consider further restricting this bound | LL | fn bar<T: std::fmt::Display + Clone>(x: T) { @@ -56,7 +63,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/clone-on-ref.rs:19:1 | LL | struct A; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +LL | fn qux(x: A) { +LL | let a = &x; + | -- you could clone this value help: consider annotating `A` with `#[derive(Clone)]` | LL + #[derive(Clone)] diff --git a/tests/ui/borrowck/issue-101119.stderr b/tests/ui/borrowck/issue-101119.stderr index b4775496f4f..a894fa63ace 100644 --- a/tests/ui/borrowck/issue-101119.stderr +++ b/tests/ui/borrowck/issue-101119.stderr @@ -22,7 +22,10 @@ note: if `State` implemented `Clone`, you could clone the value --> $DIR/issue-101119.rs:1:1 | LL | struct State; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | fill_segment(state); + | ----- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr index 94421c35c65..603055beadc 100644 --- a/tests/ui/borrowck/issue-103624.stderr +++ b/tests/ui/borrowck/issue-103624.stderr @@ -13,8 +13,11 @@ LL | self.b; note: if `StructB` implemented `Clone`, you could clone the value --> $DIR/issue-103624.rs:23:1 | +LL | self.b; + | ------ you could clone this value +... LL | struct StructB {} - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type error[E0521]: borrowed data escapes outside of method --> $DIR/issue-103624.rs:14:9 diff --git a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr index 701f00d079d..dde17d1f652 100644 --- a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr +++ b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr @@ -15,7 +15,10 @@ note: if `Example<E, NoLifetime>` implemented `Clone`, you could clone the value --> $DIR/issue-119915-bad-clone-suggestion.rs:3:1 | LL | struct Example<E, FakeParam>(PhantomData<(fn(E), fn(FakeParam))>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | unsafe { self.change() } + | ---- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-17718-static-move.stderr b/tests/ui/borrowck/issue-17718-static-move.stderr index e2c3a9d5a26..057ac6d7e3d 100644 --- a/tests/ui/borrowck/issue-17718-static-move.stderr +++ b/tests/ui/borrowck/issue-17718-static-move.stderr @@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/issue-17718-static-move.rs:1:1 | LL | struct Foo; - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _a = FOO; + | --- you could clone this value help: consider borrowing here | LL | let _a = &FOO; diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index 1da6f0bef02..20a4bd4e423 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -23,7 +23,10 @@ note: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-20801.rs:3:1 | LL | struct T(u8); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = unsafe { *mut_ref() }; + | ---------- you could clone this value help: consider removing the dereference here | LL - let a = unsafe { *mut_ref() }; @@ -40,7 +43,10 @@ note: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-20801.rs:3:1 | LL | struct T(u8); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let b = unsafe { *imm_ref() }; + | ---------- you could clone this value help: consider removing the dereference here | LL - let b = unsafe { *imm_ref() }; @@ -57,7 +63,10 @@ note: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-20801.rs:3:1 | LL | struct T(u8); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let c = unsafe { *mut_ptr() }; + | ---------- you could clone this value help: consider removing the dereference here | LL - let c = unsafe { *mut_ptr() }; @@ -74,7 +83,10 @@ note: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-20801.rs:3:1 | LL | struct T(u8); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let d = unsafe { *const_ptr() }; + | ------------ you could clone this value help: consider removing the dereference here | LL - let d = unsafe { *const_ptr() }; diff --git a/tests/ui/borrowck/move-error-in-promoted-2.stderr b/tests/ui/borrowck/move-error-in-promoted-2.stderr index 43f4e820857..1e9b1d5209c 100644 --- a/tests/ui/borrowck/move-error-in-promoted-2.stderr +++ b/tests/ui/borrowck/move-error-in-promoted-2.stderr @@ -11,7 +11,10 @@ note: if `S` implemented `Clone`, you could clone the value --> $DIR/move-error-in-promoted-2.rs:3:1 | LL | struct S; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | &([S][0],); + | ------ you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/move-error-snippets.stderr b/tests/ui/borrowck/move-error-snippets.stderr index 40b64398aef..97d14051518 100644 --- a/tests/ui/borrowck/move-error-snippets.stderr +++ b/tests/ui/borrowck/move-error-snippets.stderr @@ -13,7 +13,12 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-error-snippets.rs:9:1 | LL | struct A; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type + | + ::: $DIR/move-error-snippets-ext.rs:5:17 + | +LL | let a = $c; + | -- you could clone this value = note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider borrowing here | diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr index a4e70b50646..009e85a8031 100644 --- a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr +++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr @@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/move-in-static-initializer-issue-38520.rs:5:1 | LL | struct Foo(usize); - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | static Y: usize = get(*&X); + | --- you could clone this value error[E0507]: cannot move out of a shared reference --> $DIR/move-in-static-initializer-issue-38520.rs:13:22 @@ -20,7 +23,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/move-in-static-initializer-issue-38520.rs:5:1 | LL | struct Foo(usize); - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | const Z: usize = get(*&X); + | --- you could clone this value error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/suggest-ref-mut-issue-118596.rs b/tests/ui/borrowck/suggest-ref-mut-issue-118596.rs new file mode 100644 index 00000000000..fb894623e78 --- /dev/null +++ b/tests/ui/borrowck/suggest-ref-mut-issue-118596.rs @@ -0,0 +1,11 @@ +fn main() { + let y = Some(0); + if let Some(x) = y { + x = 2; //~ ERROR cannot assign twice to immutable variable `x` + } + + let mut arr = [1, 2, 3]; + let [x, ref xs_hold @ ..] = arr; + x = 0; //~ ERROR cannot assign twice to immutable variable `x` + eprintln!("{:?}", arr); +} diff --git a/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr b/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr new file mode 100644 index 00000000000..fd2a775a099 --- /dev/null +++ b/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr @@ -0,0 +1,37 @@ +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/suggest-ref-mut-issue-118596.rs:4:9 + | +LL | if let Some(x) = y { + | - first assignment to `x` +LL | x = 2; + | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | if let Some(mut x) = y { + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | if let Some(ref mut x) = y { + | ~~~~~~~~~ + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/suggest-ref-mut-issue-118596.rs:9:5 + | +LL | let [x, ref xs_hold @ ..] = arr; + | - first assignment to `x` +LL | x = 0; + | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let [mut x, ref xs_hold @ ..] = arr; + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let [ref mut x, ref xs_hold @ ..] = arr; + | ~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/box/leak-alloc.stderr b/tests/ui/box/leak-alloc.stderr index 53ff5f0107d..bdaa9449f91 100644 --- a/tests/ui/box/leak-alloc.stderr +++ b/tests/ui/box/leak-alloc.stderr @@ -16,7 +16,10 @@ note: if `Alloc` implemented `Clone`, you could clone the value --> $DIR/leak-alloc.rs:8:1 | LL | struct Alloc {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let boxed = Box::new_in(10, alloc.by_ref()); + | ----- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.rs b/tests/ui/codemap_tests/huge_multispan_highlight.rs index c2bd393589e..28c595cca64 100644 --- a/tests/ui/codemap_tests/huge_multispan_highlight.rs +++ b/tests/ui/codemap_tests/huge_multispan_highlight.rs @@ -1,7 +1,5 @@ //@ compile-flags: --error-format=human --color=always //@ ignore-windows -// Temporary until next release: -//@ ignore-stage2 fn main() { let _ = match true { true => ( diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.svg b/tests/ui/codemap_tests/huge_multispan_highlight.svg index f26a2bd7275..f1e96583ff0 100644 --- a/tests/ui/codemap_tests/huge_multispan_highlight.svg +++ b/tests/ui/codemap_tests/huge_multispan_highlight.svg @@ -1,4 +1,4 @@ -<svg width="750px" height="848px" xmlns="http://www.w3.org/2000/svg"> +<svg width="740px" height="848px" xmlns="http://www.w3.org/2000/svg"> <style> .fg { fill: #AAAAAA } .bg { background: #000000 } @@ -21,7 +21,7 @@ <text xml:space="preserve" class="container fg"> <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: `match` arms have incompatible types</tspan> </tspan> - <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/huge_multispan_highlight.rs:98:18</tspan> + <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/huge_multispan_highlight.rs:96:18</tspan> </tspan> <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> @@ -59,7 +59,7 @@ </tspan> <tspan x="10px" y="370px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: `match` arms have incompatible types</tspan> </tspan> - <tspan x="10px" y="388px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/huge_multispan_highlight.rs:215:18</tspan> + <tspan x="10px" y="388px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/huge_multispan_highlight.rs:213:18</tspan> </tspan> <tspan x="10px" y="406px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> diff --git a/tests/ui/coherence/coherence-with-coroutine.rs b/tests/ui/coherence/coherence-with-coroutine.rs index 1ba98344672..6b0617e950b 100644 --- a/tests/ui/coherence/coherence-with-coroutine.rs +++ b/tests/ui/coherence/coherence-with-coroutine.rs @@ -8,6 +8,7 @@ type OpaqueCoroutine = impl Sized; fn defining_use() -> OpaqueCoroutine { + #[coroutine] || { for i in 0..10 { yield i; diff --git a/tests/ui/coherence/coherence-with-coroutine.stock.stderr b/tests/ui/coherence/coherence-with-coroutine.stock.stderr index 9cf20ea4936..5f58b3088f1 100644 --- a/tests/ui/coherence/coherence-with-coroutine.stock.stderr +++ b/tests/ui/coherence/coherence-with-coroutine.stock.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueCoroutine>` - --> $DIR/coherence-with-coroutine.rs:21:1 + --> $DIR/coherence-with-coroutine.rs:22:1 | LL | impl Trait for Wrapper<OpaqueCoroutine> {} | --------------------------------------- first implementation here diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs index 7332a8f03c0..f1305202ad4 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs @@ -1,4 +1,4 @@ -#![feature(inline_const, generic_const_exprs)] +#![feature(generic_const_exprs)] //~^ WARN the feature `generic_const_exprs` is incomplete fn foo<T>() { diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr index a85e0cbcf7e..03b0004bf0b 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr @@ -1,8 +1,8 @@ warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-block-is-poly.rs:1:26 + --> $DIR/const-block-is-poly.rs:1:12 | -LL | #![feature(inline_const, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs index 4333ec9f552..f9cf8210d65 100644 --- a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs +++ b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_ty_with_infer_2.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(inline_const, generic_const_exprs)] +#![feature(generic_const_exprs)] #![allow(incomplete_features)] use std::marker::PhantomData; diff --git a/tests/ui/const-generics/generic_const_exprs/inline-const-in-const-generic-defaults.rs b/tests/ui/const-generics/generic_const_exprs/inline-const-in-const-generic-defaults.rs index 3bc02f4c6bb..073e0fe0a7f 100644 --- a/tests/ui/const-generics/generic_const_exprs/inline-const-in-const-generic-defaults.rs +++ b/tests/ui/const-generics/generic_const_exprs/inline-const-in-const-generic-defaults.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(generic_const_exprs)] -#![feature(inline_const)] #![allow(incomplete_features)] pub struct ConstDefaultUnstable<const N: usize = { const { 3 } }>; diff --git a/tests/ui/const_prop/dont-propagate-generic-instance-2.rs b/tests/ui/const_prop/dont-propagate-generic-instance-2.rs index 768c9b3171a..08064bc6589 100644 --- a/tests/ui/const_prop/dont-propagate-generic-instance-2.rs +++ b/tests/ui/const_prop/dont-propagate-generic-instance-2.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(inline_const)] - // Makes sure we don't propagate generic instances of `Self: ?Sized` blanket impls. // This is relevant when we have an overlapping impl and builtin dyn instance. // See <https://github.com/rust-lang/rust/pull/114941> for more context. diff --git a/tests/ui/consts/closure-structural-match-issue-90013.rs b/tests/ui/consts/closure-structural-match-issue-90013.rs index 7a5d9b69ee4..454341a7784 100644 --- a/tests/ui/consts/closure-structural-match-issue-90013.rs +++ b/tests/ui/consts/closure-structural-match-issue-90013.rs @@ -1,6 +1,5 @@ // Regression test for issue 90013. //@ check-pass -#![feature(inline_const)] fn main() { const { || {} }; diff --git a/tests/ui/consts/const-block-const-bound.rs b/tests/ui/consts/const-block-const-bound.rs index b0d5e19ad55..933eb6cfc0a 100644 --- a/tests/ui/consts/const-block-const-bound.rs +++ b/tests/ui/consts/const-block-const-bound.rs @@ -1,7 +1,7 @@ //@ known-bug: #103507 #![allow(unused)] -#![feature(const_trait_impl, inline_const, negative_impls)] +#![feature(const_trait_impl, negative_impls)] use std::marker::Destruct; diff --git a/tests/ui/consts/const-blocks/fn-call-in-const.rs b/tests/ui/consts/const-blocks/fn-call-in-const.rs index 9bf267b7de9..a3e24ddae7d 100644 --- a/tests/ui/consts/const-blocks/fn-call-in-const.rs +++ b/tests/ui/consts/const-blocks/fn-call-in-const.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(inline_const)] #![allow(unused)] // Some type that is not copyable. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs index 6c4fca35626..2517560c2c3 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(inline_const)] use std::intrinsics; diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs index 146a87862e8..c53bb36f4a2 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] #![feature(const_heap)] -#![feature(inline_const)] use std::intrinsics; diff --git a/tests/ui/consts/issue-102117.rs b/tests/ui/consts/issue-102117.rs index 3ed90aed235..6cb9832bcd8 100644 --- a/tests/ui/consts/issue-102117.rs +++ b/tests/ui/consts/issue-102117.rs @@ -1,4 +1,4 @@ -#![feature(inline_const, const_type_id)] +#![feature(const_type_id)] use std::alloc::Layout; use std::any::TypeId; diff --git a/tests/ui/coroutine/addassign-yield.rs b/tests/ui/coroutine/addassign-yield.rs index 8718e73512f..8329b53d715 100644 --- a/tests/ui/coroutine/addassign-yield.rs +++ b/tests/ui/coroutine/addassign-yield.rs @@ -5,21 +5,21 @@ // is being used), we were failing to account for all types that might // possibly be live across a yield point. -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn foo() { - let _x = static || { + let _x = #[coroutine] static || { let mut s = String::new(); s += { yield; "" }; }; - let _y = static || { + let _y = #[coroutine] static || { let x = &mut 0; *{ yield; x } += match String::new() { _ => 0 }; }; // Please don't ever actually write something like this - let _z = static || { + let _z = #[coroutine] static || { let x = &mut 0; *{ let inner = &mut 1; diff --git a/tests/ui/coroutine/auto-trait-regions.rs b/tests/ui/coroutine/auto-trait-regions.rs index 5fce70e8e54..4c239f9ee76 100644 --- a/tests/ui/coroutine/auto-trait-regions.rs +++ b/tests/ui/coroutine/auto-trait-regions.rs @@ -1,4 +1,4 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(auto_traits)] #![feature(negative_impls)] @@ -23,7 +23,7 @@ fn assert_foo<T: Foo>(f: T) {} fn main() { // Make sure 'static is erased for coroutine interiors so we can't match it in trait selection let x: &'static _ = &OnlyFooIfStaticRef(No); - let gen = move || { + let gen = #[coroutine] move || { let x = x; yield; assert_foo(x); @@ -33,7 +33,7 @@ fn main() { // Allow impls which matches any lifetime let x = &OnlyFooIfRef(No); - let gen = move || { + let gen = #[coroutine] move || { let x = x; yield; assert_foo(x); @@ -41,7 +41,7 @@ fn main() { assert_foo(gen); // ok // Disallow impls which relates lifetimes in the coroutine interior - let gen = move || { + let gen = #[coroutine] move || { let a = A(&mut true, &mut true, No); //~^ temporary value dropped while borrowed //~| temporary value dropped while borrowed diff --git a/tests/ui/coroutine/auxiliary/metadata-sufficient-for-layout.rs b/tests/ui/coroutine/auxiliary/metadata-sufficient-for-layout.rs index 8af6973134a..8ecb8c0c097 100644 --- a/tests/ui/coroutine/auxiliary/metadata-sufficient-for-layout.rs +++ b/tests/ui/coroutine/auxiliary/metadata-sufficient-for-layout.rs @@ -5,6 +5,7 @@ use std::marker::Unpin; use std::ops::Coroutine; pub fn g() -> impl Coroutine<(), Yield = (), Return = ()> { + #[coroutine] || { yield; } diff --git a/tests/ui/coroutine/auxiliary/unwind-aux.rs b/tests/ui/coroutine/auxiliary/unwind-aux.rs index ff1e8ed32cd..5d5e5c2218d 100644 --- a/tests/ui/coroutine/auxiliary/unwind-aux.rs +++ b/tests/ui/coroutine/auxiliary/unwind-aux.rs @@ -2,9 +2,10 @@ //@ no-prefer-dynamic //@ edition:2021 -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] pub fn run<T>(a: T) { - let _ = move || { + let _ = #[coroutine] + move || { drop(a); yield; }; diff --git a/tests/ui/coroutine/auxiliary/xcrate-reachable.rs b/tests/ui/coroutine/auxiliary/xcrate-reachable.rs index 673153f0619..0b5d1882300 100644 --- a/tests/ui/coroutine/auxiliary/xcrate-reachable.rs +++ b/tests/ui/coroutine/auxiliary/xcrate-reachable.rs @@ -7,6 +7,7 @@ fn msg() -> u32 { } pub fn foo() -> impl Coroutine<(), Yield = (), Return = u32> { + #[coroutine] || { yield; return msg(); diff --git a/tests/ui/coroutine/auxiliary/xcrate.rs b/tests/ui/coroutine/auxiliary/xcrate.rs index f749a95ad35..52f188135bd 100644 --- a/tests/ui/coroutine/auxiliary/xcrate.rs +++ b/tests/ui/coroutine/auxiliary/xcrate.rs @@ -1,9 +1,10 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::marker::Unpin; use std::ops::Coroutine; pub fn foo() -> impl Coroutine<(), Yield = (), Return = ()> { + #[coroutine] || { if false { yield; @@ -12,7 +13,10 @@ pub fn foo() -> impl Coroutine<(), Yield = (), Return = ()> { } pub fn bar<T: 'static>(t: T) -> Box<Coroutine<(), Yield = T, Return = ()> + Unpin> { - Box::new(|| { - yield t; - }) + Box::new( + #[coroutine] + || { + yield t; + }, + ) } diff --git a/tests/ui/coroutine/borrow-in-tail-expr.rs b/tests/ui/coroutine/borrow-in-tail-expr.rs index 2f0aa62019e..380e95cfc77 100644 --- a/tests/ui/coroutine/borrow-in-tail-expr.rs +++ b/tests/ui/coroutine/borrow-in-tail-expr.rs @@ -1,9 +1,9 @@ //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let _a = || { + let _a = #[coroutine] || { yield; let a = String::new(); a.len() diff --git a/tests/ui/coroutine/borrowing.rs b/tests/ui/coroutine/borrowing.rs index 778eed8bd0d..a6628766c1b 100644 --- a/tests/ui/coroutine/borrowing.rs +++ b/tests/ui/coroutine/borrowing.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; @@ -6,13 +6,13 @@ use std::pin::Pin; fn main() { let _b = { let a = 3; - Pin::new(&mut || yield &a).resume(()) + Pin::new(&mut #[coroutine] || yield &a).resume(()) //~^ ERROR: `a` does not live long enough }; let _b = { let a = 3; - || { + #[coroutine] || { yield &a //~^ ERROR: `a` does not live long enough } diff --git a/tests/ui/coroutine/borrowing.stderr b/tests/ui/coroutine/borrowing.stderr index acd4cdafdfd..4f8b9737777 100644 --- a/tests/ui/coroutine/borrowing.stderr +++ b/tests/ui/coroutine/borrowing.stderr @@ -1,13 +1,14 @@ error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:9:33 + --> $DIR/borrowing.rs:9:46 | LL | let _b = { | -- borrow later stored here LL | let a = 3; -LL | Pin::new(&mut || yield &a).resume(()) - | -- ^ borrowed value does not live long enough - | | - | value captured here by coroutine + | - binding `a` declared here +LL | Pin::new(&mut #[coroutine] || yield &a).resume(()) + | -- ^ borrowed value does not live long enough + | | + | value captured here by coroutine LL | LL | }; | - `a` dropped here while still borrowed @@ -18,8 +19,9 @@ error[E0597]: `a` does not live long enough LL | let _b = { | -- borrow later stored here LL | let a = 3; -LL | || { - | -- value captured here by coroutine + | - binding `a` declared here +LL | #[coroutine] || { + | -- value captured here by coroutine LL | yield &a | ^ borrowed value does not live long enough ... diff --git a/tests/ui/coroutine/check-resume-ty-lifetimes-2.rs b/tests/ui/coroutine/check-resume-ty-lifetimes-2.rs index a316c50e867..327756ebe66 100644 --- a/tests/ui/coroutine/check-resume-ty-lifetimes-2.rs +++ b/tests/ui/coroutine/check-resume-ty-lifetimes-2.rs @@ -7,27 +7,27 @@ struct Contravariant<'a>(fn(&'a ())); struct Covariant<'a>(fn() -> &'a ()); fn bad1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'short>> { - |_: Covariant<'short>| { + #[coroutine] |_: Covariant<'short>| { let a: Covariant<'long> = yield (); //~^ ERROR lifetime may not live long enough } } fn bad2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'long>> { - |_: Contravariant<'long>| { + #[coroutine] |_: Contravariant<'long>| { let a: Contravariant<'short> = yield (); //~^ ERROR lifetime may not live long enough } } fn good1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'long>> { - |_: Covariant<'long>| { + #[coroutine] |_: Covariant<'long>| { let a: Covariant<'short> = yield (); } } fn good2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'short>> { - |_: Contravariant<'short>| { + #[coroutine] |_: Contravariant<'short>| { let a: Contravariant<'long> = yield (); } } diff --git a/tests/ui/coroutine/check-resume-ty-lifetimes-2.stderr b/tests/ui/coroutine/check-resume-ty-lifetimes-2.stderr index e0cbca2dd52..8eb7ab3501b 100644 --- a/tests/ui/coroutine/check-resume-ty-lifetimes-2.stderr +++ b/tests/ui/coroutine/check-resume-ty-lifetimes-2.stderr @@ -5,15 +5,15 @@ LL | fn bad1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'short>> { | ------ ----- lifetime `'long` defined here | | | lifetime `'short` defined here -LL | |_: Covariant<'short>| { +LL | #[coroutine] |_: Covariant<'short>| { LL | let a: Covariant<'long> = yield (); | ^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` | = help: consider adding the following bound: `'short: 'long` help: consider adding 'move' keyword before the nested closure | -LL | move |_: Covariant<'short>| { - | ++++ +LL | #[coroutine] move |_: Covariant<'short>| { + | ++++ error: lifetime may not live long enough --> $DIR/check-resume-ty-lifetimes-2.rs:18:40 @@ -22,15 +22,15 @@ LL | fn bad2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'long>> { | ------ ----- lifetime `'long` defined here | | | lifetime `'short` defined here -LL | |_: Contravariant<'long>| { +LL | #[coroutine] |_: Contravariant<'long>| { LL | let a: Contravariant<'short> = yield (); | ^^^^^^^^ yielding this value requires that `'short` must outlive `'long` | = help: consider adding the following bound: `'short: 'long` help: consider adding 'move' keyword before the nested closure | -LL | move |_: Contravariant<'long>| { - | ++++ +LL | #[coroutine] move |_: Contravariant<'long>| { + | ++++ error: aborting due to 2 previous errors diff --git a/tests/ui/coroutine/check-resume-ty-lifetimes.rs b/tests/ui/coroutine/check-resume-ty-lifetimes.rs index add0b5080a8..b75e46c541c 100644 --- a/tests/ui/coroutine/check-resume-ty-lifetimes.rs +++ b/tests/ui/coroutine/check-resume-ty-lifetimes.rs @@ -1,5 +1,5 @@ #![feature(coroutine_trait)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![allow(unused)] use std::ops::Coroutine; @@ -9,11 +9,14 @@ use std::pin::pin; fn mk_static(s: &str) -> &'static str { let mut storage: Option<&'static str> = None; - let mut coroutine = pin!(|_: &str| { - let x: &'static str = yield (); - //~^ ERROR lifetime may not live long enough - storage = Some(x); - }); + let mut coroutine = pin!( + #[coroutine] + |_: &str| { + let x: &'static str = yield (); + //~^ ERROR lifetime may not live long enough + storage = Some(x); + } + ); coroutine.as_mut().resume(s); coroutine.as_mut().resume(s); diff --git a/tests/ui/coroutine/check-resume-ty-lifetimes.stderr b/tests/ui/coroutine/check-resume-ty-lifetimes.stderr index f373aa778a8..1fbaeb9f7fa 100644 --- a/tests/ui/coroutine/check-resume-ty-lifetimes.stderr +++ b/tests/ui/coroutine/check-resume-ty-lifetimes.stderr @@ -1,11 +1,11 @@ error: lifetime may not live long enough - --> $DIR/check-resume-ty-lifetimes.rs:13:16 + --> $DIR/check-resume-ty-lifetimes.rs:15:20 | LL | fn mk_static(s: &str) -> &'static str { | - let's call the lifetime of this reference `'1` ... -LL | let x: &'static str = yield (); - | ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` +LL | let x: &'static str = yield (); + | ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/clone-impl-static.rs b/tests/ui/coroutine/clone-impl-static.rs index 9a165cf4672..56d1ccac703 100644 --- a/tests/ui/coroutine/clone-impl-static.rs +++ b/tests/ui/coroutine/clone-impl-static.rs @@ -1,10 +1,11 @@ // gate-test-coroutine_clone // Verifies that static coroutines cannot be cloned/copied. -#![feature(coroutines, coroutine_clone)] +#![feature(coroutines, coroutine_clone, stmt_expr_attributes)] fn main() { - let gen = static move || { + let gen = #[coroutine] + static move || { yield; }; check_copy(&gen); diff --git a/tests/ui/coroutine/clone-impl-static.stderr b/tests/ui/coroutine/clone-impl-static.stderr index 8fa9fb12bf6..43920326d5d 100644 --- a/tests/ui/coroutine/clone-impl-static.stderr +++ b/tests/ui/coroutine/clone-impl-static.stderr @@ -1,27 +1,27 @@ -error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}: Copy` is not satisfied - --> $DIR/clone-impl-static.rs:10:16 +error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}: Copy` is not satisfied + --> $DIR/clone-impl-static.rs:11:16 | LL | check_copy(&gen); - | ---------- ^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}` + | ---------- ^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}` | | | required by a bound introduced by this call | note: required by a bound in `check_copy` - --> $DIR/clone-impl-static.rs:16:18 + --> $DIR/clone-impl-static.rs:17:18 | LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}: Clone` is not satisfied - --> $DIR/clone-impl-static.rs:12:17 +error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}: Clone` is not satisfied + --> $DIR/clone-impl-static.rs:13:17 | LL | check_clone(&gen); - | ----------- ^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}` + | ----------- ^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}` | | | required by a bound introduced by this call | note: required by a bound in `check_clone` - --> $DIR/clone-impl-static.rs:17:19 + --> $DIR/clone-impl-static.rs:18:19 | LL | fn check_clone<T: Clone>(_x: &T) {} | ^^^^^ required by this bound in `check_clone` diff --git a/tests/ui/coroutine/clone-impl.rs b/tests/ui/coroutine/clone-impl.rs index fffdae632ef..94420e56a22 100644 --- a/tests/ui/coroutine/clone-impl.rs +++ b/tests/ui/coroutine/clone-impl.rs @@ -2,13 +2,14 @@ // Verifies that non-static coroutines can be cloned/copied if all their upvars and locals held // across awaits can be cloned/copied. -#![feature(coroutines, coroutine_clone)] +#![feature(coroutines, coroutine_clone, stmt_expr_attributes)] struct NonClone; fn test1() { let copyable: u32 = 123; - let gen_copy_0 = move || { + let gen_copy_0 = #[coroutine] + move || { yield; drop(copyable); }; @@ -18,7 +19,8 @@ fn test1() { fn test2() { let copyable: u32 = 123; - let gen_copy_1 = move || { + let gen_copy_1 = #[coroutine] + move || { /* let v = vec!['a']; let n = NonClone; @@ -37,7 +39,8 @@ fn test2() { fn test3() { let clonable_0: Vec<u32> = Vec::new(); - let gen_clone_0 = move || { + let gen_clone_0 = #[coroutine] + move || { let v = vec!['a']; yield; drop(v); @@ -51,7 +54,8 @@ fn test3() { fn test4() { let clonable_1: Vec<u32> = Vec::new(); - let gen_clone_1 = move || { + let gen_clone_1 = #[coroutine] + move || { let v = vec!['a']; /* let n = NonClone; @@ -71,7 +75,8 @@ fn test4() { fn test5() { let non_clonable: NonClone = NonClone; - let gen_non_clone = move || { + let gen_non_clone = #[coroutine] + move || { yield; drop(non_clonable); }; diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr index b454846faac..5330d3bbd39 100644 --- a/tests/ui/coroutine/clone-impl.stderr +++ b/tests/ui/coroutine/clone-impl.stderr @@ -1,76 +1,76 @@ -error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}` - --> $DIR/clone-impl.rs:46:5 +error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` + --> $DIR/clone-impl.rs:49:5 | -LL | let gen_clone_0 = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:44:14 + --> $DIR/clone-impl.rs:47:14 | LL | drop(clonable_0); | ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:84:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}` - --> $DIR/clone-impl.rs:46:5 +error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` + --> $DIR/clone-impl.rs:49:5 | -LL | let gen_clone_0 = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:42:9 + --> $DIR/clone-impl.rs:45:9 | LL | let v = vec!['a']; | - has type `Vec<char>` which does not implement `Copy` LL | yield; | ^^^^^ yield occurs here, with `v` maybe used later note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:84:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}` - --> $DIR/clone-impl.rs:66:5 +error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` + --> $DIR/clone-impl.rs:70:5 | -LL | let gen_clone_1 = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:64:14 + --> $DIR/clone-impl.rs:68:14 | LL | drop(clonable_1); | ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:84:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}` - --> $DIR/clone-impl.rs:66:5 +error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` + --> $DIR/clone-impl.rs:70:5 | -LL | let gen_clone_1 = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:60:9 + --> $DIR/clone-impl.rs:64:9 | LL | let v = vec!['a']; | - has type `Vec<char>` which does not implement `Copy` @@ -78,27 +78,27 @@ LL | let v = vec!['a']; LL | yield; | ^^^^^ yield occurs here, with `v` maybe used later note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:84:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}` - --> $DIR/clone-impl.rs:78:5 +error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` + --> $DIR/clone-impl.rs:83:5 | -LL | let gen_non_clone = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` ... LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}: Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Copy` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:76:14 + --> $DIR/clone-impl.rs:81:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:84:18 + --> $DIR/clone-impl.rs:89:18 | LL | fn check_copy<T: Copy>(_x: &T) {} | ^^^^ required by this bound in `check_copy` @@ -108,22 +108,22 @@ LL + #[derive(Copy)] LL | struct NonClone; | -error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}` - --> $DIR/clone-impl.rs:80:5 +error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` + --> $DIR/clone-impl.rs:85:5 | -LL | let gen_non_clone = move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}` +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}` ... LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}: Clone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Clone` | note: captured value does not implement `Clone` - --> $DIR/clone-impl.rs:76:14 + --> $DIR/clone-impl.rs:81:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone` note: required by a bound in `check_clone` - --> $DIR/clone-impl.rs:85:19 + --> $DIR/clone-impl.rs:90:19 | LL | fn check_clone<T: Clone>(_x: &T) {} | ^^^^^ required by this bound in `check_clone` diff --git a/tests/ui/coroutine/clone-rpit.next.stderr b/tests/ui/coroutine/clone-rpit.next.stderr index 41aa2d63af0..c223f1f211a 100644 --- a/tests/ui/coroutine/clone-rpit.next.stderr +++ b/tests/ui/coroutine/clone-rpit.next.stderr @@ -5,32 +5,32 @@ LL | pub fn foo<'a, 'b>() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires coroutine witness types for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires promoting constants in MIR for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires checking if `foo::{closure#0}` contains FFI-unwind calls... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires building MIR for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires match-checking `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ note: ...which requires type-checking `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:14:5 + --> $DIR/clone-rpit.rs:15:5 | LL | move |_: ()| { | ^^^^^^^^^^^^ diff --git a/tests/ui/coroutine/clone-rpit.rs b/tests/ui/coroutine/clone-rpit.rs index 0df9bf61601..66569b4f427 100644 --- a/tests/ui/coroutine/clone-rpit.rs +++ b/tests/ui/coroutine/clone-rpit.rs @@ -11,6 +11,7 @@ // witness types, which we don't know until after borrowck. When we later check // the goal for correctness, we want to be able to bind the `impl Clone` opaque. pub fn foo<'a, 'b>() -> impl Clone { + #[coroutine] move |_: ()| { let () = yield (); } diff --git a/tests/ui/coroutine/conditional-drop.rs b/tests/ui/coroutine/conditional-drop.rs index 65d3a9e701e..52e1b561946 100644 --- a/tests/ui/coroutine/conditional-drop.rs +++ b/tests/ui/coroutine/conditional-drop.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; @@ -29,7 +29,7 @@ fn main() { } fn t1() { - let mut a = || { + let mut a = #[coroutine] || { let b = B; if test() { drop(b); @@ -45,7 +45,7 @@ fn t1() { } fn t2() { - let mut a = || { + let mut a = #[coroutine] || { let b = B; if test2() { drop(b); diff --git a/tests/ui/coroutine/control-flow.rs b/tests/ui/coroutine/control-flow.rs index 9070ba17856..f64b6f73883 100644 --- a/tests/ui/coroutine/control-flow.rs +++ b/tests/ui/coroutine/control-flow.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{CoroutineState, Coroutine}; use std::pin::Pin; @@ -24,25 +24,25 @@ fn finish<T>(mut amt: usize, mut t: T) -> T::Return } fn main() { - finish(1, || yield); - finish(8, || { + finish(1, #[coroutine] || yield); + finish(8, #[coroutine] || { for _ in 0..8 { yield; } }); - finish(1, || { + finish(1, #[coroutine] || { if true { yield; } else { } }); - finish(1, || { + finish(1, #[coroutine] || { if false { } else { yield; } }); - finish(2, || { + finish(2, #[coroutine] || { if { yield; false } { yield; panic!() diff --git a/tests/ui/coroutine/coroutine-region-requirements.rs b/tests/ui/coroutine/coroutine-region-requirements.rs index 8bc34fdd2f0..ab6f16995e2 100644 --- a/tests/ui/coroutine/coroutine-region-requirements.rs +++ b/tests/ui/coroutine/coroutine-region-requirements.rs @@ -1,9 +1,9 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn dangle(x: &mut i32) -> &'static mut i32 { - let mut g = || { + let mut g = #[coroutine] || { yield; x }; diff --git a/tests/ui/coroutine/coroutine-resume-after-panic.rs b/tests/ui/coroutine/coroutine-resume-after-panic.rs index 8445bf7e635..2745ebc6132 100644 --- a/tests/ui/coroutine/coroutine-resume-after-panic.rs +++ b/tests/ui/coroutine/coroutine-resume-after-panic.rs @@ -5,7 +5,7 @@ // Test that we get the correct message for resuming a panicked coroutine. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ ops::Coroutine, @@ -14,7 +14,7 @@ use std::{ }; fn main() { - let mut g = || { + let mut g = #[coroutine] || { panic!(); yield; }; diff --git a/tests/ui/coroutine/coroutine-with-nll.rs b/tests/ui/coroutine/coroutine-with-nll.rs index 28a3643fbc9..fa77ab4e049 100644 --- a/tests/ui/coroutine/coroutine-with-nll.rs +++ b/tests/ui/coroutine/coroutine-with-nll.rs @@ -1,6 +1,7 @@ #![feature(coroutines)] fn main() { + #[coroutine] || { // The reference in `_a` is a Legal with NLL since it ends before the yield let _a = &mut true; diff --git a/tests/ui/coroutine/coroutine-with-nll.stderr b/tests/ui/coroutine/coroutine-with-nll.stderr index 77e8bb1f92e..3f3d51da311 100644 --- a/tests/ui/coroutine/coroutine-with-nll.stderr +++ b/tests/ui/coroutine/coroutine-with-nll.stderr @@ -1,5 +1,5 @@ error[E0626]: borrow may still be in use when coroutine yields - --> $DIR/coroutine-with-nll.rs:7:17 + --> $DIR/coroutine-with-nll.rs:8:17 | LL | let b = &mut true; | ^^^^^^^^^ diff --git a/tests/ui/coroutine/coroutine-yielding-or-returning-itself.rs b/tests/ui/coroutine/coroutine-yielding-or-returning-itself.rs index 3c91b3c9329..f3110d71d0d 100644 --- a/tests/ui/coroutine/coroutine-yielding-or-returning-itself.rs +++ b/tests/ui/coroutine/coroutine-yielding-or-returning-itself.rs @@ -1,5 +1,5 @@ #![feature(coroutine_trait)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] // Test that we cannot create a coroutine that returns a value of its // own type. @@ -12,7 +12,7 @@ pub fn want_cyclic_coroutine_return<T>(_: T) } fn supply_cyclic_coroutine_return() { - want_cyclic_coroutine_return(|| { + want_cyclic_coroutine_return(#[coroutine] || { //~^ ERROR type mismatch if false { yield None.unwrap(); } None.unwrap() @@ -25,7 +25,7 @@ pub fn want_cyclic_coroutine_yield<T>(_: T) } fn supply_cyclic_coroutine_yield() { - want_cyclic_coroutine_yield(|| { + want_cyclic_coroutine_yield(#[coroutine] || { //~^ ERROR type mismatch if false { yield None.unwrap(); } None.unwrap() diff --git a/tests/ui/coroutine/coroutine-yielding-or-returning-itself.stderr b/tests/ui/coroutine/coroutine-yielding-or-returning-itself.stderr index 325030524ba..32799148ae1 100644 --- a/tests/ui/coroutine/coroutine-yielding-or-returning-itself.stderr +++ b/tests/ui/coroutine/coroutine-yielding-or-returning-itself.stderr @@ -1,8 +1,8 @@ -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:34: 15:36} as Coroutine>::Return == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:34: 15:36}` - --> $DIR/coroutine-yielding-or-returning-itself.rs:15:34 +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:47: 15:49} as Coroutine>::Return == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:47: 15:49}` + --> $DIR/coroutine-yielding-or-returning-itself.rs:15:47 | -LL | want_cyclic_coroutine_return(|| { - | _____----------------------------_^ +LL | want_cyclic_coroutine_return(#[coroutine] || { + | _____----------------------------______________^ | | | | | required by a bound introduced by this call LL | | @@ -23,11 +23,11 @@ LL | pub fn want_cyclic_coroutine_return<T>(_: T) LL | where T: Coroutine<Yield = (), Return = T> | ^^^^^^^^^^ required by this bound in `want_cyclic_coroutine_return` -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:33: 28:35} as Coroutine>::Yield == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:33: 28:35}` - --> $DIR/coroutine-yielding-or-returning-itself.rs:28:33 +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:46: 28:48} as Coroutine>::Yield == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:46: 28:48}` + --> $DIR/coroutine-yielding-or-returning-itself.rs:28:46 | -LL | want_cyclic_coroutine_yield(|| { - | _____---------------------------_^ +LL | want_cyclic_coroutine_yield(#[coroutine] || { + | _____---------------------------______________^ | | | | | required by a bound introduced by this call LL | | diff --git a/tests/ui/coroutine/derived-drop-parent-expr.rs b/tests/ui/coroutine/derived-drop-parent-expr.rs index f70a732c90f..cc217e4960e 100644 --- a/tests/ui/coroutine/derived-drop-parent-expr.rs +++ b/tests/ui/coroutine/derived-drop-parent-expr.rs @@ -1,7 +1,7 @@ //@ build-pass //! Like drop-tracking-parent-expression, but also tests that this doesn't ICE when building MIR -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn assert_send<T: Send>(_thing: T) {} @@ -9,8 +9,8 @@ fn assert_send<T: Send>(_thing: T) {} pub struct Client { pub nickname: String } fn main() { - let g = move || match drop(Client { ..Client::default() }) { - _status => yield, - }; + let g = #[coroutine] move || match drop(Client { ..Client::default() }) { + _status => yield, + }; assert_send(g); } diff --git a/tests/ui/coroutine/discriminant.rs b/tests/ui/coroutine/discriminant.rs index a44d8f74746..d6879e21825 100644 --- a/tests/ui/coroutine/discriminant.rs +++ b/tests/ui/coroutine/discriminant.rs @@ -86,7 +86,7 @@ fn cycle( fn main() { // Has only one invalid discr. value. let gen_u8_tiny_niche = || { - || { + #[coroutine] || { // 3 reserved variants yield250!(); // 253 variants @@ -98,7 +98,7 @@ fn main() { // Uses all values in the u8 discriminant. let gen_u8_full = || { - || { + #[coroutine] || { // 3 reserved variants yield250!(); // 253 variants @@ -111,7 +111,7 @@ fn main() { // Barely needs a u16 discriminant. let gen_u16 = || { - || { + #[coroutine] || { // 3 reserved variants yield250!(); // 253 variants diff --git a/tests/ui/coroutine/drop-and-replace.rs b/tests/ui/coroutine/drop-and-replace.rs index 6e30d76512b..d3d7e000020 100644 --- a/tests/ui/coroutine/drop-and-replace.rs +++ b/tests/ui/coroutine/drop-and-replace.rs @@ -4,7 +4,7 @@ // #60187, this produced incorrect code for coroutines when a saved local was // re-assigned. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -17,7 +17,8 @@ impl Drop for Foo { } fn main() { - let mut a = || { + let mut a = #[coroutine] + || { let mut x = Foo(4); yield; assert_eq!(x.0, 4); diff --git a/tests/ui/coroutine/drop-control-flow.rs b/tests/ui/coroutine/drop-control-flow.rs index f4e8eed4f8d..f576b1b7594 100644 --- a/tests/ui/coroutine/drop-control-flow.rs +++ b/tests/ui/coroutine/drop-control-flow.rs @@ -4,7 +4,7 @@ // and also that values that are dropped along all paths to a yield do not get // included in the coroutine type. -#![feature(coroutines, negative_impls)] +#![feature(coroutines, negative_impls, stmt_expr_attributes)] #![allow(unused_assignments, dead_code)] struct Ptr; @@ -19,7 +19,7 @@ fn assert_send<T: Send>(_: T) {} // This test case is reduced from tests/ui/drop/dynamic-drop-async.rs fn one_armed_if(arg: bool) { - let _ = || { + let _ = #[coroutine] || { let arr = [Ptr]; if arg { drop(arr); @@ -29,7 +29,7 @@ fn one_armed_if(arg: bool) { } fn two_armed_if(arg: bool) { - assert_send(|| { + assert_send(#[coroutine] || { let arr = [Ptr]; if arg { drop(arr); @@ -41,7 +41,7 @@ fn two_armed_if(arg: bool) { } fn if_let(arg: Option<i32>) { - let _ = || { + let _ = #[coroutine] || { let arr = [Ptr]; if let Some(_) = arg { drop(arr); @@ -51,7 +51,7 @@ fn if_let(arg: Option<i32>) { } fn init_in_if(arg: bool) { - assert_send(|| { + assert_send(#[coroutine] || { let mut x = NonSend; drop(x); if arg { @@ -63,7 +63,7 @@ fn init_in_if(arg: bool) { } fn init_in_match_arm(arg: Option<i32>) { - assert_send(|| { + assert_send(#[coroutine] || { let mut x = NonSend; drop(x); match arg { @@ -74,7 +74,7 @@ fn init_in_match_arm(arg: Option<i32>) { } fn reinit() { - let _ = || { + let _ = #[coroutine] || { let mut arr = [Ptr]; drop(arr); arr = [Ptr]; @@ -83,7 +83,7 @@ fn reinit() { } fn loop_uninit() { - let _ = || { + let _ = #[coroutine] || { let mut arr = [Ptr]; let mut count = 0; drop(arr); @@ -96,7 +96,7 @@ fn loop_uninit() { } fn nested_loop() { - let _ = || { + let _ = #[coroutine] || { let mut arr = [Ptr]; let mut count = 0; drop(arr); @@ -111,7 +111,7 @@ fn nested_loop() { } fn loop_continue(b: bool) { - let _ = || { + let _ = #[coroutine] || { let mut arr = [Ptr]; let mut count = 0; drop(arr); diff --git a/tests/ui/coroutine/drop-env.rs b/tests/ui/coroutine/drop-env.rs index b189ab81499..d36228dc849 100644 --- a/tests/ui/coroutine/drop-env.rs +++ b/tests/ui/coroutine/drop-env.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![allow(dropping_copy_types)] use std::ops::Coroutine; @@ -28,7 +28,7 @@ fn main() { fn t1() { let b = B; - let mut foo = || { + let mut foo = #[coroutine] || { yield; drop(b); }; @@ -42,7 +42,7 @@ fn t1() { fn t2() { let b = B; - let mut foo = || { + let mut foo = #[coroutine] || { yield b; }; @@ -55,7 +55,7 @@ fn t2() { fn t3() { let b = B; - let foo = || { + let foo = #[coroutine] || { yield; drop(b); }; diff --git a/tests/ui/coroutine/drop-track-addassign-yield.rs b/tests/ui/coroutine/drop-track-addassign-yield.rs index b1a4bd79f31..537e66c41b2 100644 --- a/tests/ui/coroutine/drop-track-addassign-yield.rs +++ b/tests/ui/coroutine/drop-track-addassign-yield.rs @@ -3,10 +3,10 @@ // Based on addassign-yield.rs, but with drop tracking enabled. Originally we did not implement // the fake_read callback on ExprUseVisitor which caused this case to break. -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn foo() { - let _y = static || { + let _y = #[coroutine] static || { let x = &mut 0; *{ yield; @@ -17,7 +17,7 @@ fn foo() { }; // Please don't ever actually write something like this - let _z = static || { + let _z = #[coroutine] static || { let x = &mut 0; *{ let inner = &mut 1; diff --git a/tests/ui/coroutine/drop-tracking-parent-expression.rs b/tests/ui/coroutine/drop-tracking-parent-expression.rs index 4d40192c07a..0f4d99c8936 100644 --- a/tests/ui/coroutine/drop-tracking-parent-expression.rs +++ b/tests/ui/coroutine/drop-tracking-parent-expression.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, negative_impls, rustc_attrs)] +#![feature(coroutines, negative_impls, rustc_attrs, stmt_expr_attributes)] macro_rules! type_combinations { ( @@ -14,7 +14,7 @@ macro_rules! type_combinations { // Struct update syntax. This fails because the Client used in the update is considered // dropped *after* the yield. { - let g = move || match drop($name::Client { ..$name::Client::default() }) { + let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { //~^ `significant_drop::Client` which is not `Send` //~| `insignificant_dtor::Client` which is not `Send` //~| `derived_drop::Client` which is not `Send` @@ -29,7 +29,7 @@ macro_rules! type_combinations { // Simple owned value. This works because the Client is considered moved into `drop`, // even though the temporary expression doesn't end until after the yield. { - let g = move || match drop($name::Client::default()) { + let g = #[coroutine] move || match drop($name::Client::default()) { _ => yield, }; assert_send(g); diff --git a/tests/ui/coroutine/drop-tracking-parent-expression.stderr b/tests/ui/coroutine/drop-tracking-parent-expression.stderr index 21aa35b9579..5f8d8495e4f 100644 --- a/tests/ui/coroutine/drop-tracking-parent-expression.stderr +++ b/tests/ui/coroutine/drop-tracking-parent-expression.stderr @@ -13,12 +13,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `derived_drop::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later @@ -53,12 +53,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `significant_drop::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later @@ -93,12 +93,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later diff --git a/tests/ui/coroutine/drop-tracking-yielding-in-match-guards.rs b/tests/ui/coroutine/drop-tracking-yielding-in-match-guards.rs index 0f94016f11b..43e42fa85f7 100644 --- a/tests/ui/coroutine/drop-tracking-yielding-in-match-guards.rs +++ b/tests/ui/coroutine/drop-tracking-yielding-in-match-guards.rs @@ -1,10 +1,10 @@ //@ build-pass //@ edition:2018 -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let _ = static |x: u8| match x { + let _ = #[coroutine] static |x: u8| match x { y if { yield } == y + 1 => (), _ => (), }; diff --git a/tests/ui/coroutine/drop-yield-twice.rs b/tests/ui/coroutine/drop-yield-twice.rs index 015343a2776..7ac1345b2ff 100644 --- a/tests/ui/coroutine/drop-yield-twice.rs +++ b/tests/ui/coroutine/drop-yield-twice.rs @@ -1,10 +1,10 @@ -#![feature(negative_impls, coroutines)] +#![feature(negative_impls, coroutines, stmt_expr_attributes)] struct Foo(i32); impl !Send for Foo {} fn main() { - assert_send(|| { //~ ERROR coroutine cannot be sent between threads safely + assert_send(#[coroutine] || { //~ ERROR coroutine cannot be sent between threads safely let guard = Foo(42); yield; drop(guard); diff --git a/tests/ui/coroutine/drop-yield-twice.stderr b/tests/ui/coroutine/drop-yield-twice.stderr index c6a9e20b8b5..362c6e943ad 100644 --- a/tests/ui/coroutine/drop-yield-twice.stderr +++ b/tests/ui/coroutine/drop-yield-twice.stderr @@ -1,7 +1,7 @@ error: coroutine cannot be sent between threads safely --> $DIR/drop-yield-twice.rs:7:5 | -LL | / assert_send(|| { +LL | / assert_send(#[coroutine] || { LL | | let guard = Foo(42); LL | | yield; LL | | drop(guard); @@ -9,7 +9,7 @@ LL | | yield; LL | | }) | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:17: 7:19}`, the trait `Send` is not implemented for `Foo`, which is required by `{coroutine@$DIR/drop-yield-twice.rs:7:17: 7:19}: Send` + = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}`, the trait `Send` is not implemented for `Foo`, which is required by `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-yield-twice.rs:9:9 | diff --git a/tests/ui/coroutine/dropck-resume.rs b/tests/ui/coroutine/dropck-resume.rs index 07ca4d37aba..df014400f00 100644 --- a/tests/ui/coroutine/dropck-resume.rs +++ b/tests/ui/coroutine/dropck-resume.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -16,7 +16,8 @@ fn drop_using_coroutine() -> i32 { let z = &mut y; let r; { - let mut g = move |r| { + let mut g = #[coroutine] + move |r| { let _s = SetToNone(r); yield; }; diff --git a/tests/ui/coroutine/dropck-resume.stderr b/tests/ui/coroutine/dropck-resume.stderr index aa6e423c760..e9243ffa41e 100644 --- a/tests/ui/coroutine/dropck-resume.stderr +++ b/tests/ui/coroutine/dropck-resume.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/dropck-resume.rs:25:13 + --> $DIR/dropck-resume.rs:26:13 | LL | let z = &mut y; | ------ mutable borrow occurs here diff --git a/tests/ui/coroutine/dropck.rs b/tests/ui/coroutine/dropck.rs index 450361c8dd0..9331c1fa1d5 100644 --- a/tests/ui/coroutine/dropck.rs +++ b/tests/ui/coroutine/dropck.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::cell::RefCell; use std::ops::Coroutine; @@ -10,7 +10,8 @@ fn main() { let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); //~^ ERROR `*cell` does not live long enough [E0597] // the upvar is the non-dropck `&mut Option<Ref<'a, i32>>`. - gen = || { + gen = #[coroutine] + || { // but the coroutine can use it to drop a `Ref<'a, i32>`. let _d = ref_.take(); //~ ERROR `ref_` does not live long enough yield; diff --git a/tests/ui/coroutine/dropck.stderr b/tests/ui/coroutine/dropck.stderr index 241d6dfe0a1..78fdeec972f 100644 --- a/tests/ui/coroutine/dropck.stderr +++ b/tests/ui/coroutine/dropck.stderr @@ -16,10 +16,13 @@ LL | } = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `ref_` does not live long enough - --> $DIR/dropck.rs:15:18 + --> $DIR/dropck.rs:16:18 | -LL | gen = || { - | -- value captured here by coroutine +LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); + | ---- binding `ref_` declared here +... +LL | || { + | -- value captured here by coroutine LL | // but the coroutine can use it to drop a `Ref<'a, i32>`. LL | let _d = ref_.take(); | ^^^^ borrowed value does not live long enough diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr index 2b9eb4a820b..322259cf2f8 100644 --- a/tests/ui/coroutine/gen_block.e2024.stderr +++ b/tests/ui/coroutine/gen_block.e2024.stderr @@ -1,5 +1,25 @@ +error[E0658]: the `#[coroutines]` attribute is an experimental feature + --> $DIR/gen_block.rs:20:13 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[coroutines]` attribute is an experimental feature + --> $DIR/gen_block.rs:24:13 + | +LL | let _ = #[coroutine] || {}; + | ^^^^^^^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: yield syntax is experimental - --> $DIR/gen_block.rs:15:16 + --> $DIR/gen_block.rs:16:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -8,13 +28,34 @@ LL | let _ = || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/gen_block.rs:16:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield true; + | ++++++++++++ + +error[E0658]: yield syntax is experimental + --> $DIR/gen_block.rs:20:29 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0282]: type annotations needed - --> $DIR/gen_block.rs:6:13 + --> $DIR/gen_block.rs:7:13 | LL | let x = gen {}; | ^^^^^^ cannot infer type -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0282, E0658. For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr index 78a8c5e798a..64fa2be003d 100644 --- a/tests/ui/coroutine/gen_block.none.stderr +++ b/tests/ui/coroutine/gen_block.none.stderr @@ -1,5 +1,5 @@ error: expected identifier, found reserved keyword `yield` - --> $DIR/gen_block.rs:9:19 + --> $DIR/gen_block.rs:10:19 | LL | let y = gen { yield 42 }; | --- ^^^^^ expected identifier, found reserved keyword @@ -7,25 +7,25 @@ LL | let y = gen { yield 42 }; | while parsing this struct error[E0422]: cannot find struct, variant or union type `gen` in this scope - --> $DIR/gen_block.rs:6:13 + --> $DIR/gen_block.rs:7:13 | LL | let x = gen {}; | ^^^ not found in this scope error[E0422]: cannot find struct, variant or union type `gen` in this scope - --> $DIR/gen_block.rs:9:13 + --> $DIR/gen_block.rs:10:13 | LL | let y = gen { yield 42 }; | ^^^ not found in this scope error[E0422]: cannot find struct, variant or union type `gen` in this scope - --> $DIR/gen_block.rs:12:5 + --> $DIR/gen_block.rs:13:5 | LL | gen {}; | ^^^ not found in this scope error[E0658]: yield syntax is experimental - --> $DIR/gen_block.rs:15:16 + --> $DIR/gen_block.rs:16:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -35,17 +35,69 @@ LL | let _ = || yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/gen_block.rs:15:16 + --> $DIR/gen_block.rs:20:29 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[coroutines]` attribute is an experimental feature + --> $DIR/gen_block.rs:20:13 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[coroutines]` attribute is an experimental feature + --> $DIR/gen_block.rs:24:13 + | +LL | let _ = #[coroutine] || {}; + | ^^^^^^^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: yield syntax is experimental + --> $DIR/gen_block.rs:16:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/gen_block.rs:16:16 | LL | let _ = || yield true; | ^^^^^^^^^^ | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield true; + | ++++++++++++ + +error[E0658]: yield syntax is experimental + --> $DIR/gen_block.rs:20:29 + | +LL | let _ = #[coroutine] || yield true; + | ^^^^^^^^^^ + | = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 6 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0422, E0658. For more information about an error, try `rustc --explain E0422`. diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs index f6a775aa661..7e87a572b90 100644 --- a/tests/ui/coroutine/gen_block.rs +++ b/tests/ui/coroutine/gen_block.rs @@ -1,6 +1,7 @@ //@ revisions: e2024 none //@[e2024] compile-flags: --edition 2024 -Zunstable-options #![cfg_attr(e2024, feature(gen_blocks))] +#![feature(stmt_expr_attributes)] fn main() { let x = gen {}; @@ -14,4 +15,12 @@ fn main() { let _ = || yield true; //[none]~ ERROR yield syntax is experimental //~^ ERROR yield syntax is experimental + //~^^ ERROR `yield` can only be used in + + let _ = #[coroutine] || yield true; //[none]~ ERROR yield syntax is experimental + //~^ ERROR `#[coroutines]` attribute is an experimental feature + //~^^ ERROR yield syntax is experimental + + let _ = #[coroutine] || {}; + //~^ ERROR `#[coroutines]` attribute is an experimental feature } diff --git a/tests/ui/coroutine/issue-102645.rs b/tests/ui/coroutine/issue-102645.rs index a0263510e13..ccf82c3606a 100644 --- a/tests/ui/coroutine/issue-102645.rs +++ b/tests/ui/coroutine/issue-102645.rs @@ -1,11 +1,12 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { let mut a = 5; - let mut b = || { + let mut b = #[coroutine] + || { let d = 6; yield; _zzz(); // #break diff --git a/tests/ui/coroutine/issue-102645.stderr b/tests/ui/coroutine/issue-102645.stderr index 7a3b7f2b04c..ab5e4a8459f 100644 --- a/tests/ui/coroutine/issue-102645.stderr +++ b/tests/ui/coroutine/issue-102645.stderr @@ -1,5 +1,5 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied - --> $DIR/issue-102645.rs:14:22 + --> $DIR/issue-102645.rs:15:22 | LL | Pin::new(&mut b).resume(); | ^^^^^^-- an argument of type `()` is missing diff --git a/tests/ui/coroutine/issue-105084.rs b/tests/ui/coroutine/issue-105084.rs index 7801f1bcea0..4e40bc127d7 100644 --- a/tests/ui/coroutine/issue-105084.rs +++ b/tests/ui/coroutine/issue-105084.rs @@ -11,7 +11,8 @@ fn copy<T: Copy>(x: T) -> T { } fn main() { - let mut g = || { + let mut g = #[coroutine] + || { // This is desuraged as 4 stages: // - allocate a `*mut u8` with `exchange_malloc`; // - create a Box that is ignored for trait computations; diff --git a/tests/ui/coroutine/issue-105084.stderr b/tests/ui/coroutine/issue-105084.stderr index c8a6522dbd9..6b1701f0c2a 100644 --- a/tests/ui/coroutine/issue-105084.stderr +++ b/tests/ui/coroutine/issue-105084.stderr @@ -1,8 +1,8 @@ error[E0382]: borrow of moved value: `g` - --> $DIR/issue-105084.rs:37:14 + --> $DIR/issue-105084.rs:38:14 | -LL | let mut g = || { - | ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}`, which does not implement the `Copy` trait +LL | let mut g = #[coroutine] + | ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, which does not implement the `Copy` trait ... LL | let mut h = copy(g); | - value moved here @@ -22,17 +22,17 @@ help: consider cloning the value if the performance cost is acceptable LL | let mut h = copy(g.clone()); | ++++++++ -error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}` - --> $DIR/issue-105084.rs:31:17 +error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}` + --> $DIR/issue-105084.rs:32:17 | -LL | let mut g = || { - | -- within this `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}` +LL | || { + | -- within this `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}` ... LL | let mut h = copy(g); - | ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}`, the trait `Copy` is not implemented for `Box<(i32, ())>`, which is required by `{coroutine@$DIR/issue-105084.rs:14:17: 14:19}: Copy` + | ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`, which is required by `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}: Copy` | note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/issue-105084.rs:21:22 + --> $DIR/issue-105084.rs:22:22 | LL | Box::new((5, yield)); | -------------^^^^^-- diff --git a/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs b/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs index 3d372ac9110..300c8fe6d46 100644 --- a/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs +++ b/tests/ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs @@ -1,11 +1,12 @@ //@ edition:2021 //@ check-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { let x = &mut (); || { - let _c = || yield *&mut *x; + let _c = #[coroutine] + || yield *&mut *x; || _ = &mut *x; }; } diff --git a/tests/ui/coroutine/issue-113279.rs b/tests/ui/coroutine/issue-113279.rs index f251c924c13..98617af105c 100644 --- a/tests/ui/coroutine/issue-113279.rs +++ b/tests/ui/coroutine/issue-113279.rs @@ -1,4 +1,4 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] // `foo` attempts to dereference `""`, which results in an error being reported. Later, the // coroutine transform for `foo` then produces a union which contains a `str` type - unions should @@ -9,7 +9,8 @@ // makes sure that doesn't happen again. fn foo() { - let _y = static || { + let _y = #[coroutine] + static || { let x = &mut 0; *{ yield; diff --git a/tests/ui/coroutine/issue-113279.stderr b/tests/ui/coroutine/issue-113279.stderr index cc9b64ef9ac..a80fe670188 100644 --- a/tests/ui/coroutine/issue-113279.stderr +++ b/tests/ui/coroutine/issue-113279.stderr @@ -1,11 +1,11 @@ error[E0161]: cannot move a value of type `str` - --> $DIR/issue-113279.rs:17:20 + --> $DIR/issue-113279.rs:18:20 | LL | } += match { *"" }.len() { | ^^^^^^^ the size of `str` cannot be statically determined error[E0507]: cannot move out of a shared reference - --> $DIR/issue-113279.rs:17:22 + --> $DIR/issue-113279.rs:18:22 | LL | } += match { *"" }.len() { | ^^^ move occurs because value has type `str`, which does not implement the `Copy` trait diff --git a/tests/ui/coroutine/issue-44197.rs b/tests/ui/coroutine/issue-44197.rs index e18bcc2c996..0240f7a7eaa 100644 --- a/tests/ui/coroutine/issue-44197.rs +++ b/tests/ui/coroutine/issue-44197.rs @@ -10,7 +10,7 @@ fn foo(_: &str) -> String { } fn bar(baz: String) -> impl Coroutine<(), Yield = String, Return = ()> { - move || { + #[coroutine] move || { yield foo(&baz); } } @@ -20,7 +20,7 @@ fn foo2(_: &str) -> Result<String, ()> { } fn bar2(baz: String) -> impl Coroutine<(), Yield = String, Return = ()> { - move || { + #[coroutine] move || { if let Ok(quux) = foo2(&baz) { yield quux; } diff --git a/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.rs b/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.rs index dab9c81bc8f..d90886b6b1d 100644 --- a/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.rs +++ b/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.rs @@ -1,7 +1,8 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let _ = || { + let _ = #[coroutine] + || { *(1 as *mut u32) = 42; //~^ ERROR dereference of raw pointer is unsafe yield; diff --git a/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.stderr b/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.stderr index 19949b42939..f99c295bb9e 100644 --- a/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.stderr +++ b/tests/ui/coroutine/issue-45729-unsafe-in-coroutine.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-45729-unsafe-in-coroutine.rs:5:9 + --> $DIR/issue-45729-unsafe-in-coroutine.rs:6:9 | LL | *(1 as *mut u32) = 42; | ^^^^^^^^^^^^^^^^ dereference of raw pointer diff --git a/tests/ui/coroutine/issue-48048.rs b/tests/ui/coroutine/issue-48048.rs index b61b7c77072..75664f20198 100644 --- a/tests/ui/coroutine/issue-48048.rs +++ b/tests/ui/coroutine/issue-48048.rs @@ -3,7 +3,7 @@ fn main() { let x = (|_| {},); - || { + #[coroutine] || { let x = x; x.0({ //~ ERROR borrow may still be in use when coroutine yields diff --git a/tests/ui/coroutine/issue-52304.rs b/tests/ui/coroutine/issue-52304.rs index 01ed181ab1d..552bc0028ee 100644 --- a/tests/ui/coroutine/issue-52304.rs +++ b/tests/ui/coroutine/issue-52304.rs @@ -5,6 +5,7 @@ use std::ops::Coroutine; pub fn example() -> impl Coroutine { + #[coroutine] || yield &1 } diff --git a/tests/ui/coroutine/issue-52398.rs b/tests/ui/coroutine/issue-52398.rs index 826ce6b9d9b..f8b2faf4eab 100644 --- a/tests/ui/coroutine/issue-52398.rs +++ b/tests/ui/coroutine/issue-52398.rs @@ -14,14 +14,14 @@ impl A { fn main() { // Test that the MIR local with type &A created for the auto-borrow adjustment // is caught by typeck - move || { //~ WARN unused coroutine that must be used + #[coroutine] move || { //~ WARN unused coroutine that must be used A.test(yield); }; // Test that the std::cell::Ref temporary returned from the `borrow` call // is caught by typeck let y = RefCell::new(true); - static move || { //~ WARN unused coroutine that must be used + #[coroutine] static move || { //~ WARN unused coroutine that must be used yield *y.borrow(); return "Done"; }; diff --git a/tests/ui/coroutine/issue-52398.stderr b/tests/ui/coroutine/issue-52398.stderr index 18d816da4c6..806690cc332 100644 --- a/tests/ui/coroutine/issue-52398.stderr +++ b/tests/ui/coroutine/issue-52398.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/issue-52398.rs:17:5 + --> $DIR/issue-52398.rs:17:18 | -LL | / move || { +LL | #[coroutine] move || { + | __________________^ LL | | A.test(yield); LL | | }; | |_____^ @@ -10,9 +11,10 @@ LL | | }; = note: `#[warn(unused_must_use)]` on by default warning: unused coroutine that must be used - --> $DIR/issue-52398.rs:24:5 + --> $DIR/issue-52398.rs:24:18 | -LL | / static move || { +LL | #[coroutine] static move || { + | __________________^ LL | | yield *y.borrow(); LL | | return "Done"; LL | | }; diff --git a/tests/ui/coroutine/issue-53548.rs b/tests/ui/coroutine/issue-53548.rs index 6d55994137f..3b8dff2be28 100644 --- a/tests/ui/coroutine/issue-53548.rs +++ b/tests/ui/coroutine/issue-53548.rs @@ -17,7 +17,7 @@ // //@ check-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] use std::cell::RefCell; use std::rc::Rc; @@ -29,7 +29,7 @@ struct Store<C> { } fn main() { - Box::new(static move || { + Box::new(#[coroutine] static move || { let store = Store::<Box<dyn Trait>> { inner: Default::default(), }; diff --git a/tests/ui/coroutine/issue-57017.rs b/tests/ui/coroutine/issue-57017.rs index b83d916932a..19cd80ab4a6 100644 --- a/tests/ui/coroutine/issue-57017.rs +++ b/tests/ui/coroutine/issue-57017.rs @@ -1,5 +1,5 @@ //@ build-pass -#![feature(coroutines, negative_impls)] +#![feature(coroutines, negative_impls, stmt_expr_attributes)] #![allow(dropping_references, dropping_copy_types)] macro_rules! type_combinations { @@ -21,7 +21,7 @@ macro_rules! type_combinations { // This is the same bug as issue 57017, but using yield instead of await { - let g = move || match drop(&$name::unsync::Client::default()) { + let g = #[coroutine] move || match drop(&$name::unsync::Client::default()) { _status => yield, }; assert_send(g); @@ -30,7 +30,7 @@ macro_rules! type_combinations { // This tests that `Client` is properly considered to be dropped after moving it into the // function. { - let g = move || match drop($name::unsend::Client::default()) { + let g = #[coroutine] move || match drop($name::unsend::Client::default()) { _status => yield, }; assert_send(g); diff --git a/tests/ui/coroutine/issue-57084.rs b/tests/ui/coroutine/issue-57084.rs index 51b0c8e1de9..2df60550e03 100644 --- a/tests/ui/coroutine/issue-57084.rs +++ b/tests/ui/coroutine/issue-57084.rs @@ -8,7 +8,7 @@ use std::ops::Coroutine; fn with<F>(f: F) -> impl Coroutine<Yield=(), Return=()> where F: Fn() -> () { - move || { + #[coroutine] move || { loop { match f() { _ => yield, @@ -19,7 +19,7 @@ where F: Fn() -> () fn main() { let data = &vec![1]; - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used let _to_pin = with(move || println!("{:p}", data)); loop { yield diff --git a/tests/ui/coroutine/issue-57084.stderr b/tests/ui/coroutine/issue-57084.stderr index 9f5b79a6ae8..81bd27da919 100644 --- a/tests/ui/coroutine/issue-57084.stderr +++ b/tests/ui/coroutine/issue-57084.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/issue-57084.rs:22:5 + --> $DIR/issue-57084.rs:22:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | let _to_pin = with(move || println!("{:p}", data)); LL | | loop { LL | | yield diff --git a/tests/ui/coroutine/issue-57478.rs b/tests/ui/coroutine/issue-57478.rs index 5e479aaa9c1..494c2ee9843 100644 --- a/tests/ui/coroutine/issue-57478.rs +++ b/tests/ui/coroutine/issue-57478.rs @@ -1,16 +1,19 @@ //@ check-pass -#![feature(negative_impls, coroutines)] +#![feature(negative_impls, coroutines, stmt_expr_attributes)] struct Foo; impl !Send for Foo {} fn main() { - assert_send(|| { - let guard = Foo; - drop(guard); - yield; - }) + assert_send( + #[coroutine] + || { + let guard = Foo; + drop(guard); + yield; + }, + ) } fn assert_send<T: Send>(_: T) {} diff --git a/tests/ui/coroutine/issue-58888.rs b/tests/ui/coroutine/issue-58888.rs index ce45f22dd6e..6266f97ce8c 100644 --- a/tests/ui/coroutine/issue-58888.rs +++ b/tests/ui/coroutine/issue-58888.rs @@ -13,7 +13,7 @@ impl Database { } fn check_connection(&self) -> impl Coroutine<Yield = (), Return = ()> + '_ { - move || { + #[coroutine] move || { let iter = self.get_connection(); for i in iter { yield i diff --git a/tests/ui/coroutine/issue-61442-stmt-expr-with-drop.rs b/tests/ui/coroutine/issue-61442-stmt-expr-with-drop.rs index 6280b777201..6f513c250a5 100644 --- a/tests/ui/coroutine/issue-61442-stmt-expr-with-drop.rs +++ b/tests/ui/coroutine/issue-61442-stmt-expr-with-drop.rs @@ -4,7 +4,7 @@ //@ check-pass //@ edition:2018 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; @@ -14,12 +14,14 @@ async fn drop_and_await() { } fn drop_and_yield() { - let x = || { + let x = #[coroutine] + || { String::new(); yield; }; Box::pin(x).as_mut().resume(()); - let y = static || { + let y = #[coroutine] + static || { String::new(); yield; }; diff --git a/tests/ui/coroutine/issue-64620-yield-array-element.rs b/tests/ui/coroutine/issue-64620-yield-array-element.rs index a9307d306a6..0d898d014e8 100644 --- a/tests/ui/coroutine/issue-64620-yield-array-element.rs +++ b/tests/ui/coroutine/issue-64620-yield-array-element.rs @@ -4,6 +4,7 @@ pub fn crash(arr: [usize; 1]) { yield arr[0]; //~ ERROR: yield expression outside of coroutine literal + //~^ ERROR: `yield` can only be used in } fn main() {} diff --git a/tests/ui/coroutine/issue-64620-yield-array-element.stderr b/tests/ui/coroutine/issue-64620-yield-array-element.stderr index 347532fb719..1c030c5248e 100644 --- a/tests/ui/coroutine/issue-64620-yield-array-element.stderr +++ b/tests/ui/coroutine/issue-64620-yield-array-element.stderr @@ -1,9 +1,20 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/issue-64620-yield-array-element.rs:6:5 + | +LL | yield arr[0]; + | ^^^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] pub fn crash(arr: [usize; 1]) { + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/issue-64620-yield-array-element.rs:6:5 | LL | yield arr[0]; | ^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/issue-68112.rs b/tests/ui/coroutine/issue-68112.rs index ccec2acc976..b296772c905 100644 --- a/tests/ui/coroutine/issue-68112.rs +++ b/tests/ui/coroutine/issue-68112.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ cell::RefCell, @@ -30,7 +30,7 @@ fn make_non_send_coroutine() -> impl Coroutine<Return = Arc<RefCell<i32>>> { } fn test1() { - let send_gen = || { + let send_gen = #[coroutine] || { let _non_send_gen = make_non_send_coroutine(); //~^ NOTE not `Send` yield; @@ -46,7 +46,7 @@ fn test1() { pub fn make_gen2<T>(t: T) -> impl Coroutine<Return = T> { //~^ NOTE appears within the type //~| NOTE expansion of desugaring - || { //~ NOTE used within this coroutine + #[coroutine] || { //~ NOTE used within this coroutine yield; t } @@ -57,7 +57,7 @@ fn make_non_send_coroutine2() -> impl Coroutine<Return = Arc<RefCell<i32>>> { // } fn test2() { - let send_gen = || { //~ NOTE used within this coroutine + let send_gen = #[coroutine] || { //~ NOTE used within this coroutine let _non_send_gen = make_non_send_coroutine2(); yield; }; diff --git a/tests/ui/coroutine/issue-68112.stderr b/tests/ui/coroutine/issue-68112.stderr index 443195d36a3..bcfcb5ec6e6 100644 --- a/tests/ui/coroutine/issue-68112.stderr +++ b/tests/ui/coroutine/issue-68112.stderr @@ -4,7 +4,7 @@ error: coroutine cannot be sent between threads safely LL | require_send(send_gen); | ^^^^^^^^^^^^^^^^^^^^^^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{coroutine@$DIR/issue-68112.rs:33:20: 33:22}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{coroutine@$DIR/issue-68112.rs:33:33: 33:35}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: coroutine is not `Send` as this value is used across a yield --> $DIR/issue-68112.rs:36:9 @@ -26,14 +26,14 @@ error[E0277]: `RefCell<i32>` cannot be shared between threads safely LL | require_send(send_gen); | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{coroutine@$DIR/issue-68112.rs:60:20: 60:22}: Send` + = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{coroutine@$DIR/issue-68112.rs:60:33: 60:35}: Send` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this coroutine - --> $DIR/issue-68112.rs:49:5 + --> $DIR/issue-68112.rs:49:18 | -LL | || { - | ^^ +LL | #[coroutine] || { + | ^^ note: required because it appears within the type `impl Coroutine<Return = Arc<RefCell<i32>>>` --> $DIR/issue-68112.rs:46:30 | @@ -45,10 +45,10 @@ note: required because it appears within the type `impl Coroutine<Return = Arc<R LL | fn make_non_send_coroutine2() -> impl Coroutine<Return = Arc<RefCell<i32>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it's used within this coroutine - --> $DIR/issue-68112.rs:60:20 + --> $DIR/issue-68112.rs:60:33 | -LL | let send_gen = || { - | ^^ +LL | let send_gen = #[coroutine] || { + | ^^ note: required by a bound in `require_send` --> $DIR/issue-68112.rs:22:25 | diff --git a/tests/ui/coroutine/issue-69017.rs b/tests/ui/coroutine/issue-69017.rs index 09bbf63a986..bf69e1dfdb1 100644 --- a/tests/ui/coroutine/issue-69017.rs +++ b/tests/ui/coroutine/issue-69017.rs @@ -10,6 +10,7 @@ use std::ops::Coroutine; fn gen() -> impl Coroutine<usize> { + #[coroutine] |_: usize| { println!("-> {}", yield); } diff --git a/tests/ui/coroutine/issue-69039.rs b/tests/ui/coroutine/issue-69039.rs index fd12414c3d8..13cb50e5828 100644 --- a/tests/ui/coroutine/issue-69039.rs +++ b/tests/ui/coroutine/issue-69039.rs @@ -9,6 +9,7 @@ fn mkstr(my_name: String, my_mood: String) -> String { } fn my_scenario() -> impl Coroutine<String, Yield = &'static str, Return = String> { + #[coroutine] |_arg: String| { let my_name = yield "What is your name?"; let my_mood = yield "How are you feeling?"; diff --git a/tests/ui/coroutine/issue-87142.rs b/tests/ui/coroutine/issue-87142.rs index f5c3805842c..6c22ba3dd75 100644 --- a/tests/ui/coroutine/issue-87142.rs +++ b/tests/ui/coroutine/issue-87142.rs @@ -22,6 +22,7 @@ pub struct Context<G: 'static + CoroutineProviderAlt> { impl CoroutineProviderAlt for () { type Coro = impl Coroutine<(), Return = (), Yield = ()>; fn start(ctx: Context<Self>) -> Self::Coro { + #[coroutine] move || { match ctx { _ => (), diff --git a/tests/ui/coroutine/issue-88653.rs b/tests/ui/coroutine/issue-88653.rs index ec4c2054758..3afd12a2093 100644 --- a/tests/ui/coroutine/issue-88653.rs +++ b/tests/ui/coroutine/issue-88653.rs @@ -11,6 +11,7 @@ fn foo(bar: bool) -> impl Coroutine<(bool,)> { //~| NOTE: expected coroutine signature `fn((bool,)) -> _` //~| NOTE: in this expansion of desugaring of `impl Trait` //~| NOTE: in this expansion of desugaring of `impl Trait` + #[coroutine] |bar| { //~^ NOTE: found signature defined here if bar { diff --git a/tests/ui/coroutine/issue-91477.rs b/tests/ui/coroutine/issue-91477.rs index c98546f7971..c215fd7948f 100644 --- a/tests/ui/coroutine/issue-91477.rs +++ b/tests/ui/coroutine/issue-91477.rs @@ -2,6 +2,7 @@ fn foo() -> impl Sized { yield 1; //~ ERROR E0627 + //~^ ERROR: `yield` can only be used in } fn main() {} diff --git a/tests/ui/coroutine/issue-91477.stderr b/tests/ui/coroutine/issue-91477.stderr index ca8e43d8a26..5e2151c4c35 100644 --- a/tests/ui/coroutine/issue-91477.stderr +++ b/tests/ui/coroutine/issue-91477.stderr @@ -1,9 +1,20 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/issue-91477.rs:4:5 + | +LL | yield 1; + | ^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn foo() -> impl Sized { + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/issue-91477.rs:4:5 | LL | yield 1; | ^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/iterator-count.rs b/tests/ui/coroutine/iterator-count.rs index bb202ab2d33..1ca8ceaed2a 100644 --- a/tests/ui/coroutine/iterator-count.rs +++ b/tests/ui/coroutine/iterator-count.rs @@ -21,6 +21,7 @@ impl<T: Coroutine<(), Return = ()> + Unpin> Iterator for W<T> { } fn test() -> impl Coroutine<(), Return = (), Yield = u8> + Unpin { + #[coroutine] || { for i in 1..6 { yield i @@ -32,6 +33,7 @@ fn main() { let end = 11; let closure_test = |start| { + #[coroutine] move || { for i in start..end { yield i diff --git a/tests/ui/coroutine/live-upvar-across-yield.rs b/tests/ui/coroutine/live-upvar-across-yield.rs index 86c4716c951..d13d480dcdc 100644 --- a/tests/ui/coroutine/live-upvar-across-yield.rs +++ b/tests/ui/coroutine/live-upvar-across-yield.rs @@ -1,13 +1,13 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { let b = |_| 3; - let mut a = || { + let mut a = #[coroutine] || { b(yield); }; Pin::new(&mut a).resume(()); diff --git a/tests/ui/coroutine/match-bindings.rs b/tests/ui/coroutine/match-bindings.rs index 9ea1deaab36..2a0cd9af9f3 100644 --- a/tests/ui/coroutine/match-bindings.rs +++ b/tests/ui/coroutine/match-bindings.rs @@ -9,7 +9,7 @@ enum Enum { } fn main() { - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used loop { if let true = true { match Enum::A(String::new()) { diff --git a/tests/ui/coroutine/match-bindings.stderr b/tests/ui/coroutine/match-bindings.stderr index a7aa6eadb95..5525bfed116 100644 --- a/tests/ui/coroutine/match-bindings.stderr +++ b/tests/ui/coroutine/match-bindings.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/match-bindings.rs:12:5 + --> $DIR/match-bindings.rs:12:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | loop { LL | | if let true = true { LL | | match Enum::A(String::new()) { diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed b/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed new file mode 100644 index 00000000000..128f09a1184 --- /dev/null +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed @@ -0,0 +1,8 @@ +//@ run-rustfix + +#![feature(coroutines, gen_blocks, stmt_expr_attributes)] + +fn main() { + let _ = #[coroutine] || yield; + //~^ ERROR `yield` can only be used +} diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs b/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs new file mode 100644 index 00000000000..dc952591496 --- /dev/null +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs @@ -0,0 +1,8 @@ +//@ run-rustfix + +#![feature(coroutines, gen_blocks, stmt_expr_attributes)] + +fn main() { + let _ = || yield; + //~^ ERROR `yield` can only be used +} diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.stderr b/tests/ui/coroutine/missing_coroutine_attr_suggestion.stderr new file mode 100644 index 00000000000..8d92471a361 --- /dev/null +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.stderr @@ -0,0 +1,13 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/missing_coroutine_attr_suggestion.rs:6:16 + | +LL | let _ = || yield; + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield; + | ++++++++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/coroutine/nested_coroutine.rs b/tests/ui/coroutine/nested_coroutine.rs index 7ff97abf4bb..2c12ab2adad 100644 --- a/tests/ui/coroutine/nested_coroutine.rs +++ b/tests/ui/coroutine/nested_coroutine.rs @@ -1,13 +1,15 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let _coroutine = || { - let mut sub_coroutine = || { + let _coroutine = #[coroutine] + || { + let mut sub_coroutine = #[coroutine] + || { yield 2; }; diff --git a/tests/ui/coroutine/niche-in-coroutine.rs b/tests/ui/coroutine/niche-in-coroutine.rs index 45b920ab927..117ee9e6f03 100644 --- a/tests/ui/coroutine/niche-in-coroutine.rs +++ b/tests/ui/coroutine/niche-in-coroutine.rs @@ -2,7 +2,7 @@ //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] use std::mem::size_of_val; @@ -10,7 +10,7 @@ fn take<T>(_: T) {} fn main() { let x = false; - let gen1 = || { + let gen1 = #[coroutine] || { yield; take(x); }; diff --git a/tests/ui/coroutine/non-static-is-unpin.rs b/tests/ui/coroutine/non-static-is-unpin.rs index 616a78d5fe2..b28bf197714 100644 --- a/tests/ui/coroutine/non-static-is-unpin.rs +++ b/tests/ui/coroutine/non-static-is-unpin.rs @@ -3,7 +3,7 @@ //@[next] compile-flags: -Znext-solver //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![allow(dropping_copy_types)] use std::marker::PhantomPinned; @@ -14,7 +14,7 @@ fn assert_unpin<G: Unpin>(_: G) { fn main() { // Even though this coroutine holds a `PhantomPinned` in its environment, it // remains `Unpin`. - assert_unpin(|| { + assert_unpin(#[coroutine] || { let pinned = PhantomPinned; yield; drop(pinned); diff --git a/tests/ui/coroutine/not-send-sync.rs b/tests/ui/coroutine/not-send-sync.rs index dd6182c10de..a46dcd14e88 100644 --- a/tests/ui/coroutine/not-send-sync.rs +++ b/tests/ui/coroutine/not-send-sync.rs @@ -1,4 +1,4 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(negative_impls)] struct NotSend; @@ -11,14 +11,14 @@ fn main() { fn assert_sync<T: Sync>(_: T) {} fn assert_send<T: Send>(_: T) {} - assert_sync(|| { + assert_sync(#[coroutine] || { //~^ ERROR: coroutine cannot be shared between threads safely let a = NotSync; yield; drop(a); }); - assert_send(|| { + assert_send(#[coroutine] || { //~^ ERROR: coroutine cannot be sent between threads safely let a = NotSend; yield; diff --git a/tests/ui/coroutine/not-send-sync.stderr b/tests/ui/coroutine/not-send-sync.stderr index 9228340c710..0f9cbdec130 100644 --- a/tests/ui/coroutine/not-send-sync.stderr +++ b/tests/ui/coroutine/not-send-sync.stderr @@ -1,7 +1,7 @@ error: coroutine cannot be shared between threads safely --> $DIR/not-send-sync.rs:14:5 | -LL | / assert_sync(|| { +LL | / assert_sync(#[coroutine] || { LL | | LL | | let a = NotSync; LL | | yield; @@ -9,7 +9,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Sync` | - = help: within `{coroutine@$DIR/not-send-sync.rs:14:17: 14:19}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{coroutine@$DIR/not-send-sync.rs:14:17: 14:19}: Sync` + = help: within `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}: Sync` note: coroutine is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:17:9 | @@ -26,7 +26,7 @@ LL | fn assert_sync<T: Sync>(_: T) {} error: coroutine cannot be sent between threads safely --> $DIR/not-send-sync.rs:21:5 | -LL | / assert_send(|| { +LL | / assert_send(#[coroutine] || { LL | | LL | | let a = NotSend; LL | | yield; @@ -34,7 +34,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/not-send-sync.rs:21:17: 21:19}`, the trait `Send` is not implemented for `NotSend`, which is required by `{coroutine@$DIR/not-send-sync.rs:21:17: 21:19}: Send` + = help: within `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}`, the trait `Send` is not implemented for `NotSend`, which is required by `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/not-send-sync.rs:24:9 | diff --git a/tests/ui/coroutine/overlap-locals.rs b/tests/ui/coroutine/overlap-locals.rs index eea8595ed06..9cfa6e2a76d 100644 --- a/tests/ui/coroutine/overlap-locals.rs +++ b/tests/ui/coroutine/overlap-locals.rs @@ -1,9 +1,10 @@ //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let a = || { + let a = #[coroutine] + || { { let w: i32 = 4; yield; diff --git a/tests/ui/coroutine/panic-drops-resume.rs b/tests/ui/coroutine/panic-drops-resume.rs index 6d026e6edc8..b23666b7885 100644 --- a/tests/ui/coroutine/panic-drops-resume.rs +++ b/tests/ui/coroutine/panic-drops-resume.rs @@ -3,7 +3,7 @@ //@ run-pass //@ needs-unwind -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -21,7 +21,7 @@ impl Drop for Dropper { } fn main() { - let mut gen = |_arg| { + let mut gen = #[coroutine] |_arg| { if true { panic!(); } diff --git a/tests/ui/coroutine/panic-drops.rs b/tests/ui/coroutine/panic-drops.rs index c99abdc7246..8c2cf560f2a 100644 --- a/tests/ui/coroutine/panic-drops.rs +++ b/tests/ui/coroutine/panic-drops.rs @@ -1,8 +1,7 @@ //@ run-pass //@ needs-unwind - -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::panic; @@ -25,7 +24,8 @@ fn bool_true() -> bool { fn main() { let b = B; - let mut foo = || { + let mut foo = #[coroutine] + || { if bool_true() { panic!(); } @@ -34,13 +34,12 @@ fn main() { }; assert_eq!(A.load(Ordering::SeqCst), 0); - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - Pin::new(&mut foo).resume(()) - })); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| Pin::new(&mut foo).resume(()))); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); - let mut foo = || { + let mut foo = #[coroutine] + || { if bool_true() { panic!(); } @@ -49,9 +48,7 @@ fn main() { }; assert_eq!(A.load(Ordering::SeqCst), 1); - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - Pin::new(&mut foo).resume(()) - })); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| Pin::new(&mut foo).resume(()))); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); } diff --git a/tests/ui/coroutine/panic-safe.rs b/tests/ui/coroutine/panic-safe.rs index 89dd09bf520..6b9b4cb33c3 100644 --- a/tests/ui/coroutine/panic-safe.rs +++ b/tests/ui/coroutine/panic-safe.rs @@ -2,14 +2,14 @@ //@ needs-unwind -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; use std::panic; fn main() { - let mut foo = || { + let mut foo = #[coroutine] || { if true { panic!(); } diff --git a/tests/ui/coroutine/parent-expression.rs b/tests/ui/coroutine/parent-expression.rs index 4d40192c07a..0f4d99c8936 100644 --- a/tests/ui/coroutine/parent-expression.rs +++ b/tests/ui/coroutine/parent-expression.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, negative_impls, rustc_attrs)] +#![feature(coroutines, negative_impls, rustc_attrs, stmt_expr_attributes)] macro_rules! type_combinations { ( @@ -14,7 +14,7 @@ macro_rules! type_combinations { // Struct update syntax. This fails because the Client used in the update is considered // dropped *after* the yield. { - let g = move || match drop($name::Client { ..$name::Client::default() }) { + let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { //~^ `significant_drop::Client` which is not `Send` //~| `insignificant_dtor::Client` which is not `Send` //~| `derived_drop::Client` which is not `Send` @@ -29,7 +29,7 @@ macro_rules! type_combinations { // Simple owned value. This works because the Client is considered moved into `drop`, // even though the temporary expression doesn't end until after the yield. { - let g = move || match drop($name::Client::default()) { + let g = #[coroutine] move || match drop($name::Client::default()) { _ => yield, }; assert_send(g); diff --git a/tests/ui/coroutine/parent-expression.stderr b/tests/ui/coroutine/parent-expression.stderr index 5b3737069e6..2d817f1bfd9 100644 --- a/tests/ui/coroutine/parent-expression.stderr +++ b/tests/ui/coroutine/parent-expression.stderr @@ -13,12 +13,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `derived_drop::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later @@ -53,12 +53,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `significant_drop::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later @@ -93,12 +93,12 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:21: 17:28}: Send` + = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send` note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:21:22 | -LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { - | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +LL | let g = #[coroutine] move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` ... LL | _ => yield, | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later diff --git a/tests/ui/coroutine/partial-drop.rs b/tests/ui/coroutine/partial-drop.rs index ba13544712f..9efb551c9c1 100644 --- a/tests/ui/coroutine/partial-drop.rs +++ b/tests/ui/coroutine/partial-drop.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(negative_impls, coroutines)] +#![feature(negative_impls, coroutines, stmt_expr_attributes)] struct Foo; impl !Send for Foo {} @@ -10,25 +10,34 @@ struct Bar { } fn main() { - assert_send(|| { - let guard = Bar { foo: Foo, x: 42 }; - drop(guard.foo); - yield; - }); + assert_send( + #[coroutine] + || { + let guard = Bar { foo: Foo, x: 42 }; + drop(guard.foo); + yield; + }, + ); - assert_send(|| { - let mut guard = Bar { foo: Foo, x: 42 }; - drop(guard); - guard = Bar { foo: Foo, x: 23 }; - yield; - }); + assert_send( + #[coroutine] + || { + let mut guard = Bar { foo: Foo, x: 42 }; + drop(guard); + guard = Bar { foo: Foo, x: 23 }; + yield; + }, + ); - assert_send(|| { - let guard = Bar { foo: Foo, x: 42 }; - let Bar { foo, x } = guard; - drop(foo); - yield; - }); + assert_send( + #[coroutine] + || { + let guard = Bar { foo: Foo, x: 42 }; + let Bar { foo, x } = guard; + drop(foo); + yield; + }, + ); } fn assert_send<T: Send>(_: T) {} diff --git a/tests/ui/coroutine/partial-initialization-across-yield.rs b/tests/ui/coroutine/partial-initialization-across-yield.rs index 75ad5a22804..ab6f9c5b1e9 100644 --- a/tests/ui/coroutine/partial-initialization-across-yield.rs +++ b/tests/ui/coroutine/partial-initialization-across-yield.rs @@ -1,13 +1,13 @@ // Test that we don't allow yielding from a coroutine while a local is partially // initialized. -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] struct S { x: i32, y: i32 } struct T(i32, i32); fn test_tuple() { - let _ = || { + let _ = #[coroutine] || { let mut t: (i32, i32); t.0 = 42; //~ ERROR E0381 yield; @@ -17,7 +17,7 @@ fn test_tuple() { } fn test_tuple_struct() { - let _ = || { + let _ = #[coroutine] || { let mut t: T; t.0 = 42; //~ ERROR E0381 yield; @@ -27,7 +27,7 @@ fn test_tuple_struct() { } fn test_struct() { - let _ = || { + let _ = #[coroutine] || { let mut t: S; t.x = 42; //~ ERROR E0381 yield; diff --git a/tests/ui/coroutine/pattern-borrow.rs b/tests/ui/coroutine/pattern-borrow.rs index 76084433d47..46547504abc 100644 --- a/tests/ui/coroutine/pattern-borrow.rs +++ b/tests/ui/coroutine/pattern-borrow.rs @@ -5,7 +5,7 @@ enum Test { A(i32), B, } fn main() { } fn fun(test: Test) { - move || { + #[coroutine] move || { if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when coroutine yields yield (); _a.use_ref(); diff --git a/tests/ui/coroutine/pin-box-coroutine.rs b/tests/ui/coroutine/pin-box-coroutine.rs index 1ee6393d1d8..d030f3ef214 100644 --- a/tests/ui/coroutine/pin-box-coroutine.rs +++ b/tests/ui/coroutine/pin-box-coroutine.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; @@ -8,6 +8,6 @@ fn assert_coroutine<G: Coroutine>(_: G) { } fn main() { - assert_coroutine(static || yield); - assert_coroutine(Box::pin(static || yield)); + assert_coroutine(#[coroutine] static || yield); + assert_coroutine(Box::pin(#[coroutine] static || yield)); } diff --git a/tests/ui/coroutine/polymorphize-args.rs b/tests/ui/coroutine/polymorphize-args.rs index 21aa3c7aafd..5123bf412b5 100644 --- a/tests/ui/coroutine/polymorphize-args.rs +++ b/tests/ui/coroutine/polymorphize-args.rs @@ -1,14 +1,15 @@ //@ compile-flags: -Zpolymorphize=on //@ build-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; use std::thread; fn main() { - let mut foo = || yield; + let mut foo = #[coroutine] + || yield; thread::spawn(move || match Pin::new(&mut foo).resume(()) { s => panic!("bad state: {:?}", s), }) diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-1.rs b/tests/ui/coroutine/print/coroutine-print-verbose-1.rs index 73106328618..dc0165c9194 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-1.rs +++ b/tests/ui/coroutine/print/coroutine-print-verbose-1.rs @@ -2,7 +2,7 @@ // Same as: tests/ui/coroutine/issue-68112.stderr -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::{ cell::RefCell, @@ -30,7 +30,7 @@ fn make_non_send_coroutine() -> impl Coroutine<Return = Arc<RefCell<i32>>> { } fn test1() { - let send_gen = || { + let send_gen = #[coroutine] || { let _non_send_gen = make_non_send_coroutine(); yield; }; @@ -39,7 +39,7 @@ fn test1() { } pub fn make_gen2<T>(t: T) -> impl Coroutine<Return = T> { - || { + #[coroutine] || { yield; t } @@ -49,7 +49,7 @@ fn make_non_send_coroutine2() -> impl Coroutine<Return = Arc<RefCell<i32>>> { } fn test2() { - let send_gen = || { + let send_gen = #[coroutine] || { let _non_send_gen = make_non_send_coroutine2(); yield; }; diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr index 37db83d57f7..934ab08cf17 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr @@ -29,10 +29,10 @@ LL | require_send(send_gen); = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this coroutine - --> $DIR/coroutine-print-verbose-1.rs:42:5 + --> $DIR/coroutine-print-verbose-1.rs:42:18 | -LL | || { - | ^^ +LL | #[coroutine] || { + | ^^ note: required because it appears within the type `Opaque(DefId(0:35 ~ coroutine_print_verbose_1[75fb]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])` --> $DIR/coroutine-print-verbose-1.rs:41:30 | @@ -44,10 +44,10 @@ note: required because it appears within the type `Opaque(DefId(0:36 ~ coroutine LL | fn make_non_send_coroutine2() -> impl Coroutine<Return = Arc<RefCell<i32>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it's used within this coroutine - --> $DIR/coroutine-print-verbose-1.rs:52:20 + --> $DIR/coroutine-print-verbose-1.rs:52:33 | -LL | let send_gen = || { - | ^^ +LL | let send_gen = #[coroutine] || { + | ^^ note: required by a bound in `require_send` --> $DIR/coroutine-print-verbose-1.rs:26:25 | diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.rs b/tests/ui/coroutine/print/coroutine-print-verbose-2.rs index f9ea68a8cd9..ef7199cafdd 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.rs +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.rs @@ -1,7 +1,7 @@ //@ compile-flags: -Zverbose-internals // Same as test/ui/coroutine/not-send-sync.rs -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(negative_impls)] struct NotSend; @@ -14,14 +14,14 @@ fn main() { fn assert_sync<T: Sync>(_: T) {} fn assert_send<T: Send>(_: T) {} - assert_sync(|| { + assert_sync(#[coroutine] || { //~^ ERROR: coroutine cannot be shared between threads safely let a = NotSync; yield; drop(a); }); - assert_send(|| { + assert_send(#[coroutine] || { //~^ ERROR: coroutine cannot be sent between threads safely let a = NotSend; yield; diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr index 26c9c27743c..0de53d9e1d7 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr @@ -1,7 +1,7 @@ error: coroutine cannot be shared between threads safely --> $DIR/coroutine-print-verbose-2.rs:17:5 | -LL | / assert_sync(|| { +LL | / assert_sync(#[coroutine] || { LL | | LL | | let a = NotSync; LL | | yield; @@ -26,7 +26,7 @@ LL | fn assert_sync<T: Sync>(_: T) {} error: coroutine cannot be sent between threads safely --> $DIR/coroutine-print-verbose-2.rs:24:5 | -LL | / assert_send(|| { +LL | / assert_send(#[coroutine] || { LL | | LL | | let a = NotSend; LL | | yield; diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.rs b/tests/ui/coroutine/print/coroutine-print-verbose-3.rs index be6dbad9e1c..5dd15fc1b95 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.rs +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.rs @@ -1,12 +1,13 @@ //@ compile-flags: -Zverbose-internals -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] fn main() { let x = "Type mismatch test"; - let coroutine :() = || { - //~^ ERROR mismatched types + let coroutine: () = #[coroutine] + || { + //~^ ERROR mismatched types yield 1i32; - return x + return x; }; } diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr index e2973cde6d3..dce45aeae56 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr @@ -1,13 +1,12 @@ error[E0308]: mismatched types - --> $DIR/coroutine-print-verbose-3.rs:7:25 + --> $DIR/coroutine-print-verbose-3.rs:8:5 | -LL | let coroutine :() = || { - | ____________________--___^ - | | | - | | expected due to this +LL | let coroutine: () = #[coroutine] + | -- expected due to this +LL | / || { LL | | LL | | yield 1i32; -LL | | return x +LL | | return x; LL | | }; | |_____^ expected `()`, found coroutine | diff --git a/tests/ui/coroutine/reborrow-mut-upvar.rs b/tests/ui/coroutine/reborrow-mut-upvar.rs index e1f6211baeb..716781e365c 100644 --- a/tests/ui/coroutine/reborrow-mut-upvar.rs +++ b/tests/ui/coroutine/reborrow-mut-upvar.rs @@ -3,7 +3,7 @@ #![feature(coroutines)] fn _run(bar: &mut i32) { - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used { let _baz = &*bar; yield; diff --git a/tests/ui/coroutine/reborrow-mut-upvar.stderr b/tests/ui/coroutine/reborrow-mut-upvar.stderr index 5b614ac4be8..a05e84c5f3e 100644 --- a/tests/ui/coroutine/reborrow-mut-upvar.stderr +++ b/tests/ui/coroutine/reborrow-mut-upvar.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/reborrow-mut-upvar.rs:6:5 + --> $DIR/reborrow-mut-upvar.rs:6:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | { LL | | let _baz = &*bar; LL | | yield; diff --git a/tests/ui/coroutine/ref-escapes-but-not-over-yield.rs b/tests/ui/coroutine/ref-escapes-but-not-over-yield.rs index a9c13188ff3..0f9c56786da 100644 --- a/tests/ui/coroutine/ref-escapes-but-not-over-yield.rs +++ b/tests/ui/coroutine/ref-escapes-but-not-over-yield.rs @@ -1,16 +1,17 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn foo(x: &i32) { // In this case, a reference to `b` escapes the coroutine, but not // because of a yield. We see that there is no yield in the scope of // `b` and give the more generic error message. let mut a = &3; - let mut b = move || { - yield(); + let mut b = #[coroutine] + move || { + yield (); let b = 5; a = &b; //~^ ERROR borrowed data escapes outside of coroutine }; } -fn main() { } +fn main() {} diff --git a/tests/ui/coroutine/ref-escapes-but-not-over-yield.stderr b/tests/ui/coroutine/ref-escapes-but-not-over-yield.stderr index 8811faf2fad..6fa7082c0b8 100644 --- a/tests/ui/coroutine/ref-escapes-but-not-over-yield.stderr +++ b/tests/ui/coroutine/ref-escapes-but-not-over-yield.stderr @@ -1,5 +1,5 @@ error[E0521]: borrowed data escapes outside of coroutine - --> $DIR/ref-escapes-but-not-over-yield.rs:11:9 + --> $DIR/ref-escapes-but-not-over-yield.rs:12:9 | LL | let mut a = &3; | ----- `a` declared here, outside of the coroutine body diff --git a/tests/ui/coroutine/ref-upvar-not-send.rs b/tests/ui/coroutine/ref-upvar-not-send.rs index 487fdeea2da..89bb5e5495f 100644 --- a/tests/ui/coroutine/ref-upvar-not-send.rs +++ b/tests/ui/coroutine/ref-upvar-not-send.rs @@ -1,7 +1,7 @@ // For `Send` coroutines, suggest a `T: Sync` requirement for `&T` upvars, // and suggest a `T: Send` requirement for `&mut T` upvars. -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn assert_send<T: Send>(_: T) {} //~^ NOTE required by a bound in `assert_send` @@ -12,7 +12,7 @@ fn assert_send<T: Send>(_: T) {} fn main() { let x: &*mut () = &std::ptr::null_mut(); let y: &mut *mut () = &mut std::ptr::null_mut(); - assert_send(move || { + assert_send(#[coroutine] move || { //~^ ERROR coroutine cannot be sent between threads safely //~| NOTE coroutine is not `Send` yield; @@ -20,7 +20,7 @@ fn main() { }); //~^^ NOTE captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` //~| NOTE has type `&*mut ()` which is not `Send`, because `*mut ()` is not `Sync` - assert_send(move || { + assert_send(#[coroutine] move || { //~^ ERROR coroutine cannot be sent between threads safely //~| NOTE coroutine is not `Send` yield; diff --git a/tests/ui/coroutine/ref-upvar-not-send.stderr b/tests/ui/coroutine/ref-upvar-not-send.stderr index 0f91bcf4053..4c7deab3f4c 100644 --- a/tests/ui/coroutine/ref-upvar-not-send.stderr +++ b/tests/ui/coroutine/ref-upvar-not-send.stderr @@ -1,8 +1,8 @@ error: coroutine cannot be sent between threads safely - --> $DIR/ref-upvar-not-send.rs:15:17 + --> $DIR/ref-upvar-not-send.rs:15:30 | -LL | assert_send(move || { - | _________________^ +LL | assert_send(#[coroutine] move || { + | ______________________________^ LL | | LL | | LL | | yield; @@ -10,7 +10,7 @@ LL | | let _x = x; LL | | }); | |_____^ coroutine is not `Send` | - = help: the trait `Sync` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:15:17: 15:24}: Send` + = help: the trait `Sync` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:15:30: 15:37}: Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` --> $DIR/ref-upvar-not-send.rs:19:18 | @@ -23,10 +23,10 @@ LL | fn assert_send<T: Send>(_: T) {} | ^^^^ required by this bound in `assert_send` error: coroutine cannot be sent between threads safely - --> $DIR/ref-upvar-not-send.rs:23:17 + --> $DIR/ref-upvar-not-send.rs:23:30 | -LL | assert_send(move || { - | _________________^ +LL | assert_send(#[coroutine] move || { + | ______________________________^ LL | | LL | | LL | | yield; @@ -34,7 +34,7 @@ LL | | let _y = y; LL | | }); | |_____^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:17: 23:24}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:23:17: 23:24}: Send` + = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}: Send` note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send` --> $DIR/ref-upvar-not-send.rs:27:18 | diff --git a/tests/ui/coroutine/reinit-in-match-guard.rs b/tests/ui/coroutine/reinit-in-match-guard.rs index 4a584204773..0a97d9fbcb2 100644 --- a/tests/ui/coroutine/reinit-in-match-guard.rs +++ b/tests/ui/coroutine/reinit-in-match-guard.rs @@ -1,11 +1,11 @@ //@ build-pass -#![feature(coroutines)] - +#![feature(coroutines, stmt_expr_attributes)] #![allow(unused_assignments, dead_code)] fn main() { - let _ = || { + let _ = #[coroutine] + || { let mut x = vec![22_usize]; std::mem::drop(x); match y() { diff --git a/tests/ui/coroutine/resume-after-return.rs b/tests/ui/coroutine/resume-after-return.rs index 81f86de641f..7028e1e81e5 100644 --- a/tests/ui/coroutine/resume-after-return.rs +++ b/tests/ui/coroutine/resume-after-return.rs @@ -1,17 +1,17 @@ //@ run-pass //@ needs-unwind +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] -#![feature(coroutines, coroutine_trait)] - -use std::ops::{CoroutineState, Coroutine}; -use std::pin::Pin; +use std::ops::{Coroutine, CoroutineState}; use std::panic; +use std::pin::Pin; fn main() { - let mut foo = || { + let mut foo = #[coroutine] + || { if true { - return + return; } yield; }; diff --git a/tests/ui/coroutine/resume-arg-late-bound.rs b/tests/ui/coroutine/resume-arg-late-bound.rs index 3c2ab41047e..e84184da631 100644 --- a/tests/ui/coroutine/resume-arg-late-bound.rs +++ b/tests/ui/coroutine/resume-arg-late-bound.rs @@ -1,14 +1,14 @@ //! Tests that we cannot produce a coroutine that accepts a resume argument //! with any lifetime and then stores it across a `yield`. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; fn test(a: impl for<'a> Coroutine<&'a mut bool>) {} fn main() { - let gen = |arg: &mut bool| { + let gen = #[coroutine] |arg: &mut bool| { yield (); *arg = true; }; diff --git a/tests/ui/coroutine/resume-arg-late-bound.stderr b/tests/ui/coroutine/resume-arg-late-bound.stderr index 4a4ee08c529..646abaf4f7b 100644 --- a/tests/ui/coroutine/resume-arg-late-bound.stderr +++ b/tests/ui/coroutine/resume-arg-late-bound.stderr @@ -4,7 +4,7 @@ error: implementation of `Coroutine` is not general enough LL | test(gen); | ^^^^^^^^^ implementation of `Coroutine` is not general enough | - = note: `{coroutine@$DIR/resume-arg-late-bound.rs:11:15: 11:31}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`... + = note: `{coroutine@$DIR/resume-arg-late-bound.rs:11:28: 11:44}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`... = note: ...but it actually implements `Coroutine<&'2 mut bool>`, for some specific lifetime `'2` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/resume-arg-size.rs b/tests/ui/coroutine/resume-arg-size.rs index 81e96975c98..59740a28f42 100644 --- a/tests/ui/coroutine/resume-arg-size.rs +++ b/tests/ui/coroutine/resume-arg-size.rs @@ -1,4 +1,4 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![allow(dropping_copy_types)] //@ run-pass @@ -7,7 +7,8 @@ use std::mem::size_of_val; fn main() { // Coroutine taking a `Copy`able resume arg. - let gen_copy = |mut x: usize| { + let gen_copy = #[coroutine] + |mut x: usize| { loop { drop(x); x = yield; @@ -15,7 +16,8 @@ fn main() { }; // Coroutine taking a non-`Copy` resume arg. - let gen_move = |mut x: Box<usize>| { + let gen_move = #[coroutine] + |mut x: Box<usize>| { loop { drop(x); x = yield; diff --git a/tests/ui/coroutine/resume-live-across-yield.rs b/tests/ui/coroutine/resume-live-across-yield.rs index 45851411daa..b67619ee70f 100644 --- a/tests/ui/coroutine/resume-live-across-yield.rs +++ b/tests/ui/coroutine/resume-live-across-yield.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -18,7 +18,8 @@ impl Drop for Dropper { } fn main() { - let mut g = |mut _d| { + let mut g = #[coroutine] + |mut _d| { _d = yield; _d }; diff --git a/tests/ui/coroutine/retain-resume-ref.rs b/tests/ui/coroutine/retain-resume-ref.rs index c9f995ab0cf..6e688c33979 100644 --- a/tests/ui/coroutine/retain-resume-ref.rs +++ b/tests/ui/coroutine/retain-resume-ref.rs @@ -1,6 +1,6 @@ //! This test ensures that a mutable reference cannot be passed as a resume argument twice. -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::marker::Unpin; use std::ops::{ @@ -12,7 +12,8 @@ use std::pin::Pin; fn main() { let mut thing = String::from("hello"); - let mut gen = |r| { + let mut gen = #[coroutine] + |r| { if false { yield r; } diff --git a/tests/ui/coroutine/retain-resume-ref.stderr b/tests/ui/coroutine/retain-resume-ref.stderr index eb8b78df6c9..e23023c6e23 100644 --- a/tests/ui/coroutine/retain-resume-ref.stderr +++ b/tests/ui/coroutine/retain-resume-ref.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `thing` as mutable more than once at a time - --> $DIR/retain-resume-ref.rs:23:25 + --> $DIR/retain-resume-ref.rs:24:25 | LL | gen.as_mut().resume(&mut thing); | ---------- first mutable borrow occurs here diff --git a/tests/ui/coroutine/size-moved-locals.rs b/tests/ui/coroutine/size-moved-locals.rs index eb5210087a0..0f800de8454 100644 --- a/tests/ui/coroutine/size-moved-locals.rs +++ b/tests/ui/coroutine/size-moved-locals.rs @@ -24,6 +24,7 @@ impl Drop for Foo { } fn move_before_yield() -> impl Coroutine<Yield = (), Return = ()> { + #[coroutine] static || { let first = Foo([0; FOO_SIZE]); let _second = first; @@ -35,6 +36,7 @@ fn move_before_yield() -> impl Coroutine<Yield = (), Return = ()> { fn noop() {} fn move_before_yield_with_noop() -> impl Coroutine<Yield = (), Return = ()> { + #[coroutine] static || { let first = Foo([0; FOO_SIZE]); noop(); @@ -47,6 +49,7 @@ fn move_before_yield_with_noop() -> impl Coroutine<Yield = (), Return = ()> { // Today we don't have NRVO (we allocate space for both `first` and `second`,) // but we can overlap `first` with `_third`. fn overlap_move_points() -> impl Coroutine<Yield = (), Return = ()> { + #[coroutine] static || { let first = Foo([0; FOO_SIZE]); yield; @@ -58,6 +61,7 @@ fn overlap_move_points() -> impl Coroutine<Yield = (), Return = ()> { } fn overlap_x_and_y() -> impl Coroutine<Yield = (), Return = ()> { + #[coroutine] static || { let x = Foo([0; FOO_SIZE]); yield; diff --git a/tests/ui/coroutine/sized-yield.rs b/tests/ui/coroutine/sized-yield.rs index 1368c88b522..a4c91fafe6c 100644 --- a/tests/ui/coroutine/sized-yield.rs +++ b/tests/ui/coroutine/sized-yield.rs @@ -1,11 +1,12 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; fn main() { let s = String::from("foo"); - let mut gen = move || { + let mut gen = #[coroutine] + move || { //~^ ERROR the size for values of type yield s[..]; }; diff --git a/tests/ui/coroutine/sized-yield.stderr b/tests/ui/coroutine/sized-yield.stderr index 4e8dc13201d..5d5dd6803c8 100644 --- a/tests/ui/coroutine/sized-yield.stderr +++ b/tests/ui/coroutine/sized-yield.stderr @@ -1,8 +1,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/sized-yield.rs:8:19 + --> $DIR/sized-yield.rs:9:5 | -LL | let mut gen = move || { - | ___________________^ +LL | / move || { LL | | LL | | yield s[..]; LL | | }; @@ -12,7 +11,7 @@ LL | | }; = note: the yield type of a coroutine must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/sized-yield.rs:12:24 + --> $DIR/sized-yield.rs:13:24 | LL | Pin::new(&mut gen).resume(()); | ^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/coroutine/smoke-resume-args.rs b/tests/ui/coroutine/smoke-resume-args.rs index 7d20cd2293d..209c4814001 100644 --- a/tests/ui/coroutine/smoke-resume-args.rs +++ b/tests/ui/coroutine/smoke-resume-args.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::fmt::Debug; use std::ops::{ @@ -50,7 +50,7 @@ fn expect_drops<T>(expected_drops: usize, f: impl FnOnce() -> T) -> T { fn main() { drain( - &mut |mut b| { + &mut #[coroutine] |mut b| { while b != 0 { b = yield (b + 1); } @@ -59,21 +59,24 @@ fn main() { vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))], ); - expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))])); + expect_drops(2, || drain(&mut #[coroutine] |a| yield a, vec![(DropMe, Yielded(DropMe))])); expect_drops(6, || { drain( - &mut |a| yield yield a, + &mut #[coroutine] |a| yield yield a, vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))], ) }); #[allow(unreachable_code)] - expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))])); + expect_drops(2, || drain( + &mut #[coroutine] |a| yield return a, + vec![(DropMe, Complete(DropMe))] + )); expect_drops(2, || { drain( - &mut |a: DropMe| { + &mut #[coroutine] |a: DropMe| { if false { yield () } else { a } }, vec![(DropMe, Complete(DropMe))], @@ -83,7 +86,7 @@ fn main() { expect_drops(4, || { drain( #[allow(unused_assignments, unused_variables)] - &mut |mut a: DropMe| { + &mut #[coroutine] |mut a: DropMe| { a = yield; a = yield; a = yield; diff --git a/tests/ui/coroutine/smoke.rs b/tests/ui/coroutine/smoke.rs index 17d98a52a1c..bfb183fde93 100644 --- a/tests/ui/coroutine/smoke.rs +++ b/tests/ui/coroutine/smoke.rs @@ -6,7 +6,7 @@ //@ needs-threads //@ compile-flags: --test -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{CoroutineState, Coroutine}; use std::pin::Pin; @@ -14,7 +14,7 @@ use std::thread; #[test] fn simple() { - let mut foo = || { + let mut foo = #[coroutine] || { if false { yield; } @@ -29,7 +29,7 @@ fn simple() { #[test] fn return_capture() { let a = String::from("foo"); - let mut foo = || { + let mut foo = #[coroutine] || { if false { yield; } @@ -44,7 +44,7 @@ fn return_capture() { #[test] fn simple_yield() { - let mut foo = || { + let mut foo = #[coroutine] || { yield; }; @@ -61,7 +61,7 @@ fn simple_yield() { #[test] fn yield_capture() { let b = String::from("foo"); - let mut foo = || { + let mut foo = #[coroutine] || { yield b; }; @@ -77,7 +77,7 @@ fn yield_capture() { #[test] fn simple_yield_value() { - let mut foo = || { + let mut foo = #[coroutine] || { yield String::from("bar"); return String::from("foo") }; @@ -95,7 +95,7 @@ fn simple_yield_value() { #[test] fn return_after_yield() { let a = String::from("foo"); - let mut foo = || { + let mut foo = #[coroutine] || { yield; return a }; @@ -112,34 +112,34 @@ fn return_after_yield() { #[test] fn send_and_sync() { - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield }); - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield String::from("foo"); }); - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield; return String::from("foo"); }); let a = 3; - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield a; return }); let a = 3; - assert_send_sync(move || { + assert_send_sync(#[coroutine] move || { yield a; return }); let a = String::from("a"); - assert_send_sync(|| { + assert_send_sync(#[coroutine] || { yield ; drop(a); return }); let a = String::from("a"); - assert_send_sync(move || { + assert_send_sync(#[coroutine] move || { yield ; drop(a); return @@ -150,7 +150,7 @@ fn send_and_sync() { #[test] fn send_over_threads() { - let mut foo = || { yield }; + let mut foo = #[coroutine] || { yield }; thread::spawn(move || { match Pin::new(&mut foo).resume(()) { CoroutineState::Yielded(()) => {} @@ -163,7 +163,7 @@ fn send_over_threads() { }).join().unwrap(); let a = String::from("a"); - let mut foo = || { yield a }; + let mut foo = #[coroutine] || { yield a }; thread::spawn(move || { match Pin::new(&mut foo).resume(()) { CoroutineState::Yielded(ref s) if *s == "a" => {} diff --git a/tests/ui/coroutine/static-coroutine.rs b/tests/ui/coroutine/static-coroutine.rs index 9beaef3e4de..eba6336d342 100644 --- a/tests/ui/coroutine/static-coroutine.rs +++ b/tests/ui/coroutine/static-coroutine.rs @@ -1,12 +1,13 @@ //@ run-pass -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] -use std::pin::Pin; use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; fn main() { - let mut coroutine = static || { + let mut coroutine = #[coroutine] + static || { let a = true; let b = &a; yield; diff --git a/tests/ui/coroutine/static-mut-reference-across-yield.rs b/tests/ui/coroutine/static-mut-reference-across-yield.rs index 0d8042ed852..40d5fdf2d57 100644 --- a/tests/ui/coroutine/static-mut-reference-across-yield.rs +++ b/tests/ui/coroutine/static-mut-reference-across-yield.rs @@ -1,6 +1,6 @@ //@ build-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; @@ -8,13 +8,15 @@ fn is_send_sync<T: Send + Sync>(_: T) {} fn main() { unsafe { - let gen_index = static || { + let gen_index = #[coroutine] + static || { let u = A[{ yield; 1 }]; }; - let gen_match = static || match A { + let gen_match = #[coroutine] + static || match A { i if { yield; true diff --git a/tests/ui/coroutine/static-not-unpin.current.stderr b/tests/ui/coroutine/static-not-unpin.current.stderr index 518abdd62c7..7d6260ac569 100644 --- a/tests/ui/coroutine/static-not-unpin.current.stderr +++ b/tests/ui/coroutine/static-not-unpin.current.stderr @@ -1,8 +1,8 @@ -error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:25: 15:34}` cannot be unpinned +error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` cannot be unpinned --> $DIR/static-not-unpin.rs:18:18 | LL | assert_unpin(coroutine); - | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:25: 15:34}` + | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` | | | required by a bound introduced by this call | @@ -11,7 +11,7 @@ LL | assert_unpin(coroutine); note: required by a bound in `assert_unpin` --> $DIR/static-not-unpin.rs:11:20 | -LL | fn assert_unpin<T: Unpin>(_: T) { +LL | fn assert_unpin<T: Unpin>(_: T) {} | ^^^^^ required by this bound in `assert_unpin` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/static-not-unpin.next.stderr b/tests/ui/coroutine/static-not-unpin.next.stderr index 518abdd62c7..7d6260ac569 100644 --- a/tests/ui/coroutine/static-not-unpin.next.stderr +++ b/tests/ui/coroutine/static-not-unpin.next.stderr @@ -1,8 +1,8 @@ -error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:25: 15:34}` cannot be unpinned +error[E0277]: `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` cannot be unpinned --> $DIR/static-not-unpin.rs:18:18 | LL | assert_unpin(coroutine); - | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:25: 15:34}` + | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/static-not-unpin.rs:15:5: 15:14}` | | | required by a bound introduced by this call | @@ -11,7 +11,7 @@ LL | assert_unpin(coroutine); note: required by a bound in `assert_unpin` --> $DIR/static-not-unpin.rs:11:20 | -LL | fn assert_unpin<T: Unpin>(_: T) { +LL | fn assert_unpin<T: Unpin>(_: T) {} | ^^^^^ required by this bound in `assert_unpin` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/static-not-unpin.rs b/tests/ui/coroutine/static-not-unpin.rs index 3704cca7729..2bc25e3796d 100644 --- a/tests/ui/coroutine/static-not-unpin.rs +++ b/tests/ui/coroutine/static-not-unpin.rs @@ -2,17 +2,17 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] //@ normalize-stderr-test "std::pin::Unpin" -> "std::marker::Unpin" use std::marker::Unpin; -fn assert_unpin<T: Unpin>(_: T) { -} +fn assert_unpin<T: Unpin>(_: T) {} fn main() { - let mut coroutine = static || { + let mut coroutine = #[coroutine] + static || { yield; }; assert_unpin(coroutine); //~ ERROR E0277 diff --git a/tests/ui/coroutine/static-reference-across-yield.rs b/tests/ui/coroutine/static-reference-across-yield.rs index cf19ccb54d5..e7ff658ebf6 100644 --- a/tests/ui/coroutine/static-reference-across-yield.rs +++ b/tests/ui/coroutine/static-reference-across-yield.rs @@ -4,10 +4,10 @@ static A: [i32; 5] = [1, 2, 3, 4, 5]; fn main() { - static || { + #[coroutine] static || { let u = A[{yield; 1}]; }; - static || { + #[coroutine] static || { match A { i if { yield; true } => (), _ => (), diff --git a/tests/ui/coroutine/too-live-local-in-immovable-gen.rs b/tests/ui/coroutine/too-live-local-in-immovable-gen.rs index 382e7ff3814..1c689ef7cef 100644 --- a/tests/ui/coroutine/too-live-local-in-immovable-gen.rs +++ b/tests/ui/coroutine/too-live-local-in-immovable-gen.rs @@ -5,7 +5,7 @@ fn main() { unsafe { - static move || { //~ WARN unused coroutine that must be used + #[coroutine] static move || { //~ WARN unused coroutine that must be used // Tests that the coroutine transformation finds out that `a` is not live // during the yield expression. Type checking will also compute liveness // and it should also find out that `a` is not live. diff --git a/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr b/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr index 4a67dbe71e1..48df5c5beac 100644 --- a/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr +++ b/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/too-live-local-in-immovable-gen.rs:8:9 + --> $DIR/too-live-local-in-immovable-gen.rs:8:22 | -LL | / static move || { +LL | #[coroutine] static move || { + | ______________________^ LL | | // Tests that the coroutine transformation finds out that `a` is not live LL | | // during the yield expression. Type checking will also compute liveness LL | | // and it should also find out that `a` is not live. diff --git a/tests/ui/coroutine/too-many-parameters.rs b/tests/ui/coroutine/too-many-parameters.rs index 377d80c7b22..3baaf062347 100644 --- a/tests/ui/coroutine/too-many-parameters.rs +++ b/tests/ui/coroutine/too-many-parameters.rs @@ -1,6 +1,7 @@ #![feature(coroutines)] fn main() { + #[coroutine] |(), ()| { //~^ error: too many parameters for a coroutine yield; diff --git a/tests/ui/coroutine/too-many-parameters.stderr b/tests/ui/coroutine/too-many-parameters.stderr index c0917c7225b..45dad8e349e 100644 --- a/tests/ui/coroutine/too-many-parameters.stderr +++ b/tests/ui/coroutine/too-many-parameters.stderr @@ -1,5 +1,5 @@ error[E0628]: too many parameters for a coroutine (expected 0 or 1 parameters) - --> $DIR/too-many-parameters.rs:4:5 + --> $DIR/too-many-parameters.rs:5:5 | LL | |(), ()| { | ^^^^^^^^ diff --git a/tests/ui/coroutine/type-mismatch-error.rs b/tests/ui/coroutine/type-mismatch-error.rs index 0d04c21484c..ee4e27c20da 100644 --- a/tests/ui/coroutine/type-mismatch-error.rs +++ b/tests/ui/coroutine/type-mismatch-error.rs @@ -1,7 +1,7 @@ //! Test that we get the expected type mismatch error instead of "closure is expected to take 0 //! arguments" (which got introduced after implementing resume arguments). -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; @@ -9,6 +9,7 @@ fn f<G: Coroutine>(_: G, _: G::Return) {} fn main() { f( + #[coroutine] |a: u8| { if false { yield (); diff --git a/tests/ui/coroutine/type-mismatch-error.stderr b/tests/ui/coroutine/type-mismatch-error.stderr index 737d9afdd79..f10c30e2590 100644 --- a/tests/ui/coroutine/type-mismatch-error.stderr +++ b/tests/ui/coroutine/type-mismatch-error.stderr @@ -1,5 +1,5 @@ error[E0308]: `if` and `else` have incompatible types - --> $DIR/type-mismatch-error.rs:16:17 + --> $DIR/type-mismatch-error.rs:17:17 | LL | / if false { LL | | yield (); diff --git a/tests/ui/coroutine/type-mismatch-signature-deduction.rs b/tests/ui/coroutine/type-mismatch-signature-deduction.rs index d4ca622e80f..5b04b3efaaa 100644 --- a/tests/ui/coroutine/type-mismatch-signature-deduction.rs +++ b/tests/ui/coroutine/type-mismatch-signature-deduction.rs @@ -4,6 +4,7 @@ use std::ops::Coroutine; fn foo() -> impl Coroutine<Return = i32> { //~^ ERROR type mismatch + #[coroutine] || { if false { return Ok(6); diff --git a/tests/ui/coroutine/type-mismatch-signature-deduction.stderr b/tests/ui/coroutine/type-mismatch-signature-deduction.stderr index f26e30a8e74..08927196037 100644 --- a/tests/ui/coroutine/type-mismatch-signature-deduction.stderr +++ b/tests/ui/coroutine/type-mismatch-signature-deduction.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/type-mismatch-signature-deduction.rs:14:9 + --> $DIR/type-mismatch-signature-deduction.rs:15:9 | LL | 5 | ^ expected `Result<{integer}, _>`, found integer @@ -7,7 +7,7 @@ LL | 5 = note: expected enum `Result<{integer}, _>` found type `{integer}` note: return type inferred to be `Result<{integer}, _>` here - --> $DIR/type-mismatch-signature-deduction.rs:9:20 + --> $DIR/type-mismatch-signature-deduction.rs:10:20 | LL | return Ok(6); | ^^^^^ @@ -18,7 +18,7 @@ LL | Ok(5) LL | Err(5) | ++++ + -error[E0271]: type mismatch resolving `<{coroutine@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7} as Coroutine>::Return == i32` +error[E0271]: type mismatch resolving `<{coroutine@$DIR/type-mismatch-signature-deduction.rs:8:5: 8:7} as Coroutine>::Return == i32` --> $DIR/type-mismatch-signature-deduction.rs:5:13 | LL | fn foo() -> impl Coroutine<Return = i32> { diff --git a/tests/ui/coroutine/uninhabited-field.rs b/tests/ui/coroutine/uninhabited-field.rs index 79776d653b1..d6ada07ce0c 100644 --- a/tests/ui/coroutine/uninhabited-field.rs +++ b/tests/ui/coroutine/uninhabited-field.rs @@ -3,7 +3,7 @@ #![allow(unused)] #![feature(assert_matches)] #![feature(coroutine_trait)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(never_type)] use std::assert_matches::assert_matches; use std::ops::Coroutine; @@ -13,7 +13,7 @@ use std::pin::Pin; fn conjure<T>() -> T { loop {} } fn run<T>(x: bool, y: bool) { - let mut c = || { + let mut c = #[coroutine] || { if x { let a : T; if y { diff --git a/tests/ui/coroutine/unsized-capture-across-yield.rs b/tests/ui/coroutine/unsized-capture-across-yield.rs index ef9cbc1d677..c86b1823aaf 100644 --- a/tests/ui/coroutine/unsized-capture-across-yield.rs +++ b/tests/ui/coroutine/unsized-capture-across-yield.rs @@ -7,6 +7,7 @@ use std::ops::Coroutine; fn capture() -> impl Coroutine { let b: [u8] = *(Box::new([]) as Box<[u8]>); + #[coroutine] move || { println!("{:?}", &b); //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui/coroutine/unsized-capture-across-yield.stderr b/tests/ui/coroutine/unsized-capture-across-yield.stderr index 436f0901a97..03551f1bbff 100644 --- a/tests/ui/coroutine/unsized-capture-across-yield.stderr +++ b/tests/ui/coroutine/unsized-capture-across-yield.stderr @@ -8,7 +8,7 @@ LL | #![feature(unsized_locals)] = note: `#[warn(incomplete_features)]` on by default error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-capture-across-yield.rs:11:27 + --> $DIR/unsized-capture-across-yield.rs:12:27 | LL | move || { | -- this closure captures all values by move diff --git a/tests/ui/coroutine/unsized-local-across-yield.rs b/tests/ui/coroutine/unsized-local-across-yield.rs index 7a8ed60e46a..cb8ced13a11 100644 --- a/tests/ui/coroutine/unsized-local-across-yield.rs +++ b/tests/ui/coroutine/unsized-local-across-yield.rs @@ -6,6 +6,7 @@ use std::ops::Coroutine; fn across() -> impl Coroutine { + #[coroutine] move || { let b: [u8] = *(Box::new([]) as Box<[u8]>); //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui/coroutine/unsized-local-across-yield.stderr b/tests/ui/coroutine/unsized-local-across-yield.stderr index c4c3be77ac2..4fe0f135a9d 100644 --- a/tests/ui/coroutine/unsized-local-across-yield.stderr +++ b/tests/ui/coroutine/unsized-local-across-yield.stderr @@ -8,7 +8,7 @@ LL | #![feature(unsized_locals)] = note: `#[warn(incomplete_features)]` on by default error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-local-across-yield.rs:10:13 + --> $DIR/unsized-local-across-yield.rs:11:13 | LL | let b: [u8] = *(Box::new([]) as Box<[u8]>); | ^ doesn't have a size known at compile-time diff --git a/tests/ui/coroutine/yield-in-args-rev.rs b/tests/ui/coroutine/yield-in-args-rev.rs index b074e2bc939..29d79df25fb 100644 --- a/tests/ui/coroutine/yield-in-args-rev.rs +++ b/tests/ui/coroutine/yield-in-args-rev.rs @@ -10,7 +10,7 @@ fn foo(_a: (), _b: &bool) {} fn bar() { - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used let b = true; foo(yield, &b); }; diff --git a/tests/ui/coroutine/yield-in-args-rev.stderr b/tests/ui/coroutine/yield-in-args-rev.stderr index dbf46739e8b..10829d66185 100644 --- a/tests/ui/coroutine/yield-in-args-rev.stderr +++ b/tests/ui/coroutine/yield-in-args-rev.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/yield-in-args-rev.rs:13:5 + --> $DIR/yield-in-args-rev.rs:13:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | let b = true; LL | | foo(yield, &b); LL | | }; diff --git a/tests/ui/coroutine/yield-in-args.rs b/tests/ui/coroutine/yield-in-args.rs index b2827148d77..bc9909b310c 100644 --- a/tests/ui/coroutine/yield-in-args.rs +++ b/tests/ui/coroutine/yield-in-args.rs @@ -3,6 +3,7 @@ fn foo(_b: &bool, _a: ()) {} fn main() { + #[coroutine] || { let b = true; foo(&b, yield); //~ ERROR diff --git a/tests/ui/coroutine/yield-in-args.stderr b/tests/ui/coroutine/yield-in-args.stderr index 7233f47884b..1d2c54f9bdb 100644 --- a/tests/ui/coroutine/yield-in-args.stderr +++ b/tests/ui/coroutine/yield-in-args.stderr @@ -1,5 +1,5 @@ error[E0626]: borrow may still be in use when coroutine yields - --> $DIR/yield-in-args.rs:8:13 + --> $DIR/yield-in-args.rs:9:13 | LL | foo(&b, yield); | ^^ ----- possible yield occurs here diff --git a/tests/ui/coroutine/yield-in-const.rs b/tests/ui/coroutine/yield-in-const.rs index 22651f32cf8..dc1b30155b9 100644 --- a/tests/ui/coroutine/yield-in-const.rs +++ b/tests/ui/coroutine/yield-in-const.rs @@ -2,5 +2,6 @@ const A: u8 = { yield 3u8; 3u8}; //~^ ERROR yield expression outside +//~| ERROR `yield` can only be used in fn main() {} diff --git a/tests/ui/coroutine/yield-in-const.stderr b/tests/ui/coroutine/yield-in-const.stderr index d5748b05337..f02729412cc 100644 --- a/tests/ui/coroutine/yield-in-const.stderr +++ b/tests/ui/coroutine/yield-in-const.stderr @@ -1,9 +1,15 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/yield-in-const.rs:3:17 + | +LL | const A: u8 = { yield 3u8; 3u8}; + | ^^^^^^^^^ + error[E0627]: yield expression outside of coroutine literal --> $DIR/yield-in-const.rs:3:17 | LL | const A: u8 = { yield 3u8; 3u8}; | ^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/yield-in-function.rs b/tests/ui/coroutine/yield-in-function.rs index a99312043bd..427c5d0e7f5 100644 --- a/tests/ui/coroutine/yield-in-function.rs +++ b/tests/ui/coroutine/yield-in-function.rs @@ -2,3 +2,4 @@ fn main() { yield; } //~^ ERROR yield expression outside +//~| ERROR `yield` can only be used in diff --git a/tests/ui/coroutine/yield-in-function.stderr b/tests/ui/coroutine/yield-in-function.stderr index b9d4708bb8d..dbebf310b04 100644 --- a/tests/ui/coroutine/yield-in-function.stderr +++ b/tests/ui/coroutine/yield-in-function.stderr @@ -1,9 +1,20 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/yield-in-function.rs:3:13 + | +LL | fn main() { yield; } + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn main() { yield; } + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/yield-in-function.rs:3:13 | LL | fn main() { yield; } | ^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/yield-in-initializer.rs b/tests/ui/coroutine/yield-in-initializer.rs index 19218926b8a..3caefac013e 100644 --- a/tests/ui/coroutine/yield-in-initializer.rs +++ b/tests/ui/coroutine/yield-in-initializer.rs @@ -3,7 +3,7 @@ #![feature(coroutines)] fn main() { - static || { //~ WARN unused coroutine that must be used + #[coroutine] static || { //~ WARN unused coroutine that must be used loop { // Test that `opt` is not live across the yield, even when borrowed in a loop // See https://github.com/rust-lang/rust/issues/52792 diff --git a/tests/ui/coroutine/yield-in-initializer.stderr b/tests/ui/coroutine/yield-in-initializer.stderr index 614df43f2f5..1e22b787668 100644 --- a/tests/ui/coroutine/yield-in-initializer.stderr +++ b/tests/ui/coroutine/yield-in-initializer.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/yield-in-initializer.rs:6:5 + --> $DIR/yield-in-initializer.rs:6:18 | -LL | / static || { +LL | #[coroutine] static || { + | __________________^ LL | | loop { LL | | // Test that `opt` is not live across the yield, even when borrowed in a loop LL | | // See https://github.com/rust-lang/rust/issues/52792 diff --git a/tests/ui/coroutine/yield-in-static.rs b/tests/ui/coroutine/yield-in-static.rs index 45e0380d46d..99d08913e64 100644 --- a/tests/ui/coroutine/yield-in-static.rs +++ b/tests/ui/coroutine/yield-in-static.rs @@ -2,5 +2,6 @@ static B: u8 = { yield 3u8; 3u8}; //~^ ERROR yield expression outside +//~| ERROR `yield` can only be used in fn main() {} diff --git a/tests/ui/coroutine/yield-in-static.stderr b/tests/ui/coroutine/yield-in-static.stderr index b56283cab66..d1fd4eab0fc 100644 --- a/tests/ui/coroutine/yield-in-static.stderr +++ b/tests/ui/coroutine/yield-in-static.stderr @@ -1,9 +1,15 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/yield-in-static.rs:3:18 + | +LL | static B: u8 = { yield 3u8; 3u8}; + | ^^^^^^^^^ + error[E0627]: yield expression outside of coroutine literal --> $DIR/yield-in-static.rs:3:18 | LL | static B: u8 = { yield 3u8; 3u8}; | ^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.rs b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.rs index 31025c33b1a..6833bc99012 100644 --- a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.rs +++ b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.rs @@ -4,4 +4,5 @@ fn main() { yield || for i in 0 { } //~^ ERROR yield expression outside of coroutine literal //~| ERROR `{integer}` is not an iterator + //~| ERROR `yield` can only be used in } diff --git a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr index 8f8bec99458..921e8d5d47a 100644 --- a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr +++ b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr @@ -1,3 +1,14 @@ +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/yield-outside-coroutine-issue-78653.rs:4:5 + | +LL | yield || for i in 0 { } + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn main() { + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/yield-outside-coroutine-issue-78653.rs:4:5 | @@ -14,7 +25,7 @@ LL | yield || for i in 0 { } = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{integer}` to implement `IntoIterator` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0627. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/coroutine/yield-subtype.rs b/tests/ui/coroutine/yield-subtype.rs index 271f8362f17..adee5075e83 100644 --- a/tests/ui/coroutine/yield-subtype.rs +++ b/tests/ui/coroutine/yield-subtype.rs @@ -8,7 +8,7 @@ fn bar<'a>() { let a: &'static str = "hi"; let b: &'a str = a; - || { //~ WARN unused coroutine that must be used + #[coroutine] || { //~ WARN unused coroutine that must be used yield a; yield b; }; diff --git a/tests/ui/coroutine/yield-subtype.stderr b/tests/ui/coroutine/yield-subtype.stderr index 5e7ae9f581e..973415327a5 100644 --- a/tests/ui/coroutine/yield-subtype.stderr +++ b/tests/ui/coroutine/yield-subtype.stderr @@ -1,7 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/yield-subtype.rs:11:5 + --> $DIR/yield-subtype.rs:11:18 | -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | yield a; LL | | yield b; LL | | }; diff --git a/tests/ui/coroutine/yield-while-iterating.rs b/tests/ui/coroutine/yield-while-iterating.rs index 66ac6d3922a..77f601e4f2c 100644 --- a/tests/ui/coroutine/yield-while-iterating.rs +++ b/tests/ui/coroutine/yield-while-iterating.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{CoroutineState, Coroutine}; use std::cell::Cell; @@ -9,7 +9,7 @@ fn yield_during_iter_owned_data(x: Vec<i32>) { // reference to it. This winds up becoming a rather confusing // regionck error -- in particular, we would freeze with the // reference in scope, and it doesn't live long enough. - let _b = move || { + let _b =#[coroutine] move || { for p in &x { //~ ERROR yield(); } @@ -17,7 +17,7 @@ fn yield_during_iter_owned_data(x: Vec<i32>) { } fn yield_during_iter_borrowed_slice(x: &[i32]) { - let _b = move || { + let _b = #[coroutine] move || { for p in x { yield(); } @@ -26,7 +26,7 @@ fn yield_during_iter_borrowed_slice(x: &[i32]) { fn yield_during_iter_borrowed_slice_2() { let mut x = vec![22_i32]; - let _b = || { + let _b = #[coroutine] || { for p in &x { yield(); } @@ -38,7 +38,7 @@ fn yield_during_iter_borrowed_slice_3() { // OK to take a mutable ref to `x` and yield // up pointers from it: let mut x = vec![22_i32]; - let mut b = || { + let mut b = #[coroutine] || { for p in &mut x { yield p; } @@ -50,7 +50,7 @@ fn yield_during_iter_borrowed_slice_4() { // ...but not OK to do that while reading // from `x` too let mut x = vec![22_i32]; - let mut b = || { + let mut b = #[coroutine] || { for p in &mut x { yield p; } @@ -61,7 +61,7 @@ fn yield_during_iter_borrowed_slice_4() { fn yield_during_range_iter() { // Should be OK. - let mut b = || { + let mut b = #[coroutine] || { let v = vec![1,2,3]; let len = v.len(); for i in 0..len { diff --git a/tests/ui/coroutine/yield-while-iterating.stderr b/tests/ui/coroutine/yield-while-iterating.stderr index 5330121f372..f81c914c4bd 100644 --- a/tests/ui/coroutine/yield-while-iterating.stderr +++ b/tests/ui/coroutine/yield-while-iterating.stderr @@ -9,8 +9,8 @@ LL | yield(); error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/yield-while-iterating.rs:58:20 | -LL | let mut b = || { - | -- mutable borrow occurs here +LL | let mut b = #[coroutine] || { + | -- mutable borrow occurs here LL | for p in &mut x { | - first borrow occurs due to use of `x` in coroutine ... diff --git a/tests/ui/coroutine/yield-while-local-borrowed.rs b/tests/ui/coroutine/yield-while-local-borrowed.rs index 7f8d1d4543d..3db30c36712 100644 --- a/tests/ui/coroutine/yield-while-local-borrowed.rs +++ b/tests/ui/coroutine/yield-while-local-borrowed.rs @@ -1,4 +1,4 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::cell::Cell; use std::ops::{Coroutine, CoroutineState}; @@ -9,7 +9,7 @@ fn borrow_local_inline() { // // (This error occurs because the region shows up in the type of // `b` and gets extended by region inference.) - let mut b = move || { + let mut b = #[coroutine] move || { let a = &mut 3; //~^ ERROR borrow may still be in use when coroutine yields yield (); @@ -20,7 +20,7 @@ fn borrow_local_inline() { fn borrow_local_inline_done() { // No error here -- `a` is not in scope at the point of `yield`. - let mut b = move || { + let mut b = #[coroutine] move || { { let a = &mut 3; } @@ -34,7 +34,7 @@ fn borrow_local() { // // (This error occurs because the region shows up in the type of // `b` and gets extended by region inference.) - let mut b = move || { + let mut b = #[coroutine] move || { let a = 3; { let b = &a; diff --git a/tests/ui/coroutine/yield-while-ref-reborrowed.rs b/tests/ui/coroutine/yield-while-ref-reborrowed.rs index 07c59175858..2600d0b4124 100644 --- a/tests/ui/coroutine/yield-while-ref-reborrowed.rs +++ b/tests/ui/coroutine/yield-while-ref-reborrowed.rs @@ -1,15 +1,16 @@ -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] -use std::ops::{CoroutineState, Coroutine}; use std::cell::Cell; +use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn reborrow_shared_ref(x: &i32) { // This is OK -- we have a borrow live over the yield, but it's of // data that outlives the coroutine. - let mut b = move || { + let mut b = #[coroutine] + move || { let a = &*x; - yield(); + yield (); println!("{}", a); }; Pin::new(&mut b).resume(()); @@ -18,9 +19,10 @@ fn reborrow_shared_ref(x: &i32) { fn reborrow_mutable_ref(x: &mut i32) { // This is OK -- we have a borrow live over the yield, but it's of // data that outlives the coroutine. - let mut b = move || { + let mut b = #[coroutine] + move || { let a = &mut *x; - yield(); + yield (); println!("{}", a); }; Pin::new(&mut b).resume(()); @@ -28,13 +30,14 @@ fn reborrow_mutable_ref(x: &mut i32) { fn reborrow_mutable_ref_2(x: &mut i32) { // ...but not OK to go on using `x`. - let mut b = || { + let mut b = #[coroutine] + || { let a = &mut *x; - yield(); + yield (); println!("{}", a); }; println!("{}", x); //~ ERROR Pin::new(&mut b).resume(()); } -fn main() { } +fn main() {} diff --git a/tests/ui/coroutine/yield-while-ref-reborrowed.stderr b/tests/ui/coroutine/yield-while-ref-reborrowed.stderr index 62ac0265311..7c9b766457d 100644 --- a/tests/ui/coroutine/yield-while-ref-reborrowed.stderr +++ b/tests/ui/coroutine/yield-while-ref-reborrowed.stderr @@ -1,8 +1,8 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access - --> $DIR/yield-while-ref-reborrowed.rs:36:20 + --> $DIR/yield-while-ref-reborrowed.rs:39:20 | -LL | let mut b = || { - | -- coroutine construction occurs here +LL | || { + | -- coroutine construction occurs here LL | let a = &mut *x; | -- first borrow occurs due to use of `x` in coroutine ... diff --git a/tests/ui/debuginfo/backtrace-dylib-dep.rs b/tests/ui/debuginfo/backtrace-dylib-dep.rs index e2414073ede..fcd1f92e28e 100644 --- a/tests/ui/debuginfo/backtrace-dylib-dep.rs +++ b/tests/ui/debuginfo/backtrace-dylib-dep.rs @@ -27,6 +27,7 @@ macro_rules! pos { }; } +#[collapse_debuginfo(yes)] macro_rules! check { ($($pos:expr),*) => ({ verify(&[$($pos,)* pos!()]); diff --git a/tests/ui/delegation/auxiliary/fn-header-aux.rs b/tests/ui/delegation/auxiliary/fn-header-aux.rs new file mode 100644 index 00000000000..d26209a4f78 --- /dev/null +++ b/tests/ui/delegation/auxiliary/fn-header-aux.rs @@ -0,0 +1,9 @@ +//@ edition:2018 + +#![feature(c_variadic)] + +pub unsafe fn unsafe_fn_extern() {} +pub extern "C" fn extern_fn_extern() {} +pub unsafe extern "C" fn variadic_fn_extern(n: usize, mut args: ...) {} +pub const fn const_fn_extern() {} +pub async fn async_fn_extern() {} diff --git a/tests/ui/delegation/fn-header.rs b/tests/ui/delegation/fn-header.rs new file mode 100644 index 00000000000..db20e1058e0 --- /dev/null +++ b/tests/ui/delegation/fn-header.rs @@ -0,0 +1,57 @@ +//@ check-pass +//@ edition:2018 +//@ aux-crate:fn_header_aux=fn-header-aux.rs + +#![feature(c_variadic)] +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![deny(unused_unsafe)] + +mod to_reuse { + pub unsafe fn unsafe_fn() {} + pub extern "C" fn extern_fn() {} + pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} + pub const fn const_fn() {} + pub async fn async_fn() {} +} + +reuse to_reuse::unsafe_fn; +reuse to_reuse::extern_fn; +reuse to_reuse::variadic_fn; +reuse to_reuse::const_fn; +reuse to_reuse::async_fn; + +reuse fn_header_aux::unsafe_fn_extern; +reuse fn_header_aux::extern_fn_extern; +reuse fn_header_aux::variadic_fn_extern; +reuse fn_header_aux::const_fn_extern; +reuse fn_header_aux::async_fn_extern; + +const fn const_check() { + const_fn(); + const_fn_extern(); +} + +async fn async_check() { + async_fn().await; + async_fn_extern().await; +} + +fn main() { + unsafe { + unsafe_fn(); + unsafe_fn_extern(); + } + extern_fn(); + extern_fn_extern(); + let _: extern "C" fn() = extern_fn; + let _: extern "C" fn() = extern_fn_extern; + unsafe { + variadic_fn(0); + variadic_fn(0, 1); + variadic_fn_extern(0); + variadic_fn_extern(0, 1); + } + let _: unsafe extern "C" fn(usize, ...) = variadic_fn; + let _: unsafe extern "C" fn(usize, ...) = variadic_fn_extern; +} diff --git a/tests/ui/delegation/impl-trait.rs b/tests/ui/delegation/impl-trait.rs new file mode 100644 index 00000000000..13df0155485 --- /dev/null +++ b/tests/ui/delegation/impl-trait.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo() -> impl Clone { 0 } +} + +reuse to_reuse::foo; + +trait Trait { + fn bar() -> impl Clone { 1 } +} + +struct S; +impl Trait for S {} + +impl S { + reuse to_reuse::foo; + reuse <S as Trait>::bar; +} + +fn main() { + foo().clone(); + <S>::bar().clone(); +} diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs index 9dccb12b57a..5f78de97638 100644 --- a/tests/ui/delegation/not-supported.rs +++ b/tests/ui/delegation/not-supported.rs @@ -14,9 +14,9 @@ mod generics { fn foo3<'a: 'a>(_: &'a u32) {} reuse GenericTrait::bar; - //~^ delegation with early bound generics is not supported yet + //~^ ERROR delegation with early bound generics is not supported yet reuse GenericTrait::bar1; - //~^ delegation with early bound generics is not supported yet + //~^ ERROR delegation with early bound generics is not supported yet } struct F; @@ -73,26 +73,18 @@ mod opaque { } reuse to_reuse::opaque_arg; //~^ ERROR delegation with early bound generics is not supported yet - reuse to_reuse::opaque_ret; - //~^ ERROR delegation to a function with opaque type is not supported yet -} -mod fn_header { - mod to_reuse { - pub unsafe fn unsafe_fn() {} - pub extern "C" fn extern_fn() {} - pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} - pub const fn const_fn() {} + trait ToReuse { + fn opaque_ret() -> impl Trait { unimplemented!() } } - reuse to_reuse::unsafe_fn; - //~^ ERROR delegation to unsafe functions is not supported yet - reuse to_reuse::extern_fn; - //~^ ERROR delegation to non Rust ABI functions is not supported yet - reuse to_reuse::variadic_fn; - //~^ ERROR delegation to variadic functions is not supported yet - reuse to_reuse::const_fn; - //~^ ERROR delegation to const functions is not supported yet + // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. + impl ToReuse for u8 { + reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type + } + impl ToReuse for u16 { + reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type + } } mod recursive { diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index f6c49366899..e2cb04f977b 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -115,53 +115,46 @@ LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } LL | reuse to_reuse::opaque_arg; | ^^^^^^^^^^ -error: delegation to a function with opaque type is not supported yet - --> $DIR/not-supported.rs:76:21 +error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/not-supported.rs:82:5: 82:24>::{synthetic#0}` + --> $DIR/not-supported.rs:83:25 | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | --------------------------------- callee defined here -... -LL | reuse to_reuse::opaque_ret; - | ^^^^^^^^^^ - -error: delegation to unsafe functions is not supported yet - --> $DIR/not-supported.rs:88:21 +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ | -LL | pub unsafe fn unsafe_fn() {} - | ------------------------- callee defined here -... -LL | reuse to_reuse::unsafe_fn; - | ^^^^^^^^^ - -error: delegation to non Rust ABI functions is not supported yet - --> $DIR/not-supported.rs:90:21 +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/not-supported.rs:83:25 | -LL | pub extern "C" fn extern_fn() {} - | ----------------------------- callee defined here -... -LL | reuse to_reuse::extern_fn; - | ^^^^^^^^^ - -error: delegation to variadic functions is not supported yet - --> $DIR/not-supported.rs:92:21 +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::<impl at $DIR/not-supported.rs:82:5: 82:24>::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::<impl at $DIR/not-supported.rs:82:5: 82:24>` is well-formed + --> $DIR/not-supported.rs:82:5 | -LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} - | ------------------------------------------------------------- callee defined here -... -LL | reuse to_reuse::variadic_fn; - | ^^^^^^^^^^^ +LL | impl ToReuse for u8 { + | ^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: delegation to const functions is not supported yet - --> $DIR/not-supported.rs:94:21 +error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/not-supported.rs:85:5: 85:25>::{synthetic#0}` + --> $DIR/not-supported.rs:86:24 | -LL | pub const fn const_fn() {} - | ----------------------- callee defined here -... -LL | reuse to_reuse::const_fn; - | ^^^^^^^^ +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/not-supported.rs:86:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::<impl at $DIR/not-supported.rs:85:5: 85:25>::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::<impl at $DIR/not-supported.rs:85:5: 85:25>` is well-formed + --> $DIR/not-supported.rs:85:5 + | +LL | impl ToReuse for u16 { + | ^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: recursive delegation is not supported yet - --> $DIR/not-supported.rs:107:22 + --> $DIR/not-supported.rs:99:22 | LL | pub reuse to_reuse2::foo; | --- callee defined here @@ -169,7 +162,7 @@ LL | pub reuse to_reuse2::foo; LL | reuse to_reuse1::foo; | ^^^ -error: aborting due to 19 previous errors +error: aborting due to 16 previous errors -Some errors have detailed explanations: E0049, E0195. +Some errors have detailed explanations: E0049, E0195, E0391. For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/rename.rs b/tests/ui/delegation/rename.rs new file mode 100644 index 00000000000..f4b3da76c56 --- /dev/null +++ b/tests/ui/delegation/rename.rs @@ -0,0 +1,20 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn a() {} +} + +reuse to_reuse::a as b; + +struct S; +impl S { + reuse to_reuse::a as b; +} + +fn main() { + b(); + S::b(); +} diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index 26ac532263f..a8523d25cab 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -40,7 +40,10 @@ note: if `Y` implemented `Clone`, you could clone the value --> $DIR/deriving-with-repr-packed.rs:16:1 | LL | struct Y(usize); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | struct X(Y); + | - you could clone this value = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/diagnostic-flags/colored-session-opt-error.rs b/tests/ui/diagnostic-flags/colored-session-opt-error.rs index 932c2bf2473..e850345fbf1 100644 --- a/tests/ui/diagnostic-flags/colored-session-opt-error.rs +++ b/tests/ui/diagnostic-flags/colored-session-opt-error.rs @@ -1,6 +1,4 @@ //@ check-pass //@ ignore-windows //@ compile-flags: -Cremark=foo --error-format=human --color=always -// Temporary until next release: -//@ ignore-stage2 fn main() {} diff --git a/tests/ui/drop/dynamic-drop.rs b/tests/ui/drop/dynamic-drop.rs index f848a1a340b..b695b5702d9 100644 --- a/tests/ui/drop/dynamic-drop.rs +++ b/tests/ui/drop/dynamic-drop.rs @@ -1,7 +1,7 @@ //@ run-pass //@ needs-unwind -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] #![feature(if_let_guard)] #![allow(unused_assignments)] @@ -176,7 +176,7 @@ fn vec_simple(a: &Allocator) { fn coroutine(a: &Allocator, run_count: usize) { assert!(run_count < 4); - let mut gen = || { + let mut gen = #[coroutine] || { (a.alloc(), yield a.alloc(), a.alloc(), diff --git a/tests/ui/error-codes/E0504.stderr b/tests/ui/error-codes/E0504.stderr index 900cb706bd9..343bca9a72e 100644 --- a/tests/ui/error-codes/E0504.stderr +++ b/tests/ui/error-codes/E0504.stderr @@ -18,7 +18,10 @@ note: if `FancyNum` implemented `Clone`, you could clone the value --> $DIR/E0504.rs:1:1 | LL | struct FancyNum { - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let fancy_ref = &fancy_num; + | ---------- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0505.stderr b/tests/ui/error-codes/E0505.stderr index ce01298a70d..266df9ea32a 100644 --- a/tests/ui/error-codes/E0505.stderr +++ b/tests/ui/error-codes/E0505.stderr @@ -15,7 +15,10 @@ note: if `Value` implemented `Clone`, you could clone the value --> $DIR/E0505.rs:1:1 | LL | struct Value {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _ref_to_val: &Value = &x; + | -- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0507.stderr b/tests/ui/error-codes/E0507.stderr index 60a4daa9d38..70d99ea2cce 100644 --- a/tests/ui/error-codes/E0507.stderr +++ b/tests/ui/error-codes/E0507.stderr @@ -15,7 +15,10 @@ note: if `TheDarkKnight` implemented `Clone`, you could clone the value --> $DIR/E0507.rs:3:1 | LL | struct TheDarkKnight; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | x.borrow().nothing_is_true(); + | ---------- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0508-fail.stderr b/tests/ui/error-codes/E0508-fail.stderr index 96d3bcb67a5..fcfac399e0d 100644 --- a/tests/ui/error-codes/E0508-fail.stderr +++ b/tests/ui/error-codes/E0508-fail.stderr @@ -11,7 +11,10 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/E0508-fail.rs:1:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _value = array[0]; + | -------- you could clone this value help: consider borrowing here | LL | let _value = &array[0]; diff --git a/tests/ui/error-codes/E0508.stderr b/tests/ui/error-codes/E0508.stderr index c1b622e2432..b9fa0f4d17a 100644 --- a/tests/ui/error-codes/E0508.stderr +++ b/tests/ui/error-codes/E0508.stderr @@ -11,7 +11,10 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/E0508.rs:1:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _value = array[0]; + | -------- you could clone this value help: consider borrowing here | LL | let _value = &array[0]; diff --git a/tests/ui/error-codes/E0509.stderr b/tests/ui/error-codes/E0509.stderr index 75c372d0440..628a253e085 100644 --- a/tests/ui/error-codes/E0509.stderr +++ b/tests/ui/error-codes/E0509.stderr @@ -11,7 +11,10 @@ note: if `FancyNum` implemented `Clone`, you could clone the value --> $DIR/E0509.rs:1:1 | LL | struct FancyNum { - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let fancy_field = drop_struct.fancy; + | ----------------- you could clone this value help: consider borrowing here | LL | let fancy_field = &drop_struct.fancy; diff --git a/tests/ui/error-emitter/highlighting.rs b/tests/ui/error-emitter/highlighting.rs index 16794a80914..b3c1acbd342 100644 --- a/tests/ui/error-emitter/highlighting.rs +++ b/tests/ui/error-emitter/highlighting.rs @@ -3,8 +3,6 @@ //@ compile-flags: --error-format=human --color=always //@ error-pattern:[35mfor<'a> [0m //@ edition:2018 -// Temporary until next release: -//@ ignore-stage2 use core::pin::Pin; use core::future::Future; diff --git a/tests/ui/error-emitter/highlighting.svg b/tests/ui/error-emitter/highlighting.svg index b5791858ab6..1d82a97888a 100644 --- a/tests/ui/error-emitter/highlighting.svg +++ b/tests/ui/error-emitter/highlighting.svg @@ -23,7 +23,7 @@ <text xml:space="preserve" class="container fg"> <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: mismatched types</tspan> </tspan> - <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/highlighting.rs:24:11</tspan> + <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/highlighting.rs:22:11</tspan> </tspan> <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> @@ -43,7 +43,7 @@ </tspan> <tspan x="10px" y="208px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: function defined here</tspan> </tspan> - <tspan x="10px" y="226px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/highlighting.rs:13:4</tspan> + <tspan x="10px" y="226px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/highlighting.rs:11:4</tspan> </tspan> <tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> diff --git a/tests/ui/error-emitter/highlighting.windows.svg b/tests/ui/error-emitter/highlighting.windows.svg index 6b714d64ade..88143f725a5 100644 --- a/tests/ui/error-emitter/highlighting.windows.svg +++ b/tests/ui/error-emitter/highlighting.windows.svg @@ -24,7 +24,7 @@ <text xml:space="preserve" class="container fg"> <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="fg-ansi256-015 bold">: mismatched types</tspan> </tspan> - <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/highlighting.rs:24:11</tspan> + <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/highlighting.rs:22:11</tspan> </tspan> <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">|</tspan> </tspan> @@ -44,7 +44,7 @@ </tspan> <tspan x="10px" y="208px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: function defined here</tspan> </tspan> - <tspan x="10px" y="226px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/highlighting.rs:13:4</tspan> + <tspan x="10px" y="226px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/highlighting.rs:11:4</tspan> </tspan> <tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">|</tspan> </tspan> diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.rs b/tests/ui/error-emitter/multiline-multipart-suggestion.rs index 12c9324edb7..a938b280ca2 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.rs +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.rs @@ -1,7 +1,5 @@ //@ compile-flags: --error-format=human --color=always //@ error-pattern: missing lifetime specifier -// Temporary until next release: -//@ ignore-stage2 fn short(foo_bar: &Vec<&i32>) -> &i32 { &12 diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.svg index 3aa607ea693..26210fade74 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.svg +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.svg @@ -23,7 +23,7 @@ <text xml:space="preserve" class="container fg"> <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0106]</tspan><tspan class="bold">: missing lifetime specifier</tspan> </tspan> - <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:6:34</tspan> + <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:4:34</tspan> </tspan> <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> @@ -47,7 +47,7 @@ </tspan> <tspan x="10px" y="244px"><tspan class="fg-ansi256-009 bold">error[E0106]</tspan><tspan class="bold">: missing lifetime specifier</tspan> </tspan> - <tspan x="10px" y="262px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:13:6</tspan> + <tspan x="10px" y="262px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:11:6</tspan> </tspan> <tspan x="10px" y="280px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> @@ -83,7 +83,7 @@ </tspan> <tspan x="10px" y="568px"><tspan class="fg-ansi256-009 bold">error[E0106]</tspan><tspan class="bold">: missing lifetime specifier</tspan> </tspan> - <tspan x="10px" y="586px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:18:29</tspan> + <tspan x="10px" y="586px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:16:29</tspan> </tspan> <tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg index 330eb96e4ae..3fa9cc18f0d 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg @@ -23,7 +23,7 @@ <text xml:space="preserve" class="container fg"> <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0106]</tspan><tspan class="fg-ansi256-015 bold">: missing lifetime specifier</tspan> </tspan> - <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:6:34</tspan> + <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:4:34</tspan> </tspan> <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">|</tspan> </tspan> @@ -47,7 +47,7 @@ </tspan> <tspan x="10px" y="244px"><tspan class="fg-ansi256-009 bold">error[E0106]</tspan><tspan class="fg-ansi256-015 bold">: missing lifetime specifier</tspan> </tspan> - <tspan x="10px" y="262px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:13:6</tspan> + <tspan x="10px" y="262px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:11:6</tspan> </tspan> <tspan x="10px" y="280px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">|</tspan> </tspan> @@ -83,7 +83,7 @@ </tspan> <tspan x="10px" y="568px"><tspan class="fg-ansi256-009 bold">error[E0106]</tspan><tspan class="fg-ansi256-015 bold">: missing lifetime specifier</tspan> </tspan> - <tspan x="10px" y="586px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:18:29</tspan> + <tspan x="10px" y="586px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">--> </tspan><tspan>$DIR/multiline-multipart-suggestion.rs:16:29</tspan> </tspan> <tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-ansi256-014 bold">|</tspan> </tspan> diff --git a/tests/ui/feature-gates/feature-gate-closure_track_caller.rs b/tests/ui/feature-gates/feature-gate-closure_track_caller.rs index 93bf83ecf53..d90fb765a23 100644 --- a/tests/ui/feature-gates/feature-gate-closure_track_caller.rs +++ b/tests/ui/feature-gates/feature-gate-closure_track_caller.rs @@ -4,6 +4,6 @@ fn main() { let _closure = #[track_caller] || {}; //~ `#[track_caller]` on closures - let _coroutine = #[track_caller] || { yield; }; //~ `#[track_caller]` on closures + let _coroutine = #[coroutine] #[track_caller] || { yield; }; //~ `#[track_caller]` on closures let _future = #[track_caller] async {}; //~ `#[track_caller]` on closures } diff --git a/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr b/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr index 17b5e6016a4..0b12b73fd1f 100644 --- a/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr +++ b/tests/ui/feature-gates/feature-gate-closure_track_caller.stderr @@ -9,10 +9,10 @@ LL | let _closure = #[track_caller] || {}; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/feature-gate-closure_track_caller.rs:7:22 + --> $DIR/feature-gate-closure_track_caller.rs:7:35 | -LL | let _coroutine = #[track_caller] || { yield; }; - | ^^^^^^^^^^^^^^^ +LL | let _coroutine = #[coroutine] #[track_caller] || { yield; }; + | ^^^^^^^^^^^^^^^ | = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-collapse_debuginfo.rs b/tests/ui/feature-gates/feature-gate-collapse_debuginfo.rs deleted file mode 100644 index f73bf579f6d..00000000000 --- a/tests/ui/feature-gates/feature-gate-collapse_debuginfo.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[collapse_debuginfo] -//~^ ERROR the `#[collapse_debuginfo]` attribute is an experimental feature -macro_rules! foo { - ($e:expr) => { $e } -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-collapse_debuginfo.stderr b/tests/ui/feature-gates/feature-gate-collapse_debuginfo.stderr deleted file mode 100644 index f361a76b4a7..00000000000 --- a/tests/ui/feature-gates/feature-gate-collapse_debuginfo.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: the `#[collapse_debuginfo]` attribute is an experimental feature - --> $DIR/feature-gate-collapse_debuginfo.rs:1:1 - | -LL | #[collapse_debuginfo] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #100758 <https://github.com/rust-lang/rust/issues/100758> for more information - = help: add `#![feature(collapse_debuginfo)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr index 1cef163cef5..3bb48e4a37a 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr @@ -8,8 +8,19 @@ LL | yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/feature-gate-coroutines.rs:5:5 + | +LL | yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn main() { + | ++++++++++++ + error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -18,13 +29,24 @@ LL | let _ = || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/feature-gate-coroutines.rs:10:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield true; + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/feature-gate-coroutines.rs:5:5 | LL | yield true; | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0627, E0658. For more information about an error, try `rustc --explain E0627`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr index 403f0549aef..65e7737ef84 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr @@ -9,7 +9,7 @@ LL | yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | let _ = || yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:16:5 + --> $DIR/feature-gate-coroutines.rs:18:5 | LL | yield; | ^^^^^ @@ -29,7 +29,7 @@ LL | yield; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:17:5 + --> $DIR/feature-gate-coroutines.rs:19:5 | LL | yield 0; | ^^^^^^^ @@ -49,8 +49,19 @@ LL | yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/feature-gate-coroutines.rs:5:5 + | +LL | yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn main() { + | ++++++++++++ + error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -60,13 +71,24 @@ LL | let _ = || yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/feature-gate-coroutines.rs:10:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | let _ = #[coroutine] || yield true; + | ++++++++++++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/feature-gate-coroutines.rs:5:5 | LL | yield true; | ^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0627, E0658. For more information about an error, try `rustc --explain E0627`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.rs b/tests/ui/feature-gates/feature-gate-coroutines.rs index b3df2351b68..28dce8596d3 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.rs +++ b/tests/ui/feature-gates/feature-gate-coroutines.rs @@ -5,9 +5,11 @@ fn main() { yield true; //~ ERROR yield syntax is experimental //~^ ERROR yield expression outside of coroutine literal //[none]~^^ ERROR yield syntax is experimental + //~^^^ ERROR `yield` can only be used let _ = || yield true; //~ ERROR yield syntax is experimental //[none]~^ ERROR yield syntax is experimental + //~^^ ERROR `yield` can only be used } #[cfg(FALSE)] diff --git a/tests/ui/feature-gates/feature-gate-inline_const.rs b/tests/ui/feature-gates/feature-gate-inline_const.rs deleted file mode 100644 index 43ff90d234c..00000000000 --- a/tests/ui/feature-gates/feature-gate-inline_const.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let _ = const { - //~^ ERROR inline-const is experimental [E0658] - true - }; -} diff --git a/tests/ui/feature-gates/feature-gate-inline_const.stderr b/tests/ui/feature-gates/feature-gate-inline_const.stderr deleted file mode 100644 index 6cf675065f3..00000000000 --- a/tests/ui/feature-gates/feature-gate-inline_const.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: inline-const is experimental - --> $DIR/feature-gate-inline_const.rs:2:13 - | -LL | let _ = const { - | ^^^^^ - | - = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information - = help: add `#![feature(inline_const)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs new file mode 100644 index 00000000000..313be6f28cd --- /dev/null +++ b/tests/ui/fn/fn_def_coercion.rs @@ -0,0 +1,58 @@ +//! Test that coercing between function items of the same function, +//! but with different generic args succeeds in typeck, but then fails +//! in borrowck when the lifetimes can't actually be merged. + +fn foo<T>(t: T) -> T { + t +} + +fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let mut x = foo::<&'a ()>; //~ ERROR: lifetime may not live long enough + x = foo::<&'b ()>; //~ ERROR: lifetime may not live long enough + x = foo::<&'c ()>; + x(a); + x(b); + x(c); +} + +fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = foo::<&'c ()>; + let _: &'c () = x(a); //~ ERROR lifetime may not live long enough +} + +fn h<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = foo::<&'a ()>; + let _: &'a () = x(c); +} + +fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let mut x = foo::<&'c ()>; + x = foo::<&'b ()>; //~ ERROR lifetime may not live long enough + x = foo::<&'a ()>; //~ ERROR lifetime may not live long enough + x(a); + x(b); + x(c); +} + +fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = match true { + true => foo::<&'b ()>, //~ ERROR lifetime may not live long enough + false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough + }; + x(a); + x(b); + x(c); +} + +fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = match true { + true => foo::<&'c ()>, + false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough + }; + + x(a); + x(b); //~ ERROR lifetime may not live long enough + x(c); +} + +fn main() {} diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr new file mode 100644 index 00000000000..ec4a1bde7fd --- /dev/null +++ b/tests/ui/fn/fn_def_coercion.stderr @@ -0,0 +1,154 @@ +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:10:17 + | +LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'a ()>; + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:11:5 + | +LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'a ()>; +LL | x = foo::<&'b ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:20:12 + | +LL | fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here +LL | let x = foo::<&'c ()>; +LL | let _: &'c () = x(a); + | ^^^^^^ type annotation requires that `'a` must outlive `'c` + | + = help: consider adding the following bound: `'a: 'c` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:30:5 + | +LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'c ()>; +LL | x = foo::<&'b ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:31:5 + | +LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | x = foo::<&'a ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:39:17 + | +LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let x = match true { +LL | true => foo::<&'b ()>, + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:40:18 + | +LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:50:18 + | +LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here +... +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` + | + = help: consider adding the following bound: `'a: 'c` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:54:5 + | +LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | x(b); + | ^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'c` + = help: add bound `'b: 'a` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/fn/fn_def_opaque_coercion.rs b/tests/ui/fn/fn_def_opaque_coercion.rs new file mode 100644 index 00000000000..0a8810cf4f8 --- /dev/null +++ b/tests/ui/fn/fn_def_opaque_coercion.rs @@ -0,0 +1,69 @@ +//! Test that coercing between function items of the same function, +//! but with different generic args works. + +//@check-pass + +#![feature(type_alias_impl_trait)] + +fn foo<T>(t: T) -> T { + t +} + +type F = impl Sized; + +fn f(a: F) { + let mut x = foo::<F>; + x = foo::<()>; + x(a); + x(()); +} + +type G = impl Sized; + +fn g(a: G) { + let x = foo::<()>; + let _: () = x(a); +} + +type H = impl Sized; + +fn h(a: H) { + let x = foo::<H>; + let _: H = x(()); +} + +type I = impl Sized; + +fn i(a: I) { + let mut x = foo::<()>; + x = foo::<I>; + x(a); + x(()); +} + +type J = impl Sized; + +fn j(a: J) { + let x = match true { + true => foo::<J>, + false => foo::<()>, + }; + x(a); + x(()); +} + +fn k() -> impl Sized { + fn bind<T, F: FnOnce(T) -> T>(_: T, f: F) -> F { + f + } + let x = match true { + true => { + let f = foo; + bind(k(), f) + } + false => foo::<()>, + }; + todo!() +} + +fn main() {} diff --git a/tests/ui/fn/suggest-return-closure.rs b/tests/ui/fn/suggest-return-closure.rs index 81f20272867..30e25ca8edc 100644 --- a/tests/ui/fn/suggest-return-closure.rs +++ b/tests/ui/fn/suggest-return-closure.rs @@ -18,6 +18,7 @@ fn fn_mut() -> _ { //~| NOTE for more information on `Fn` traits and closure types let x = String::new(); //~^ HELP: consider changing this to be mutable + //~| NOTE binding `x` declared here |c| { //~ NOTE: value captured here x.push(c); //~^ ERROR: does not live long enough diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr index 8e80a11fe1b..d276ce8be2b 100644 --- a/tests/ui/fn/suggest-return-closure.stderr +++ b/tests/ui/fn/suggest-return-closure.stderr @@ -21,7 +21,7 @@ LL | fn fn_mut() -> _ { = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types - --> $DIR/suggest-return-closure.rs:31:13 + --> $DIR/suggest-return-closure.rs:32:13 | LL | fn fun() -> _ { | ^ @@ -32,7 +32,7 @@ LL | fn fun() -> _ { = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/suggest-return-closure.rs:22:9 + --> $DIR/suggest-return-closure.rs:23:9 | LL | let x = String::new(); | - help: consider changing this to be mutable: `mut x` @@ -41,8 +41,11 @@ LL | x.push(c); | ^ cannot borrow as mutable error[E0597]: `x` does not live long enough - --> $DIR/suggest-return-closure.rs:22:9 + --> $DIR/suggest-return-closure.rs:23:9 | +LL | let x = String::new(); + | - binding `x` declared here +... LL | |c| { | --- value captured here LL | x.push(c); diff --git a/tests/ui/impl-trait/issues/issue-58504.rs b/tests/ui/impl-trait/issues/issue-58504.rs index 4f7a35e81b8..856e1297e58 100644 --- a/tests/ui/impl-trait/issues/issue-58504.rs +++ b/tests/ui/impl-trait/issues/issue-58504.rs @@ -3,7 +3,7 @@ use std::ops::Coroutine; fn mk_gen() -> impl Coroutine<Return=!, Yield=()> { - || { loop { yield; } } + #[coroutine] || { loop { yield; } } } fn main() { diff --git a/tests/ui/impl-trait/lifetimes.rs b/tests/ui/impl-trait/lifetimes.rs index 93a4801fa40..df64b685eab 100644 --- a/tests/ui/impl-trait/lifetimes.rs +++ b/tests/ui/impl-trait/lifetimes.rs @@ -115,7 +115,7 @@ impl<'unnecessary_lifetime> MyVec { } fn coroutine_doesnt_capture_unnecessary_lifetime<'s: 's>() -> impl Sized { - || yield + #[coroutine] || yield } } diff --git a/tests/ui/impl-trait/normalize-tait-in-const.rs b/tests/ui/impl-trait/normalize-tait-in-const.rs index ccd073b8070..422c2e439cf 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.rs +++ b/tests/ui/impl-trait/normalize-tait-in-const.rs @@ -3,7 +3,6 @@ #![feature(type_alias_impl_trait)] #![feature(const_trait_impl)] #![feature(const_refs_to_cell)] -#![feature(inline_const)] use std::marker::Destruct; diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 7ae8306d74d..fbd41b61730 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,11 +1,11 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:25:42 + --> $DIR/normalize-tait-in-const.rs:24:42 | LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^^^^^^^^^^^^^^^ error[E0015]: cannot call non-const closure in constant functions - --> $DIR/normalize-tait-in-const.rs:26:5 + --> $DIR/normalize-tait-in-const.rs:25:5 | LL | fun(filter_positive()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL + #![feature(effects)] | error[E0493]: destructor of `F` cannot be evaluated at compile-time - --> $DIR/normalize-tait-in-const.rs:25:79 + --> $DIR/normalize-tait-in-const.rs:24:79 | LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^ the destructor for this type cannot be evaluated in constant functions diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr index c0b399746ea..96db2030a40 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/recursive-coroutine-boxed.rs:14:23 + --> $DIR/recursive-coroutine-boxed.rs:15:23 | LL | let mut gen = Box::pin(foo()); | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box` @@ -13,7 +13,7 @@ LL | let mut gen = Box::<T>::pin(foo()); | +++++ error[E0308]: mismatched types - --> $DIR/recursive-coroutine-boxed.rs:13:5 + --> $DIR/recursive-coroutine-boxed.rs:14:18 | LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> { | --------------------------------------- @@ -21,7 +21,8 @@ LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> { | the expected opaque type | expected `impl Coroutine<Yield = (), Return = ()>` because of return type ... -LL | / || { +LL | #[coroutine] || { + | __________________^ LL | | let mut gen = Box::pin(foo()); LL | | LL | | let mut r = gen.as_mut().resume(()); @@ -31,7 +32,7 @@ LL | | } | |_____^ types differ | = note: expected opaque type `impl Coroutine<Yield = (), Return = ()>` - found coroutine `{coroutine@$DIR/recursive-coroutine-boxed.rs:13:5: 13:7}` + found coroutine `{coroutine@$DIR/recursive-coroutine-boxed.rs:14:18: 14:20}` error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs index 02c75be0f3a..24a77d73114 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -10,7 +10,8 @@ fn foo() -> impl Coroutine<Yield = (), Return = ()> { // FIXME(-Znext-solver): this fails with a mismatched types as the // hidden type of the opaque ends up as {type error}. We should not // emit errors for such goals. - || { //[next]~ ERROR mismatched types + + #[coroutine] || { //[next]~ ERROR mismatched types let mut gen = Box::pin(foo()); //[next]~^ ERROR type annotations needed let mut r = gen.as_mut().resume(()); diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr index ee87c483d0d..9814187e179 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr @@ -1,8 +1,8 @@ error[E0733]: recursion in a coroutine requires boxing - --> $DIR/recursive-coroutine-indirect.rs:11:5 + --> $DIR/recursive-coroutine-indirect.rs:11:18 | -LL | move || { - | ^^^^^^^ +LL | #[coroutine] move || { + | ^^^^^^^ LL | let x = coroutine_hold(); | - recursive call here diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr index ee87c483d0d..9814187e179 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr @@ -1,8 +1,8 @@ error[E0733]: recursion in a coroutine requires boxing - --> $DIR/recursive-coroutine-indirect.rs:11:5 + --> $DIR/recursive-coroutine-indirect.rs:11:18 | -LL | move || { - | ^^^^^^^ +LL | #[coroutine] move || { + | ^^^^^^^ LL | let x = coroutine_hold(); | - recursive call here diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.rs b/tests/ui/impl-trait/recursive-coroutine-indirect.rs index bba9792fe3c..cec2176049b 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.rs +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.rs @@ -8,7 +8,7 @@ #![feature(coroutines)] #![allow(unconditional_recursion)] fn coroutine_hold() -> impl Sized { - move || { //~ ERROR recursion in a coroutine requires boxing + #[coroutine] move || { //~ ERROR recursion in a coroutine requires boxing let x = coroutine_hold(); yield; x; diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs index 432f80a1763..8b9dac0e29b 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -57,6 +57,8 @@ fn coroutine_sig() -> impl Sized { fn coroutine_capture() -> impl Sized { //~^ ERROR let x = coroutine_capture(); + + #[coroutine] move || { yield; x; diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index d5b8c531fd6..2d2731e4368 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -98,10 +98,10 @@ LL | | yield; LL | | x; | | - coroutine captures itself here LL | | } - | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:60:5: 60:12}` + | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:62:5: 62:12}` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:66:35 + --> $DIR/recursive-impl-trait-type-indirect.rs:68:35 | LL | fn substs_change<T: 'static>() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -110,7 +110,7 @@ LL | (substs_change::<&T>(),) | ------------------------ returning here with type `(impl Sized,)` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:76:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:78:26 | LL | fn mutual_recursion() -> impl Sync { | ^^^^^^^^^ recursive opaque type @@ -122,7 +122,7 @@ LL | fn mutual_recursion_b() -> impl Sized { | ---------- returning this opaque type `impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:81:28 + --> $DIR/recursive-impl-trait-type-indirect.rs:83:28 | LL | fn mutual_recursion() -> impl Sync { | --------- returning this opaque type `impl Sync` diff --git a/tests/ui/inference/issue-80409.compat.stderr b/tests/ui/inference/issue-80409.compat.stderr new file mode 100644 index 00000000000..2f3f6cef209 --- /dev/null +++ b/tests/ui/inference/issue-80409.compat.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `usize: Fsm` is not satisfied + --> $DIR/issue-80409.rs:36:31 + | +LL | builder.state().on_entry(|_| {}); + | ^ the trait `Fsm` is not implemented for `usize` + | +help: this trait has no implementations, consider adding one + --> $DIR/issue-80409.rs:26:1 + | +LL | trait Fsm { + | ^^^^^^^^^ +note: required by a bound in `StateContext` + --> $DIR/issue-80409.rs:30:31 + | +LL | struct StateContext<'a, TFsm: Fsm> { + | ^^^ required by this bound in `StateContext` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr index c772225be75..2f3f6cef209 100644 --- a/tests/ui/inference/issue-80409.no-compat.stderr +++ b/tests/ui/inference/issue-80409.no-compat.stderr @@ -1,14 +1,20 @@ -error: internal compiler error: error performing operation: fully_perform - --> $DIR/issue-80409.rs:49:30 +error[E0277]: the trait bound `usize: Fsm` is not satisfied + --> $DIR/issue-80409.rs:36:31 | LL | builder.state().on_entry(|_| {}); - | ^^^ + | ^ the trait `Fsm` is not implemented for `usize` | -note: - --> $DIR/issue-80409.rs:49:30 +help: this trait has no implementations, consider adding one + --> $DIR/issue-80409.rs:26:1 | -LL | builder.state().on_entry(|_| {}); - | ^^^ +LL | trait Fsm { + | ^^^^^^^^^ +note: required by a bound in `StateContext` + --> $DIR/issue-80409.rs:30:31 + | +LL | struct StateContext<'a, TFsm: Fsm> { + | ^^^ required by this bound in `StateContext` + +error: aborting due to 1 previous error -query stack during panic: -end of query stack +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/inference/issue-80409.rs b/tests/ui/inference/issue-80409.rs index dfb84563e6d..86dac3cda91 100644 --- a/tests/ui/inference/issue-80409.rs +++ b/tests/ui/inference/issue-80409.rs @@ -1,18 +1,5 @@ -// This should not pass, because `usize: Fsm` does not hold. However, it currently ICEs. - -// ignore-tidy-linelength - //@ revisions: compat no-compat -//@[compat] check-pass //@[no-compat] compile-flags: -Zno-implied-bounds-compat -//@[no-compat] check-fail -//@[no-compat] known-bug: #80409 -//@[no-compat] failure-status: 101 -//@[no-compat] normalize-stderr-test "delayed at.*" -> "" -//@[no-compat] normalize-stderr-test "note: .*\n\n" -> "" -//@[no-compat] normalize-stderr-test "thread 'rustc' panicked.*\n" -> "" -//@[no-compat] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//@[no-compat] rustc-env:RUST_BACKTRACE=0 #![allow(unreachable_code, unused)] @@ -47,4 +34,5 @@ struct StateContext<'a, TFsm: Fsm> { fn main() { let mut builder: FsmBuilder<usize> = todo!(); builder.state().on_entry(|_| {}); + //~^ ERROR the trait bound `usize: Fsm` is not satisfied } diff --git a/tests/ui/inline-const/const-expr-array-init.rs b/tests/ui/inline-const/const-expr-array-init.rs index 075c27c1cc9..eb126b61f2d 100644 --- a/tests/ui/inline-const/const-expr-array-init.rs +++ b/tests/ui/inline-const/const-expr-array-init.rs @@ -1,7 +1,5 @@ //@ build-pass -#![feature(inline_const)] - use std::cell::Cell; fn main() { diff --git a/tests/ui/inline-const/const-expr-basic.rs b/tests/ui/inline-const/const-expr-basic.rs index 6a19cc656d0..7f769d2b5c3 100644 --- a/tests/ui/inline-const/const-expr-basic.rs +++ b/tests/ui/inline-const/const-expr-basic.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(inline_const)] - fn foo() -> i32 { const { let x = 5 + 10; diff --git a/tests/ui/inline-const/const-expr-generic-err.rs b/tests/ui/inline-const/const-expr-generic-err.rs index 3c4bbcb3dc9..3249e826a96 100644 --- a/tests/ui/inline-const/const-expr-generic-err.rs +++ b/tests/ui/inline-const/const-expr-generic-err.rs @@ -1,5 +1,4 @@ //@ build-fail -#![feature(inline_const)] fn foo<T>() { const { assert!(std::mem::size_of::<T>() == 0); } //~ ERROR E0080 diff --git a/tests/ui/inline-const/const-expr-generic-err.stderr b/tests/ui/inline-const/const-expr-generic-err.stderr index 7331c7f18e9..dcd6b62bbfc 100644 --- a/tests/ui/inline-const/const-expr-generic-err.stderr +++ b/tests/ui/inline-const/const-expr-generic-err.stderr @@ -1,37 +1,37 @@ error[E0080]: evaluation of `foo::<i32>::{constant#0}` failed - --> $DIR/const-expr-generic-err.rs:5:13 + --> $DIR/const-expr-generic-err.rs:4:13 | LL | const { assert!(std::mem::size_of::<T>() == 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: std::mem::size_of::<T>() == 0', $DIR/const-expr-generic-err.rs:5:13 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: std::mem::size_of::<T>() == 0', $DIR/const-expr-generic-err.rs:4:13 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $DIR/const-expr-generic-err.rs:5:5 + --> $DIR/const-expr-generic-err.rs:4:5 | LL | const { assert!(std::mem::size_of::<T>() == 0); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: the above error was encountered while instantiating `fn foo::<i32>` - --> $DIR/const-expr-generic-err.rs:13:5 + --> $DIR/const-expr-generic-err.rs:12:5 | LL | foo::<i32>(); | ^^^^^^^^^^^^ error[E0080]: evaluation of `bar::<0>::{constant#0}` failed - --> $DIR/const-expr-generic-err.rs:9:13 + --> $DIR/const-expr-generic-err.rs:8:13 | LL | const { N - 1 } | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow note: erroneous constant encountered - --> $DIR/const-expr-generic-err.rs:9:5 + --> $DIR/const-expr-generic-err.rs:8:5 | LL | const { N - 1 } | ^^^^^^^^^^^^^^^ note: erroneous constant encountered - --> $DIR/const-expr-generic-err.rs:9:5 + --> $DIR/const-expr-generic-err.rs:8:5 | LL | const { N - 1 } | ^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | const { N - 1 } = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: the above error was encountered while instantiating `fn bar::<0>` - --> $DIR/const-expr-generic-err.rs:14:5 + --> $DIR/const-expr-generic-err.rs:13:5 | LL | bar::<0>(); | ^^^^^^^^^^ diff --git a/tests/ui/inline-const/const-expr-generic-err2.rs b/tests/ui/inline-const/const-expr-generic-err2.rs index e097cbe9dd6..49cbdbfda5d 100644 --- a/tests/ui/inline-const/const-expr-generic-err2.rs +++ b/tests/ui/inline-const/const-expr-generic-err2.rs @@ -1,5 +1,3 @@ -#![feature(inline_const)] - fn foo<T>() { let _ = [0u8; const { std::mem::size_of::<T>() }]; //~^ ERROR: constant expression depends on a generic parameter diff --git a/tests/ui/inline-const/const-expr-generic-err2.stderr b/tests/ui/inline-const/const-expr-generic-err2.stderr index 5876a6c9e19..c6d77593c46 100644 --- a/tests/ui/inline-const/const-expr-generic-err2.stderr +++ b/tests/ui/inline-const/const-expr-generic-err2.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/const-expr-generic-err2.rs:4:19 + --> $DIR/const-expr-generic-err2.rs:2:19 | LL | let _ = [0u8; const { std::mem::size_of::<T>() }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/inline-const/const-expr-generic.rs b/tests/ui/inline-const/const-expr-generic.rs index e634e1d4a47..0c33b02d3a2 100644 --- a/tests/ui/inline-const/const-expr-generic.rs +++ b/tests/ui/inline-const/const-expr-generic.rs @@ -1,5 +1,4 @@ //@ check-pass -#![feature(inline_const)] fn foo<T>() -> usize { const { std::mem::size_of::<T>() } diff --git a/tests/ui/inline-const/const-expr-inference.rs b/tests/ui/inline-const/const-expr-inference.rs index f3b97d3430e..99cea3204a1 100644 --- a/tests/ui/inline-const/const-expr-inference.rs +++ b/tests/ui/inline-const/const-expr-inference.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(inline_const)] - pub fn todo<T>() -> T { const { todo!() } } diff --git a/tests/ui/inline-const/const-expr-lifetime-err.rs b/tests/ui/inline-const/const-expr-lifetime-err.rs index 0a032a7338a..df1e5fcb473 100644 --- a/tests/ui/inline-const/const-expr-lifetime-err.rs +++ b/tests/ui/inline-const/const-expr-lifetime-err.rs @@ -1,5 +1,4 @@ #![feature(const_mut_refs)] -#![feature(inline_const)] use std::marker::PhantomData; diff --git a/tests/ui/inline-const/const-expr-lifetime-err.stderr b/tests/ui/inline-const/const-expr-lifetime-err.stderr index 75877bc093a..f97e2d25e6c 100644 --- a/tests/ui/inline-const/const-expr-lifetime-err.stderr +++ b/tests/ui/inline-const/const-expr-lifetime-err.stderr @@ -1,5 +1,5 @@ error[E0597]: `y` does not live long enough - --> $DIR/const-expr-lifetime-err.rs:23:30 + --> $DIR/const-expr-lifetime-err.rs:22:30 | LL | fn foo<'a>() { | -- lifetime `'a` defined here diff --git a/tests/ui/inline-const/const-expr-lifetime.rs b/tests/ui/inline-const/const-expr-lifetime.rs index 5dac17645d7..071e724a0fa 100644 --- a/tests/ui/inline-const/const-expr-lifetime.rs +++ b/tests/ui/inline-const/const-expr-lifetime.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(const_mut_refs)] -#![feature(inline_const)] use std::marker::PhantomData; diff --git a/tests/ui/inline-const/const-expr-macro.rs b/tests/ui/inline-const/const-expr-macro.rs index bf3cb3c3320..cf07eb12f5a 100644 --- a/tests/ui/inline-const/const-expr-macro.rs +++ b/tests/ui/inline-const/const-expr-macro.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(inline_const)] - macro_rules! do_const_block{ ($val:block) => { const $val } } diff --git a/tests/ui/inline-const/const-expr-reference.rs b/tests/ui/inline-const/const-expr-reference.rs index b3753b0d371..208271e37c3 100644 --- a/tests/ui/inline-const/const-expr-reference.rs +++ b/tests/ui/inline-const/const-expr-reference.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(inline_const)] - const fn bar() -> i32 { const { 2 + 3 diff --git a/tests/ui/inline-const/const-match-pat-lifetime.rs b/tests/ui/inline-const/const-match-pat-lifetime.rs index f909e68e7be..590c426c773 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime.rs +++ b/tests/ui/inline-const/const-match-pat-lifetime.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(const_mut_refs)] -#![feature(inline_const)] #![feature(inline_const_pat)] use std::marker::PhantomData; diff --git a/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs b/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs index a1c3c61484a..e0a889ac347 100644 --- a/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs +++ b/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(inline_const)] - fn main() { let _my_usize = const { let a = 10_usize; diff --git a/tests/ui/inline-const/expr-unsafe-err.rs b/tests/ui/inline-const/expr-unsafe-err.rs index a05a2945168..d53d84b944f 100644 --- a/tests/ui/inline-const/expr-unsafe-err.rs +++ b/tests/ui/inline-const/expr-unsafe-err.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] const unsafe fn require_unsafe() -> usize { 1 } diff --git a/tests/ui/inline-const/expr-unsafe-err.stderr b/tests/ui/inline-const/expr-unsafe-err.stderr index 45f850d1f99..13a408b971c 100644 --- a/tests/ui/inline-const/expr-unsafe-err.stderr +++ b/tests/ui/inline-const/expr-unsafe-err.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block - --> $DIR/expr-unsafe-err.rs:8:9 + --> $DIR/expr-unsafe-err.rs:7:9 | LL | require_unsafe(); | ^^^^^^^^^^^^^^^^ call to unsafe function diff --git a/tests/ui/inline-const/expr-unsafe.rs b/tests/ui/inline-const/expr-unsafe.rs index f9d1450503e..cdd101f3e08 100644 --- a/tests/ui/inline-const/expr-unsafe.rs +++ b/tests/ui/inline-const/expr-unsafe.rs @@ -1,7 +1,7 @@ //@ check-pass #![warn(unused_unsafe)] -#![feature(inline_const)] + const unsafe fn require_unsafe() -> usize { 1 } fn main() { diff --git a/tests/ui/inline-const/expr-with-block-err.rs b/tests/ui/inline-const/expr-with-block-err.rs index f7547742ddc..6f850757558 100644 --- a/tests/ui/inline-const/expr-with-block-err.rs +++ b/tests/ui/inline-const/expr-with-block-err.rs @@ -1,5 +1,3 @@ -#![feature(inline_const)] - fn main() { const { 2 } - const { 1 }; //~^ ERROR mismatched types diff --git a/tests/ui/inline-const/expr-with-block-err.stderr b/tests/ui/inline-const/expr-with-block-err.stderr index a46d7395045..f127c11e9b7 100644 --- a/tests/ui/inline-const/expr-with-block-err.stderr +++ b/tests/ui/inline-const/expr-with-block-err.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/expr-with-block-err.rs:4:13 + --> $DIR/expr-with-block-err.rs:2:13 | LL | const { 2 } - const { 1 }; | ^ expected `()`, found integer diff --git a/tests/ui/inline-const/expr-with-block.rs b/tests/ui/inline-const/expr-with-block.rs index 07a1c9a10f5..a32afbcffad 100644 --- a/tests/ui/inline-const/expr-with-block.rs +++ b/tests/ui/inline-const/expr-with-block.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(inline_const)] + fn main() { match true { true => const {} diff --git a/tests/ui/inline-const/instance-doesnt-depend-on-type.rs b/tests/ui/inline-const/instance-doesnt-depend-on-type.rs index e69106a43af..c53aab60b06 100644 --- a/tests/ui/inline-const/instance-doesnt-depend-on-type.rs +++ b/tests/ui/inline-const/instance-doesnt-depend-on-type.rs @@ -1,8 +1,6 @@ //@ check-pass // issue: 114660 -#![feature(inline_const)] - fn main() { const { core::mem::transmute::<u8, u8> }; // Don't resolve the instance of this inline constant to be an intrinsic, diff --git a/tests/ui/inline-const/interpolated.rs b/tests/ui/inline-const/interpolated.rs index 582900e7aa0..38ed2a042e0 100644 --- a/tests/ui/inline-const/interpolated.rs +++ b/tests/ui/inline-const/interpolated.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(inline_const)] - // This used to be unsupported since the parser first tries to check if we have // any nested items, and then checks for statements (and expressions). The heuristic // that we were using to detect the beginning of a const item was incorrect, so diff --git a/tests/ui/inline-const/promotion.rs b/tests/ui/inline-const/promotion.rs index 242959c6b51..2cfb8a0d19f 100644 --- a/tests/ui/inline-const/promotion.rs +++ b/tests/ui/inline-const/promotion.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![allow(arithmetic_overflow, unconditional_panic)] // The only way to have promoteds that fail is in `const fn` called from `const`/`static`. diff --git a/tests/ui/inline-const/promotion.stderr b/tests/ui/inline-const/promotion.stderr index 7f06b97818b..4e914c9e087 100644 --- a/tests/ui/inline-const/promotion.stderr +++ b/tests/ui/inline-const/promotion.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promotion.rs:17:37 + --> $DIR/promotion.rs:16:37 | LL | let _x: &'static i32 = &div_by_zero(); | ------------ ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use diff --git a/tests/ui/inline-const/required-const.rs b/tests/ui/inline-const/required-const.rs index 3de0ab2a0c0..8f640e933d0 100644 --- a/tests/ui/inline-const/required-const.rs +++ b/tests/ui/inline-const/required-const.rs @@ -1,6 +1,5 @@ //@ build-fail //@ compile-flags: -Zmir-opt-level=3 -#![feature(inline_const)] fn foo<T>() { if false { diff --git a/tests/ui/inline-const/required-const.stderr b/tests/ui/inline-const/required-const.stderr index 2a13d18547c..6ca4c250223 100644 --- a/tests/ui/inline-const/required-const.stderr +++ b/tests/ui/inline-const/required-const.stderr @@ -1,13 +1,13 @@ error[E0080]: evaluation of `foo::<i32>::{constant#0}` failed - --> $DIR/required-const.rs:7:17 + --> $DIR/required-const.rs:6:17 | LL | const { panic!() } - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/required-const.rs:7:17 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/required-const.rs:6:17 | = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $DIR/required-const.rs:7:9 + --> $DIR/required-const.rs:6:9 | LL | const { panic!() } | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/invalid-compile-flags/print.rs b/tests/ui/invalid-compile-flags/print.rs new file mode 100644 index 00000000000..0d0a9d22750 --- /dev/null +++ b/tests/ui/invalid-compile-flags/print.rs @@ -0,0 +1 @@ +//@ compile-flags: --print yyyy diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr new file mode 100644 index 00000000000..0a032aabdfe --- /dev/null +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -0,0 +1,4 @@ +error: unknown print request: `yyyy` + | + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + diff --git a/tests/ui/issues/issue-17385.stderr b/tests/ui/issues/issue-17385.stderr index 988db0fb1fc..3c451a859e9 100644 --- a/tests/ui/issues/issue-17385.stderr +++ b/tests/ui/issues/issue-17385.stderr @@ -12,7 +12,10 @@ note: if `X` implemented `Clone`, you could clone the value --> $DIR/issue-17385.rs:1:1 | LL | struct X(isize); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(foo); + | --- you could clone this value error[E0382]: use of moved value: `e` --> $DIR/issue-17385.rs:25:11 @@ -28,7 +31,10 @@ note: if `Enum` implemented `Clone`, you could clone the value --> $DIR/issue-17385.rs:3:1 | LL | enum Enum { - | ^^^^^^^^^ + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | drop(e); + | - you could clone this value error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-24357.rs b/tests/ui/issues/issue-24357.rs index d1a9e37251e..63c061594d8 100644 --- a/tests/ui/issues/issue-24357.rs +++ b/tests/ui/issues/issue-24357.rs @@ -1,10 +1,12 @@ struct NoCopy; //~ NOTE if `NoCopy` implemented `Clone`, you could clone the value +//~^ NOTE consider implementing `Clone` for this type fn main() { let x = NoCopy; //~^ NOTE move occurs because `x` has type `NoCopy` let f = move || { let y = x; }; //~^ NOTE value moved into closure here //~| NOTE variable moved due to use in closure + //~| NOTE you could clone this value let z = x; //~^ ERROR use of moved value: `x` //~| NOTE value used here after move diff --git a/tests/ui/issues/issue-24357.stderr b/tests/ui/issues/issue-24357.stderr index 6d50eea7e21..2d85077fe4c 100644 --- a/tests/ui/issues/issue-24357.stderr +++ b/tests/ui/issues/issue-24357.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/issue-24357.rs:8:12 + --> $DIR/issue-24357.rs:10:12 | LL | let x = NoCopy; | - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait @@ -16,7 +16,10 @@ note: if `NoCopy` implemented `Clone`, you could clone the value --> $DIR/issue-24357.rs:1:1 | LL | struct NoCopy; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let f = move || { let y = x; }; + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-4335.stderr b/tests/ui/issues/issue-4335.stderr index 8b4aff54dc3..14b5cfa9f9a 100644 --- a/tests/ui/issues/issue-4335.stderr +++ b/tests/ui/issues/issue-4335.stderr @@ -7,6 +7,14 @@ LL | id(Box::new(|| *v)) | -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait | | | captured by this `FnMut` closure + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/issue-4335.rs:5:10 + | +LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> { + | ^ consider constraining this type parameter with `Clone` +LL | id(Box::new(|| *v)) + | -- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-66706.rs b/tests/ui/issues/issue-66706.rs index 835fdfae86c..6d1d9f5e3a9 100644 --- a/tests/ui/issues/issue-66706.rs +++ b/tests/ui/issues/issue-66706.rs @@ -12,6 +12,7 @@ fn b() { fn c() { [0; [|&_: _ &_| {}; 0 ].len()] //~^ ERROR expected `,`, found `&` + //~| ERROR type annotations needed } fn d() { diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr index ffdd61e7723..0271db754bd 100644 --- a/tests/ui/issues/issue-66706.stderr +++ b/tests/ui/issues/issue-66706.stderr @@ -21,7 +21,7 @@ LL | [0; [|&_: _ &_| {}; 0 ].len()] | help: missing `,` error: expected identifier, found reserved identifier `_` - --> $DIR/issue-66706.rs:18:26 + --> $DIR/issue-66706.rs:19:26 | LL | [0; match [|f @ &ref _| () ] {} ] | ----- ^ expected identifier, found reserved identifier @@ -34,6 +34,12 @@ error[E0282]: type annotations needed LL | [0; [|_: _ &_| ()].len()] | ^ cannot infer type -error: aborting due to 5 previous errors +error[E0282]: type annotations needed + --> $DIR/issue-66706.rs:13:11 + | +LL | [0; [|&_: _ &_| {}; 0 ].len()] + | ^^^^^ cannot infer type + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs index e98affc5cc2..2c5257ce063 100644 --- a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs +++ b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs @@ -19,5 +19,4 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA` fn main() { let _ = [0; B::VALUE]; - //~^ constant } diff --git a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr index 6f9302bc4a5..fa1d7dffbd4 100644 --- a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr +++ b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr @@ -13,12 +13,6 @@ LL | type MyA: TraitA; LL | impl TraitB for B { | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation -note: erroneous constant encountered - --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 - | -LL | let _ = [0; B::VALUE]; - | ^^^^^^^^ - error: aborting due to 2 previous errors Some errors have detailed explanations: E0046, E0437. diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs index a2461cff932..3bc87b9d480 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.rs +++ b/tests/ui/lifetimes/unusual-rib-combinations.rs @@ -1,5 +1,3 @@ -#![feature(inline_const)] - struct S<'a>(&'a u8); fn foo() {} diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 320e64a2f77..2857fc72ea1 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -1,11 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/unusual-rib-combinations.rs:24:15 + --> $DIR/unusual-rib-combinations.rs:22:15 | LL | fn d<const C: S>() {} | ^ expected named lifetime parameter error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/unusual-rib-combinations.rs:29:22 + --> $DIR/unusual-rib-combinations.rs:27:22 | LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; | ^^ the type must not depend on the parameter `'a` @@ -13,25 +13,25 @@ LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; = note: lifetime parameters may not be used in the type of const parameters error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:7:16 + --> $DIR/unusual-rib-combinations.rs:5:16 | LL | fn a() -> [u8; foo::()] { | ^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:14:15 + --> $DIR/unusual-rib-combinations.rs:12:15 | LL | fn b<const C: u8()>() {} | ^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:18:10 + --> $DIR/unusual-rib-combinations.rs:16:10 | LL | fn c<T = u8()>() {} | ^^^^ only `Fn` traits may use parentheses error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/unusual-rib-combinations.rs:18:6 + --> $DIR/unusual-rib-combinations.rs:16:6 | LL | fn c<T = u8()>() {} | ^^^^^^^^ @@ -41,7 +41,7 @@ LL | fn c<T = u8()>() {} = note: `#[deny(invalid_type_param_default)]` on by default error[E0308]: mismatched types - --> $DIR/unusual-rib-combinations.rs:7:16 + --> $DIR/unusual-rib-combinations.rs:5:16 | LL | fn a() -> [u8; foo::()] { | ^^^^^^^ expected `usize`, found fn item @@ -50,7 +50,7 @@ LL | fn a() -> [u8; foo::()] { found fn item `fn() {foo}` error: `S<'_>` is forbidden as the type of a const generic parameter - --> $DIR/unusual-rib-combinations.rs:24:15 + --> $DIR/unusual-rib-combinations.rs:22:15 | LL | fn d<const C: S>() {} | ^ diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs index e87afe9094c..2d1822a54ac 100644 --- a/tests/ui/lint/invalid_from_utf8.rs +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -1,6 +1,5 @@ //@ check-pass -#![feature(inline_const)] #![feature(concat_bytes)] #![warn(invalid_from_utf8_unchecked)] diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr index 884165d4f12..07616e11801 100644 --- a/tests/ui/lint/invalid_from_utf8.stderr +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -1,5 +1,5 @@ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:21:9 + --> $DIR/invalid_from_utf8.rs:20:9 | LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -7,13 +7,13 @@ LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112 | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:6:9 + --> $DIR/invalid_from_utf8.rs:5:9 | LL | #![warn(invalid_from_utf8_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:23:9 + --> $DIR/invalid_from_utf8.rs:22:9 | LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -21,7 +21,7 @@ LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:41:9 + --> $DIR/invalid_from_utf8.rs:40:9 | LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -29,7 +29,7 @@ LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:43:9 + --> $DIR/invalid_from_utf8.rs:42:9 | LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -37,7 +37,7 @@ LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b' | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:45:9 + --> $DIR/invalid_from_utf8.rs:44:9 | LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ @@ -45,7 +45,7 @@ LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:47:9 + --> $DIR/invalid_from_utf8.rs:46:9 | LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -53,7 +53,7 @@ LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:64:9 + --> $DIR/invalid_from_utf8.rs:63:9 | LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -61,13 +61,13 @@ LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:7:9 + --> $DIR/invalid_from_utf8.rs:6:9 | LL | #![warn(invalid_from_utf8)] | ^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:66:9 + --> $DIR/invalid_from_utf8.rs:65:9 | LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -75,7 +75,7 @@ LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p' | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:84:9 + --> $DIR/invalid_from_utf8.rs:83:9 | LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^----------------------------------^ @@ -83,7 +83,7 @@ LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:86:9 + --> $DIR/invalid_from_utf8.rs:85:9 | LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ @@ -91,7 +91,7 @@ LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']) | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:88:9 + --> $DIR/invalid_from_utf8.rs:87:9 | LL | std::str::from_utf8(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^-------------^ @@ -99,7 +99,7 @@ LL | std::str::from_utf8(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:90:9 + --> $DIR/invalid_from_utf8.rs:89:9 | LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -107,7 +107,7 @@ LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:97:5 + --> $DIR/invalid_from_utf8.rs:96:5 | LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -115,7 +115,7 @@ LL | std::str::from_utf8_mut(&mut a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:101:5 + --> $DIR/invalid_from_utf8.rs:100:5 | LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -124,7 +124,7 @@ LL | std::str::from_utf8_mut(c); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:104:5 + --> $DIR/invalid_from_utf8.rs:103:5 | LL | let mut c = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -132,7 +132,7 @@ LL | std::str::from_utf8(c); | ^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:107:5 + --> $DIR/invalid_from_utf8.rs:106:5 | LL | const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -140,7 +140,7 @@ LL | std::str::from_utf8(&INVALID_1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:110:5 + --> $DIR/invalid_from_utf8.rs:109:5 | LL | static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -148,7 +148,7 @@ LL | std::str::from_utf8(&INVALID_2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:113:5 + --> $DIR/invalid_from_utf8.rs:112:5 | LL | const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -156,7 +156,7 @@ LL | std::str::from_utf8(INVALID_3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:116:5 + --> $DIR/invalid_from_utf8.rs:115:5 | LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes diff --git a/tests/ui/lint/must_not_suspend/tuple-mismatch.rs b/tests/ui/lint/must_not_suspend/tuple-mismatch.rs index 2f3c5d9ea29..ec409925d72 100644 --- a/tests/ui/lint/must_not_suspend/tuple-mismatch.rs +++ b/tests/ui/lint/must_not_suspend/tuple-mismatch.rs @@ -1,7 +1,8 @@ -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { - let _coroutine = || { + let _coroutine = #[coroutine] + || { yield ((), ((), ())); yield ((), ()); //~^ ERROR mismatched types diff --git a/tests/ui/lint/must_not_suspend/tuple-mismatch.stderr b/tests/ui/lint/must_not_suspend/tuple-mismatch.stderr index 3adf26cfee2..102eadd7aff 100644 --- a/tests/ui/lint/must_not_suspend/tuple-mismatch.stderr +++ b/tests/ui/lint/must_not_suspend/tuple-mismatch.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/tuple-mismatch.rs:6:20 + --> $DIR/tuple-mismatch.rs:7:20 | LL | yield ((), ()); | ^^ expected `((), ())`, found `()` diff --git a/tests/ui/lint/non-local-defs/consts.rs b/tests/ui/lint/non-local-defs/consts.rs index 2652447dcf5..d8a497e43e5 100644 --- a/tests/ui/lint/non-local-defs/consts.rs +++ b/tests/ui/lint/non-local-defs/consts.rs @@ -2,8 +2,6 @@ //@ edition:2021 //@ rustc-env:CARGO_CRATE_NAME=non_local_def -#![feature(inline_const)] - struct Test; trait Uto {} diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr index 5563ea9d93f..d15b452b004 100644 --- a/tests/ui/lint/non-local-defs/consts.stderr +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:15:5 + --> $DIR/consts.rs:13:5 | LL | const Z: () = { | - help: use a const-anon item to suppress this lint: `_` @@ -14,7 +14,7 @@ LL | impl Uto for &Test {} = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:26:5 + --> $DIR/consts.rs:24:5 | LL | impl Uto2 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | impl Uto2 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:34:5 + --> $DIR/consts.rs:32:5 | LL | impl Uto3 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | impl Uto3 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:45:5 + --> $DIR/consts.rs:43:5 | LL | / impl Test { LL | | @@ -50,7 +50,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:52:9 + --> $DIR/consts.rs:50:9 | LL | / impl Test { LL | | @@ -64,7 +64,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:61:9 + --> $DIR/consts.rs:59:9 | LL | / impl Test { LL | | @@ -78,7 +78,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:74:9 + --> $DIR/consts.rs:72:9 | LL | impl Uto9 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | impl Uto9 for Test {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/consts.rs:81:9 + --> $DIR/consts.rs:79:9 | LL | impl Uto10 for Test {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.rs b/tests/ui/lint/non-local-defs/from-local-for-global.rs index 0ab3a6b1988..fea9679d737 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.rs +++ b/tests/ui/lint/non-local-defs/from-local-for-global.rs @@ -1,8 +1,6 @@ //@ check-pass //@ edition:2021 -#![feature(inline_const)] - struct Cat; struct Wrap<T>(T); diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.stderr b/tests/ui/lint/non-local-defs/from-local-for-global.stderr index bd592a72157..0cd385049aa 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.stderr +++ b/tests/ui/lint/non-local-defs/from-local-for-global.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:10:5 + --> $DIR/from-local-for-global.rs:8:5 | LL | / impl From<Cat> for () { LL | | @@ -16,7 +16,7 @@ LL | | } = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:20:5 + --> $DIR/from-local-for-global.rs:18:5 | LL | / impl From<Wrap<Wrap<Elephant>>> for () { LL | | @@ -32,7 +32,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:34:5 + --> $DIR/from-local-for-global.rs:32:5 | LL | impl StillNonLocal for &Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | impl StillNonLocal for &Foo {} = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:42:5 + --> $DIR/from-local-for-global.rs:40:5 | LL | / impl From<Local1> for GlobalSameFunction { LL | | @@ -59,7 +59,7 @@ LL | | } = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/from-local-for-global.rs:50:5 + --> $DIR/from-local-for-global.rs:48:5 | LL | / impl From<Local2> for GlobalSameFunction { LL | | diff --git a/tests/ui/lint/unused/issue-74883-unused-paren-baren-yield.rs b/tests/ui/lint/unused/issue-74883-unused-paren-baren-yield.rs index c5dd281cb4e..12e2bcb898c 100644 --- a/tests/ui/lint/unused/issue-74883-unused-paren-baren-yield.rs +++ b/tests/ui/lint/unused/issue-74883-unused-paren-baren-yield.rs @@ -1,12 +1,12 @@ #![feature(coroutine_trait)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![deny(unused_braces, unused_parens)] use std::ops::Coroutine; use std::pin::Pin; fn main() { - let mut x = |_| { + let mut x = #[coroutine] |_| { while let Some(_) = (yield) {} while let Some(_) = {yield} {} diff --git a/tests/ui/lint/unused/unused-closure.rs b/tests/ui/lint/unused/unused-closure.rs index 9106edee653..4633038cc9b 100644 --- a/tests/ui/lint/unused/unused-closure.rs +++ b/tests/ui/lint/unused/unused-closure.rs @@ -2,7 +2,7 @@ //@ edition:2018 #![feature(async_closure)] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![deny(unused_must_use)] fn unused() { @@ -26,7 +26,7 @@ fn unused() { fn ignored() { let _ = || {}; - let _ = || yield 42; + let _ = #[coroutine] || yield 42; } fn main() { diff --git a/tests/ui/liveness/liveness-upvars.rs b/tests/ui/liveness/liveness-upvars.rs index 7898b978882..f76efba3e6b 100644 --- a/tests/ui/liveness/liveness-upvars.rs +++ b/tests/ui/liveness/liveness-upvars.rs @@ -1,6 +1,6 @@ //@ edition:2018 //@ check-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![warn(unused)] #![allow(unreachable_code)] @@ -131,7 +131,7 @@ pub fn async_coroutine() { pub fn coroutine() { let mut s: u32 = 0; - let _ = |_| { + let _ = #[coroutine] |_| { s = 0; yield (); s = 1; //~ WARN value assigned to `s` is never read diff --git a/tests/ui/loops/dont-suggest-break-thru-item.rs b/tests/ui/loops/dont-suggest-break-thru-item.rs index 34a9a57bfed..b4262ec02bf 100644 --- a/tests/ui/loops/dont-suggest-break-thru-item.rs +++ b/tests/ui/loops/dont-suggest-break-thru-item.rs @@ -1,7 +1,5 @@ //@ edition:2021 -#![feature(inline_const)] - fn closure() { loop { let closure = || { diff --git a/tests/ui/loops/dont-suggest-break-thru-item.stderr b/tests/ui/loops/dont-suggest-break-thru-item.stderr index c84a98198f5..642578ade60 100644 --- a/tests/ui/loops/dont-suggest-break-thru-item.stderr +++ b/tests/ui/loops/dont-suggest-break-thru-item.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:9:17 + --> $DIR/dont-suggest-break-thru-item.rs:7:17 | LL | / if true { LL | | Err(1) @@ -17,7 +17,7 @@ LL | return Err(1); | ++++++ + error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:23:17 + --> $DIR/dont-suggest-break-thru-item.rs:21:17 | LL | / if true { LL | | Err(1) @@ -35,7 +35,7 @@ LL | return Err(1); | ++++++ + error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:37:17 + --> $DIR/dont-suggest-break-thru-item.rs:35:17 | LL | / if true { LL | | Err(1) @@ -48,7 +48,7 @@ LL | | } found enum `Result<_, {integer}>` error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:49:17 + --> $DIR/dont-suggest-break-thru-item.rs:47:17 | LL | / if true { LL | | Err(1) diff --git a/tests/ui/lto/issue-105637.rs b/tests/ui/lto/issue-105637.rs index 2cc70964b4c..884cd5d5e0e 100644 --- a/tests/ui/lto/issue-105637.rs +++ b/tests/ui/lto/issue-105637.rs @@ -3,8 +3,8 @@ // // That manifested as both `rustc_driver` and rustc's "main" (`compiler/rustc`) having their own // `std::panicking::HOOK` static, and the hook in rustc's main (the default stdlib's) being executed -// when rustc ICEs, instead of the overriden hook from `rustc_driver` (which also displays the query -// stack and information on how to open a GH issue for the encountered ICE). +// when rustc ICEs, instead of the overridden hook from `rustc_driver` (which also displays the +// query stack and information on how to open a GH issue for the encountered ICE). // // In this test, we reproduce this setup by installing a panic hook in both the main and an LTOed // dylib: the last hook set should be the one being executed, the dylib's. diff --git a/tests/ui/mir/issue-102389.stderr b/tests/ui/mir/issue-102389.stderr index 838eaffb5a0..162d7ac031a 100644 --- a/tests/ui/mir/issue-102389.stderr +++ b/tests/ui/mir/issue-102389.stderr @@ -8,7 +8,10 @@ note: if `Enum` implemented `Clone`, you could clone the value --> $DIR/issue-102389.rs:1:1 | LL | enum Enum { A, B, C } - | ^^^^^^^^^ + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | array[*inbounds as usize] + | --------- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/moves/borrow-closures-instead-of-move.rs b/tests/ui/moves/borrow-closures-instead-of-move.rs index 51771ced7f2..e4bca54e995 100644 --- a/tests/ui/moves/borrow-closures-instead-of-move.rs +++ b/tests/ui/moves/borrow-closures-instead-of-move.rs @@ -1,4 +1,4 @@ -fn takes_fn(f: impl Fn()) { +fn takes_fn(f: impl Fn()) { //~ HELP if `impl Fn()` implemented `Clone` loop { takes_fnonce(f); //~^ ERROR use of moved value @@ -6,7 +6,7 @@ fn takes_fn(f: impl Fn()) { } } -fn takes_fn_mut(m: impl FnMut()) { +fn takes_fn_mut(m: impl FnMut()) { //~ HELP if `impl FnMut()` implemented `Clone` if maybe() { takes_fnonce(m); //~^ HELP consider mutably borrowing diff --git a/tests/ui/moves/borrow-closures-instead-of-move.stderr b/tests/ui/moves/borrow-closures-instead-of-move.stderr index 9a84ddef7e6..ab6ff417efb 100644 --- a/tests/ui/moves/borrow-closures-instead-of-move.stderr +++ b/tests/ui/moves/borrow-closures-instead-of-move.stderr @@ -15,6 +15,14 @@ LL | fn takes_fnonce(_: impl FnOnce()) {} | ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function +help: if `impl Fn()` implemented `Clone`, you could clone the value + --> $DIR/borrow-closures-instead-of-move.rs:1:16 + | +LL | fn takes_fn(f: impl Fn()) { + | ^^^^^^^^^ consider constraining this type parameter with `Clone` +LL | loop { +LL | takes_fnonce(f); + | - you could clone this value help: consider borrowing `f` | LL | takes_fnonce(&f); @@ -39,6 +47,14 @@ LL | fn takes_fnonce(_: impl FnOnce()) {} | ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function +help: if `impl FnMut()` implemented `Clone`, you could clone the value + --> $DIR/borrow-closures-instead-of-move.rs:9:20 + | +LL | fn takes_fn_mut(m: impl FnMut()) { + | ^^^^^^^^^^^^ consider constraining this type parameter with `Clone` +LL | if maybe() { +LL | takes_fnonce(m); + | - you could clone this value help: consider mutably borrowing `m` | LL | takes_fnonce(&mut m); diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.rs b/tests/ui/moves/issue-72649-uninit-in-loop.rs index 86f389cb3af..8f2e01bdf1a 100644 --- a/tests/ui/moves/issue-72649-uninit-in-loop.rs +++ b/tests/ui/moves/issue-72649-uninit-in-loop.rs @@ -7,6 +7,10 @@ struct NonCopy; //~| NOTE if `NonCopy` implemented `Clone` //~| NOTE if `NonCopy` implemented `Clone` //~| NOTE if `NonCopy` implemented `Clone` +//~| NOTE consider implementing `Clone` for this type +//~| NOTE consider implementing `Clone` for this type +//~| NOTE consider implementing `Clone` for this type +//~| NOTE consider implementing `Clone` for this type fn good() { loop { @@ -21,6 +25,7 @@ fn moved_here_1() { //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait let _used = value; //~^ NOTE value moved here + //~| NOTE you could clone this value let _used2 = value; //~ ERROR use of moved value: `value` //~^ NOTE value used here after move } @@ -32,6 +37,7 @@ fn moved_here_2() { loop { //~ NOTE inside of this loop let _used = value; //~^ NOTE value moved here + //~| NOTE you could clone this value loop { let _used2 = value; //~ ERROR use of moved value: `value` //~^ NOTE value used here after move @@ -45,6 +51,7 @@ fn moved_loop_1() { loop { //~ NOTE inside of this loop let _used = value; //~ ERROR use of moved value: `value` //~^ NOTE value moved here, in previous iteration of loop + //~| NOTE you could clone this value } } @@ -56,6 +63,7 @@ fn moved_loop_2() { loop { //~ NOTE inside of this loop let _used2 = value; //~ ERROR use of moved value: `value` //~^ NOTE value moved here, in previous iteration of loop + //~| NOTE you could clone this value } } diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.stderr b/tests/ui/moves/issue-72649-uninit-in-loop.stderr index a613f35a35e..3a93769ac45 100644 --- a/tests/ui/moves/issue-72649-uninit-in-loop.stderr +++ b/tests/ui/moves/issue-72649-uninit-in-loop.stderr @@ -1,12 +1,12 @@ error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:24:22 + --> $DIR/issue-72649-uninit-in-loop.rs:29:22 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait LL | LL | let _used = value; | ----- value moved here -LL | +... LL | let _used2 = value; | ^^^^^ value used here after move | @@ -14,10 +14,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/issue-72649-uninit-in-loop.rs:5:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _used = value; + | ----- you could clone this value error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:36:26 + --> $DIR/issue-72649-uninit-in-loop.rs:42:26 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -34,10 +37,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/issue-72649-uninit-in-loop.rs:5:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _used = value; + | ----- you could clone this value error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:46:21 + --> $DIR/issue-72649-uninit-in-loop.rs:52:21 | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -51,10 +57,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/issue-72649-uninit-in-loop.rs:5:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _used = value; + | ----- you could clone this value error[E0382]: use of moved value: `value` - --> $DIR/issue-72649-uninit-in-loop.rs:57:22 + --> $DIR/issue-72649-uninit-in-loop.rs:64:22 | LL | let mut value = NonCopy{}; | --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait @@ -68,10 +77,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value --> $DIR/issue-72649-uninit-in-loop.rs:5:1 | LL | struct NonCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _used2 = value; + | ----- you could clone this value error[E0381]: used binding `value` isn't initialized - --> $DIR/issue-72649-uninit-in-loop.rs:65:21 + --> $DIR/issue-72649-uninit-in-loop.rs:73:21 | LL | let value: NonCopy; | ----- binding declared here but left uninitialized @@ -84,7 +96,7 @@ LL | let value: NonCopy = /* value */; | +++++++++++++ error[E0381]: used binding `value` isn't initialized - --> $DIR/issue-72649-uninit-in-loop.rs:73:21 + --> $DIR/issue-72649-uninit-in-loop.rs:81:21 | LL | let mut value: NonCopy; | --------- binding declared here but left uninitialized diff --git a/tests/ui/moves/issue-75904-move-closure-loop.stderr b/tests/ui/moves/issue-75904-move-closure-loop.stderr index b6ad906bbdb..815e91b0f4d 100644 --- a/tests/ui/moves/issue-75904-move-closure-loop.stderr +++ b/tests/ui/moves/issue-75904-move-closure-loop.stderr @@ -15,7 +15,10 @@ note: if `NotCopy` implemented `Clone`, you could clone the value --> $DIR/issue-75904-move-closure-loop.rs:5:1 | LL | struct NotCopy; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | a; + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr index e6bf52276ac..f2c6008d27e 100644 --- a/tests/ui/moves/move-fn-self-receiver.stderr +++ b/tests/ui/moves/move-fn-self-receiver.stderr @@ -106,7 +106,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/move-fn-self-receiver.rs:5:1 | LL | struct Foo; - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let ret = mut_foo.use_mut_self(); + | ------- you could clone this value error[E0382]: use of moved value: `rc_foo` --> $DIR/move-fn-self-receiver.rs:55:5 @@ -142,7 +145,10 @@ note: if `Foo` implemented `Clone`, you could clone the value --> $DIR/move-fn-self-receiver.rs:5:1 | LL | struct Foo; - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | foo_add + Foo; + | ------- you could clone this value note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/arith.rs:LL:COL diff --git a/tests/ui/moves/move-out-of-array-1.stderr b/tests/ui/moves/move-out-of-array-1.stderr index 9e4a08e0cef..8a030f02192 100644 --- a/tests/ui/moves/move-out-of-array-1.stderr +++ b/tests/ui/moves/move-out-of-array-1.stderr @@ -11,7 +11,10 @@ note: if `D` implemented `Clone`, you could clone the value --> $DIR/move-out-of-array-1.rs:5:1 | LL | struct D { _x: u8 } - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | a[i] + | ---- you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr index 4759b45892c..a8473bb8198 100644 --- a/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr +++ b/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr @@ -17,6 +17,13 @@ LL | let mut r = R {c: Box::new(f)}; LL | f(&mut r, false) | ^ value borrowed here after move | +help: if `F` implemented `Clone`, you could clone the value + --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:30:16 + | +LL | fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) { + | ^ consider constraining this type parameter with `Clone` +LL | let mut r = R {c: Box::new(f)}; + | - you could clone this value help: consider mutably borrowing `f` | LL | let mut r = R {c: Box::new(&mut f)}; diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed index e726c8145c3..bfb855c7fb1 100644 --- a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed +++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed @@ -3,6 +3,7 @@ fn duplicate_t<T: Copy>(t: T) -> (T, T) { //~^ HELP consider restricting type parameter `T` + //~| HELP if `T` implemented `Clone`, you could clone the value (t, t) //~ use of moved value: `t` } @@ -72,10 +73,11 @@ where #[rustfmt::skip] fn existing_colon<T: Copy>(t: T) { //~^ HELP consider restricting type parameter `T` + //~| HELP if `T` implemented `Clone`, you could clone the value [t, t]; //~ use of moved value: `t` } -fn existing_colon_in_where<T>(t: T) +fn existing_colon_in_where<T>(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value where T:, T: Copy //~^ HELP consider further restricting type parameter `T` diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs index ee08ce0fa5b..fbe5a1d74c3 100644 --- a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs +++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs @@ -3,6 +3,7 @@ fn duplicate_t<T>(t: T) -> (T, T) { //~^ HELP consider restricting type parameter `T` + //~| HELP if `T` implemented `Clone`, you could clone the value (t, t) //~ use of moved value: `t` } @@ -72,10 +73,11 @@ where #[rustfmt::skip] fn existing_colon<T:>(t: T) { //~^ HELP consider restricting type parameter `T` + //~| HELP if `T` implemented `Clone`, you could clone the value [t, t]; //~ use of moved value: `t` } -fn existing_colon_in_where<T>(t: T) +fn existing_colon_in_where<T>(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value where T:, //~^ HELP consider further restricting type parameter `T` diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr index 3e37fcb2141..c03204c7b9f 100644 --- a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr +++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr @@ -1,21 +1,29 @@ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:6:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:7:9 | LL | fn duplicate_t<T>(t: T) -> (T, T) { | - move occurs because `t` has type `T`, which does not implement the `Copy` trait -LL | +... LL | (t, t) | - ^ value used here after move | | | value moved here | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/use_of_moved_value_copy_suggestions.rs:4:16 + | +LL | fn duplicate_t<T>(t: T) -> (T, T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | (t, t) + | - you could clone this value help: consider restricting type parameter `T` | LL | fn duplicate_t<T: Copy>(t: T) -> (T, T) { | ++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:11:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:12:9 | LL | fn duplicate_opt<T>(t: Option<T>) -> (Option<T>, Option<T>) { | - move occurs because `t` has type `Option<T>`, which does not implement the `Copy` trait @@ -31,7 +39,7 @@ LL | fn duplicate_opt<T: Copy>(t: Option<T>) -> (Option<T>, Option<T>) { | ++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:16:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:17:9 | LL | fn duplicate_tup1<T>(t: (T,)) -> ((T,), (T,)) { | - move occurs because `t` has type `(T,)`, which does not implement the `Copy` trait @@ -47,7 +55,7 @@ LL | fn duplicate_tup1<T: Copy>(t: (T,)) -> ((T,), (T,)) { | ++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:21:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:22:9 | LL | fn duplicate_tup2<A, B>(t: (A, B)) -> ((A, B), (A, B)) { | - move occurs because `t` has type `(A, B)`, which does not implement the `Copy` trait @@ -63,7 +71,7 @@ LL | fn duplicate_tup2<A: Copy, B: Copy>(t: (A, B)) -> ((A, B), (A, B)) { | ++++++ ++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:26:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:27:9 | LL | fn duplicate_custom<T>(t: S<T>) -> (S<T>, S<T>) { | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait @@ -79,7 +87,7 @@ LL | fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) { | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:44:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:45:9 | LL | fn duplicate_custom_1<T>(t: S<T>) -> (S<T>, S<T>) where { | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait @@ -95,7 +103,7 @@ LL | fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where { | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:52:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:53:9 | LL | fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>) | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait @@ -111,7 +119,7 @@ LL | T: A + Copy + Trait, | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:61:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:62:9 | LL | fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>) | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait @@ -127,7 +135,7 @@ LL | T: A + Copy + Trait, | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:70:9 | LL | fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>) | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait @@ -143,23 +151,31 @@ LL | fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>) | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:77:9 | LL | fn existing_colon<T:>(t: T) { | - move occurs because `t` has type `T`, which does not implement the `Copy` trait -LL | +... LL | [t, t]; | - ^ value used here after move | | | value moved here | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/use_of_moved_value_copy_suggestions.rs:74:19 + | +LL | fn existing_colon<T:>(t: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | [t, t]; + | - you could clone this value help: consider restricting type parameter `T` | LL | fn existing_colon<T: Copy>(t: T) { | ++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:85:9 | LL | fn existing_colon_in_where<T>(t: T) | - move occurs because `t` has type `T`, which does not implement the `Copy` trait @@ -169,6 +185,14 @@ LL | [t, t]; | | | value moved here | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/use_of_moved_value_copy_suggestions.rs:80:28 + | +LL | fn existing_colon_in_where<T>(t: T) + | ^ consider constraining this type parameter with `Clone` +... +LL | [t, t]; + | - you could clone this value help: consider further restricting type parameter `T` | LL | T:, T: Copy diff --git a/tests/ui/mut/mut-pattern-internal-mutability.stderr b/tests/ui/mut/mut-pattern-internal-mutability.stderr index 5f2074edb12..ab80af17a08 100644 --- a/tests/ui/mut/mut-pattern-internal-mutability.stderr +++ b/tests/ui/mut/mut-pattern-internal-mutability.stderr @@ -2,12 +2,18 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/mut-pattern-internal-mutability.rs:5:5 | LL | let &mut x = foo; - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let &mut mut x = foo; + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let &mut ref mut x = foo; + | ~~~~~~~~~ error[E0506]: cannot assign to `*foo` because it is borrowed --> $DIR/mut-pattern-internal-mutability.rs:13:5 diff --git a/tests/ui/nll/closure-borrow-spans.stderr b/tests/ui/nll/closure-borrow-spans.stderr index cac22c2ecda..c466cad25d2 100644 --- a/tests/ui/nll/closure-borrow-spans.stderr +++ b/tests/ui/nll/closure-borrow-spans.stderr @@ -25,6 +25,8 @@ LL | f.use_ref(); error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:19:16 | +LL | let x = 1; + | - binding `x` declared here LL | f = || x; | -- ^ borrowed value does not live long enough | | @@ -85,6 +87,8 @@ LL | f.use_ref(); error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:52:16 | +LL | let mut x = 1; + | ----- binding `x` declared here LL | f = || x = 0; | -- ^ borrowed value does not live long enough | | @@ -145,6 +149,8 @@ LL | f.use_ref(); error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:86:16 | +LL | let x = &mut z; + | - binding `x` declared here LL | f = || *x = 0; | -- ^^ borrowed value does not live long enough | | diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr index aa73e91cc77..8e47ab780f2 100644 --- a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -37,6 +37,9 @@ LL | fn test() { error[E0597]: `y` does not live long enough --> $DIR/escape-upvar-nested.rs:21:40 | +LL | let y = 22; + | - binding `y` declared here +LL | LL | let mut closure = || { | -- value captured here LL | let mut closure1 = || p = &y; diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr index 949dcc78703..c428150aa2f 100644 --- a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -23,6 +23,8 @@ LL | fn test() { error[E0597]: `y` does not live long enough --> $DIR/escape-upvar-ref.rs:23:35 | +LL | let y = 22; + | - binding `y` declared here LL | let mut closure = || p = &y; | -- ^ borrowed value does not live long enough | | diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr index 81b5f09b041..15f48d88c37 100644 --- a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr +++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr @@ -1,6 +1,8 @@ error[E0597]: `local_arr` does not live long enough --> $DIR/propagate-multiple-requirements.rs:15:14 | +LL | let local_arr = other_local_arr; + | --------- binding `local_arr` declared here LL | let mut out: &mut &'static [i32] = &mut (&[1] as _); | ------------------- type annotation requires that `local_arr` is borrowed for `'static` LL | once(|mut z: &[i32], mut out_val: &mut &[i32]| { diff --git a/tests/ui/nll/coroutine-distinct-lifetime.rs b/tests/ui/nll/coroutine-distinct-lifetime.rs index ff94a3d54b7..471fad686c4 100644 --- a/tests/ui/nll/coroutine-distinct-lifetime.rs +++ b/tests/ui/nll/coroutine-distinct-lifetime.rs @@ -9,6 +9,7 @@ //@ check-pass fn foo(x: &mut u32) { + #[coroutine] move || { let s = &mut *x; yield; diff --git a/tests/ui/nll/coroutine-upvar-mutability.rs b/tests/ui/nll/coroutine-upvar-mutability.rs index 12853b16b9b..a7d14173fb9 100644 --- a/tests/ui/nll/coroutine-upvar-mutability.rs +++ b/tests/ui/nll/coroutine-upvar-mutability.rs @@ -4,6 +4,8 @@ fn mutate_upvar() { let x = 0; + + #[coroutine] move || { x = 1; //~^ ERROR diff --git a/tests/ui/nll/coroutine-upvar-mutability.stderr b/tests/ui/nll/coroutine-upvar-mutability.stderr index 8922eae3151..8b9be877c8f 100644 --- a/tests/ui/nll/coroutine-upvar-mutability.stderr +++ b/tests/ui/nll/coroutine-upvar-mutability.stderr @@ -1,9 +1,9 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/coroutine-upvar-mutability.rs:8:9 + --> $DIR/coroutine-upvar-mutability.rs:10:9 | LL | let x = 0; | - help: consider changing this to be mutable: `mut x` -LL | move || { +... LL | x = 1; | ^^^^^ cannot assign diff --git a/tests/ui/nll/extra-unused-mut.rs b/tests/ui/nll/extra-unused-mut.rs index 786ba98508f..b040dcc6e5d 100644 --- a/tests/ui/nll/extra-unused-mut.rs +++ b/tests/ui/nll/extra-unused-mut.rs @@ -18,6 +18,8 @@ fn mutable_upvar() { // #50897 fn coroutine_mutable_upvar() { let mut x = 0; + + #[coroutine] move || { x = 1; yield; @@ -36,13 +38,13 @@ struct Expr { // #51904 fn parse_dot_or_call_expr_with(mut attrs: Vec<u32>) { let x = Expr { attrs: vec![] }; - Some(Some(x)).map(|expr| + Some(Some(x)).map(|expr| { expr.map(|mut expr| { attrs.push(666); expr.attrs = attrs; expr }) - ); + }); } // Found when trying to bootstrap rustc diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-use.stderr index 2aff375f0a7..496a298a36c 100644 --- a/tests/ui/nll/issue-21232-partial-init-and-use.stderr +++ b/tests/ui/nll/issue-21232-partial-init-and-use.stderr @@ -32,7 +32,10 @@ note: if `S<Box<u32>>` implemented `Clone`, you could clone the value --> $DIR/issue-21232-partial-init-and-use.rs:15:1 | LL | struct S<Y> { - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let mut s: S<B> = S::new(); drop(s); + | - you could clone this value error[E0382]: assign to part of moved value: `t` --> $DIR/issue-21232-partial-init-and-use.rs:116:5 @@ -83,7 +86,10 @@ note: if `S<Box<u32>>` implemented `Clone`, you could clone the value --> $DIR/issue-21232-partial-init-and-use.rs:15:1 | LL | struct S<Y> { - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let mut s: S<B> = S::new(); drop(s); + | - you could clone this value error[E0382]: assign to part of moved value: `t` --> $DIR/issue-21232-partial-init-and-use.rs:142:5 diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed new file mode 100644 index 00000000000..7692be7ccc8 --- /dev/null +++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.fixed @@ -0,0 +1,23 @@ +// Issue 27282: Example 1: This sidesteps the AST checks disallowing +// mutable borrows in match guards by hiding the mutable borrow in a +// guard behind a move (of the ref mut pattern id) within a closure. +//@ run-rustfix +#![feature(if_let_guard)] + +fn main() { + match Some(&4) { + None => {}, + ref mut foo + if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {}, + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] + Some(s) => std::process::exit(*s), + } + + match Some(&4) { + None => {}, + ref mut foo + if let Some(()) = { (|| { let mut bar = foo.clone(); bar.take() })(); None } => {}, + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] + Some(s) => std::process::exit(*s), + } +} diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs index 833ca8afd61..f3d0a184e03 100644 --- a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs +++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.rs @@ -1,14 +1,14 @@ // Issue 27282: Example 1: This sidesteps the AST checks disallowing // mutable borrows in match guards by hiding the mutable borrow in a // guard behind a move (of the ref mut pattern id) within a closure. - +//@ run-rustfix #![feature(if_let_guard)] fn main() { match Some(&4) { None => {}, ref mut foo - if { (|| { let bar = foo; bar.take() })(); false } => {}, + if { (|| { let mut bar = foo; bar.take() })(); false } => {}, //~^ ERROR cannot move out of `foo` in pattern guard [E0507] Some(s) => std::process::exit(*s), } @@ -16,7 +16,7 @@ fn main() { match Some(&4) { None => {}, ref mut foo - if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {}, + if let Some(()) = { (|| { let mut bar = foo; bar.take() })(); None } => {}, //~^ ERROR cannot move out of `foo` in pattern guard [E0507] Some(s) => std::process::exit(*s), } diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr index 4a512560c87..7781e77894b 100644 --- a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr +++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr @@ -1,22 +1,30 @@ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19 | -LL | if { (|| { let bar = foo; bar.take() })(); false } => {}, - | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait +LL | if { (|| { let mut bar = foo; bar.take() })(); false } => {}, + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {}, + | ++++++++ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34 | -LL | if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {}, - | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait +LL | if let Some(()) = { (|| { let mut bar = foo; bar.take() })(); None } => {}, + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | if let Some(()) = { (|| { let mut bar = foo.clone(); bar.take() })(); None } => {}, + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/issue-27282-mutation-in-guard.stderr b/tests/ui/nll/issue-27282-mutation-in-guard.stderr index 0b5d723172c..f73e4aaa489 100644 --- a/tests/ui/nll/issue-27282-mutation-in-guard.stderr +++ b/tests/ui/nll/issue-27282-mutation-in-guard.stderr @@ -7,6 +7,10 @@ LL | (|| { let bar = foo; bar.take() })(); | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let bar = foo.clone(); bar.take() })(); + | ++++++++ error[E0507]: cannot move out of `foo` in pattern guard --> $DIR/issue-27282-mutation-in-guard.rs:20:18 @@ -17,6 +21,10 @@ LL | (|| { let bar = foo; bar.take() })(); | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let bar = foo.clone(); bar.take() })(); + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr index f7a525ee9b0..e3f44467550 100644 --- a/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr +++ b/tests/ui/nll/issue-42574-diagnostic-in-nested-closure.stderr @@ -11,6 +11,8 @@ LL | || doit(data); error[E0597]: `data` does not live long enough --> $DIR/issue-42574-diagnostic-in-nested-closure.rs:6:13 | +LL | fn doit(data: &'static mut ()) { + | ---- binding `data` declared here LL | || doit(data); | -- -----^^^^- | | | | diff --git a/tests/ui/nll/issue-48623-coroutine.rs b/tests/ui/nll/issue-48623-coroutine.rs index 3a4a27855d9..63348a2047c 100644 --- a/tests/ui/nll/issue-48623-coroutine.rs +++ b/tests/ui/nll/issue-48623-coroutine.rs @@ -12,7 +12,7 @@ impl Drop for WithDrop { fn reborrow_from_coroutine(r: &mut ()) { let d = WithDrop; - move || { d; yield; &mut *r }; //~ WARN unused coroutine that must be used + #[coroutine] move || { d; yield; &mut *r }; //~ WARN unused coroutine that must be used } fn main() {} diff --git a/tests/ui/nll/issue-48623-coroutine.stderr b/tests/ui/nll/issue-48623-coroutine.stderr index 1b7b1735aac..4e4cd28ef2a 100644 --- a/tests/ui/nll/issue-48623-coroutine.stderr +++ b/tests/ui/nll/issue-48623-coroutine.stderr @@ -1,8 +1,8 @@ warning: unused coroutine that must be used - --> $DIR/issue-48623-coroutine.rs:15:5 + --> $DIR/issue-48623-coroutine.rs:15:18 | -LL | move || { d; yield; &mut *r }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[coroutine] move || { d; yield; &mut *r }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: coroutines are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/tests/ui/nll/issue-55850.rs b/tests/ui/nll/issue-55850.rs index fc873af9463..bf1e2e7caef 100644 --- a/tests/ui/nll/issue-55850.rs +++ b/tests/ui/nll/issue-55850.rs @@ -23,7 +23,7 @@ where } fn bug<'a>() -> impl Iterator<Item = &'a str> { - GenIter(move || { + GenIter(#[coroutine] move || { let mut s = String::new(); yield &s[..] //~ ERROR cannot yield value referencing local variable `s` [E0515] //~| ERROR borrow may still be in use when coroutine yields diff --git a/tests/ui/nll/match-guards-always-borrow.fixed b/tests/ui/nll/match-guards-always-borrow.fixed new file mode 100644 index 00000000000..56e743bf196 --- /dev/null +++ b/tests/ui/nll/match-guards-always-borrow.fixed @@ -0,0 +1,66 @@ +#![feature(if_let_guard)] +#![allow(unused_mut)] +//@ run-rustfix + +// Here is arielb1's basic example from rust-lang/rust#27282 +// that AST borrowck is flummoxed by: + +fn should_reject_destructive_mutate_in_guard() { + match Some(&4) { + None => {}, + ref mut foo if { + (|| { let mut bar = foo.clone(); bar.take() })(); + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] + false } => { }, + Some(s) => std::process::exit(*s), + } + + match Some(&4) { + None => {}, + ref mut foo if let Some(()) = { + (|| { let mut bar = foo.clone(); bar.take() })(); + //~^ ERROR cannot move out of `foo` in pattern guard [E0507] + None } => { }, + Some(s) => std::process::exit(*s), + } +} + +// Here below is a case that needs to keep working: we only use the +// binding via immutable-borrow in the guard, and we mutate in the arm +// body. +fn allow_mutate_in_arm_body() { + match Some(&4) { + None => {}, + ref mut foo if foo.is_some() => { foo.take(); () } + Some(s) => std::process::exit(*s), + } + + match Some(&4) { + None => {}, + ref mut foo if let Some(_) = foo => { foo.take(); () } + Some(s) => std::process::exit(*s), + } +} + +// Here below is a case that needs to keep working: we only use the +// binding via immutable-borrow in the guard, and we move into the arm +// body. +fn allow_move_into_arm_body() { + match Some(&4) { + None => {}, + mut foo if foo.is_some() => { foo.unwrap(); () } + Some(s) => std::process::exit(*s), + } + + match Some(&4) { + None => {}, + mut foo if let Some(_) = foo => { foo.unwrap(); () } + Some(s) => std::process::exit(*s), + } +} + +fn main() { + should_reject_destructive_mutate_in_guard(); + allow_mutate_in_arm_body(); + allow_move_into_arm_body(); +} diff --git a/tests/ui/nll/match-guards-always-borrow.rs b/tests/ui/nll/match-guards-always-borrow.rs index ff63cc09273..927d55c42a6 100644 --- a/tests/ui/nll/match-guards-always-borrow.rs +++ b/tests/ui/nll/match-guards-always-borrow.rs @@ -1,4 +1,6 @@ #![feature(if_let_guard)] +#![allow(unused_mut)] +//@ run-rustfix // Here is arielb1's basic example from rust-lang/rust#27282 // that AST borrowck is flummoxed by: @@ -7,7 +9,7 @@ fn should_reject_destructive_mutate_in_guard() { match Some(&4) { None => {}, ref mut foo if { - (|| { let bar = foo; bar.take() })(); + (|| { let mut bar = foo; bar.take() })(); //~^ ERROR cannot move out of `foo` in pattern guard [E0507] false } => { }, Some(s) => std::process::exit(*s), @@ -16,7 +18,7 @@ fn should_reject_destructive_mutate_in_guard() { match Some(&4) { None => {}, ref mut foo if let Some(()) = { - (|| { let bar = foo; bar.take() })(); + (|| { let mut bar = foo; bar.take() })(); //~^ ERROR cannot move out of `foo` in pattern guard [E0507] None } => { }, Some(s) => std::process::exit(*s), diff --git a/tests/ui/nll/match-guards-always-borrow.stderr b/tests/ui/nll/match-guards-always-borrow.stderr index afd853c403e..bb0c5bd4c97 100644 --- a/tests/ui/nll/match-guards-always-borrow.stderr +++ b/tests/ui/nll/match-guards-always-borrow.stderr @@ -1,22 +1,30 @@ error[E0507]: cannot move out of `foo` in pattern guard - --> $DIR/match-guards-always-borrow.rs:10:14 + --> $DIR/match-guards-always-borrow.rs:12:14 | -LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait +LL | (|| { let mut bar = foo; bar.take() })(); + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let mut bar = foo.clone(); bar.take() })(); + | ++++++++ error[E0507]: cannot move out of `foo` in pattern guard - --> $DIR/match-guards-always-borrow.rs:19:14 + --> $DIR/match-guards-always-borrow.rs:21:14 | -LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait +LL | (|| { let mut bar = foo; bar.take() })(); + | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard +help: consider cloning the value if the performance cost is acceptable + | +LL | (|| { let mut bar = foo.clone(); bar.take() })(); + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr index 842ecaf524b..d1384121379 100644 --- a/tests/ui/nll/move-errors.stderr +++ b/tests/ui/nll/move-errors.stderr @@ -8,7 +8,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let b = *a; + | -- you could clone this value help: consider removing the dereference here | LL - let b = *a; @@ -28,7 +31,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let b = a[0]; + | ---- you could clone this value help: consider borrowing here | LL | let b = &a[0]; @@ -44,7 +50,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let s = **r; + | --- you could clone this value help: consider removing the dereference here | LL - let s = **r; @@ -61,7 +70,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let s = *r; + | -- you could clone this value help: consider removing the dereference here | LL - let s = *r; @@ -81,7 +93,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = [A("".to_string())][0]; + | ---------------------- you could clone this value help: consider borrowing here | LL | let a = &[A("".to_string())][0]; @@ -126,7 +141,10 @@ note: if `A` implemented `Clone`, you could clone the value --> $DIR/move-errors.rs:1:1 | LL | struct A(String); - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | b = *a; + | -- you could clone this value error[E0508]: cannot move out of type `[B; 1]`, a non-copy array --> $DIR/move-errors.rs:74:11 diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 5227ca8ec17..1d086c658df 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18 | +LL | let a = (); + | - binding `a` declared here LL | let b = |_| &a; | --- -^ | | || diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 5227ca8ec17..1d086c658df 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18 | +LL | let a = (); + | - binding `a` declared here LL | let b = |_| &a; | --- -^ | | || diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr index c7c08c948ab..c42ea0172cf 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-1.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr @@ -33,7 +33,9 @@ error[E0597]: `a` does not live long enough | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here -... +LL | let a = 22; + | - binding `a` declared here +LL | let b = 44; LL | let _closure = || { | -- value captured here LL | let c = 66; diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr index b7861a3bd06..287337c7d52 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-2.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr @@ -34,7 +34,9 @@ error[E0597]: `b` does not live long enough | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here -... +LL | let a = 22; +LL | let b = 44; + | - binding `b` declared here LL | let _closure = || { | -- value captured here LL | let c = 66; diff --git a/tests/ui/packed/packed-struct-drop-aligned.rs b/tests/ui/packed/packed-struct-drop-aligned.rs index 037b8cb78b7..ba3dcb10c61 100644 --- a/tests/ui/packed/packed-struct-drop-aligned.rs +++ b/tests/ui/packed/packed-struct-drop-aligned.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(coroutine_trait)] use std::cell::Cell; use std::mem; @@ -7,13 +7,12 @@ use std::ops::Coroutine; use std::pin::Pin; struct Aligned<'a> { - drop_count: &'a Cell<usize> + drop_count: &'a Cell<usize>, } #[inline(never)] fn check_align(ptr: *const Aligned) { - assert_eq!(ptr as usize % mem::align_of::<Aligned>(), - 0); + assert_eq!(ptr as usize % mem::align_of::<Aligned>(), 0); } impl<'a> Drop for Aligned<'a> { @@ -39,7 +38,8 @@ fn main() { assert_eq!(drop_count.get(), 2); let drop_count = &Cell::new(0); - let mut g = || { + let mut g = #[coroutine] + || { let mut p = Packed(NotCopy(0), Aligned { drop_count }); let _ = &p; p.1 = Aligned { drop_count }; diff --git a/tests/ui/parser/bad-let-else-statement.rs b/tests/ui/parser/bad-let-else-statement.rs index c3126a493e5..de41a07568f 100644 --- a/tests/ui/parser/bad-let-else-statement.rs +++ b/tests/ui/parser/bad-let-else-statement.rs @@ -1,4 +1,3 @@ -#![feature(inline_const)] #![feature(yeet_expr)] #![allow(incomplete_features)] // Necessary for now, while explicit_tail_calls is incomplete #![feature(explicit_tail_calls)] diff --git a/tests/ui/parser/bad-let-else-statement.stderr b/tests/ui/parser/bad-let-else-statement.stderr index 12df8f849ab..3f7e176b3e3 100644 --- a/tests/ui/parser/bad-let-else-statement.stderr +++ b/tests/ui/parser/bad-let-else-statement.stderr @@ -1,5 +1,5 @@ error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:10:5 + --> $DIR/bad-let-else-statement.rs:9:5 | LL | } else { | ^ @@ -13,7 +13,7 @@ LL ~ }) else { | error: `for...else` loops are not supported - --> $DIR/bad-let-else-statement.rs:19:7 + --> $DIR/bad-let-else-statement.rs:18:7 | LL | let foo = for i in 1..2 { | --- `else` is attached to this loop @@ -28,7 +28,7 @@ LL | | }; = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:31:5 + --> $DIR/bad-let-else-statement.rs:30:5 | LL | } else { | ^ @@ -43,7 +43,7 @@ LL ~ }) else { | error: `loop...else` loops are not supported - --> $DIR/bad-let-else-statement.rs:40:7 + --> $DIR/bad-let-else-statement.rs:39:7 | LL | let foo = loop { | ---- `else` is attached to this loop @@ -58,7 +58,7 @@ LL | | }; = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:51:5 + --> $DIR/bad-let-else-statement.rs:50:5 | LL | } else { | ^ @@ -73,7 +73,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:62:5 + --> $DIR/bad-let-else-statement.rs:61:5 | LL | } else { | ^ @@ -87,7 +87,7 @@ LL ~ }) else { | error: `while...else` loops are not supported - --> $DIR/bad-let-else-statement.rs:71:7 + --> $DIR/bad-let-else-statement.rs:70:7 | LL | let foo = while false { | ----- `else` is attached to this loop @@ -102,7 +102,7 @@ LL | | }; = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:81:5 + --> $DIR/bad-let-else-statement.rs:80:5 | LL | } else { | ^ @@ -116,7 +116,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:91:5 + --> $DIR/bad-let-else-statement.rs:90:5 | LL | } else { | ^ @@ -130,7 +130,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:102:5 + --> $DIR/bad-let-else-statement.rs:101:5 | LL | } else { | ^ @@ -144,7 +144,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:112:5 + --> $DIR/bad-let-else-statement.rs:111:5 | LL | } else { | ^ @@ -158,7 +158,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:122:5 + --> $DIR/bad-let-else-statement.rs:121:5 | LL | } else { | ^ @@ -172,7 +172,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:132:5 + --> $DIR/bad-let-else-statement.rs:131:5 | LL | } else { | ^ @@ -186,7 +186,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:142:5 + --> $DIR/bad-let-else-statement.rs:141:5 | LL | } else { | ^ @@ -200,7 +200,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:152:5 + --> $DIR/bad-let-else-statement.rs:151:5 | LL | } else { | ^ @@ -214,7 +214,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:162:5 + --> $DIR/bad-let-else-statement.rs:161:5 | LL | } else { | ^ @@ -228,7 +228,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:172:5 + --> $DIR/bad-let-else-statement.rs:171:5 | LL | } else { | ^ @@ -242,7 +242,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:182:31 + --> $DIR/bad-let-else-statement.rs:181:31 | LL | let bad = format_args! {""} else { return; }; | ^ @@ -253,7 +253,7 @@ LL | let bad = format_args! ("") else { return; }; | ~ ~ error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:199:25 + --> $DIR/bad-let-else-statement.rs:198:25 | LL | let x = a! {} else { return; }; | ^ @@ -268,7 +268,7 @@ LL | let x = a! () else { return; }; | ~~ warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:7:5 + --> $DIR/bad-let-else-statement.rs:6:5 | LL | / let foo = { LL | | @@ -281,7 +281,7 @@ LL | | } else { = note: `#[warn(irrefutable_let_patterns)]` on by default warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:26:5 + --> $DIR/bad-let-else-statement.rs:25:5 | LL | / let foo = if true { LL | | @@ -295,7 +295,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:47:5 + --> $DIR/bad-let-else-statement.rs:46:5 | LL | / let foo = match true { LL | | @@ -308,7 +308,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:59:5 + --> $DIR/bad-let-else-statement.rs:58:5 | LL | / let foo = X { LL | | @@ -320,7 +320,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:78:5 + --> $DIR/bad-let-else-statement.rs:77:5 | LL | / let foo = const { LL | | @@ -332,7 +332,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:88:5 + --> $DIR/bad-let-else-statement.rs:87:5 | LL | / let foo = &{ LL | | @@ -344,7 +344,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:99:5 + --> $DIR/bad-let-else-statement.rs:98:5 | LL | / let foo = bar = { LL | | @@ -356,7 +356,7 @@ LL | | } else { = help: consider removing the `else` clause error[E0384]: cannot assign twice to immutable variable `bar` - --> $DIR/bad-let-else-statement.rs:99:15 + --> $DIR/bad-let-else-statement.rs:98:15 | LL | let bar = 0; | --- @@ -371,7 +371,7 @@ LL | | } else { | |_____^ cannot assign twice to immutable variable warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:109:5 + --> $DIR/bad-let-else-statement.rs:108:5 | LL | / let foo = 1 + { LL | | @@ -383,7 +383,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:119:5 + --> $DIR/bad-let-else-statement.rs:118:5 | LL | / let foo = 1..{ LL | | @@ -395,7 +395,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:129:5 + --> $DIR/bad-let-else-statement.rs:128:5 | LL | / let foo = return { LL | | @@ -407,7 +407,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:139:5 + --> $DIR/bad-let-else-statement.rs:138:5 | LL | / let foo = -{ LL | | @@ -419,7 +419,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:149:5 + --> $DIR/bad-let-else-statement.rs:148:5 | LL | / let foo = do yeet { LL | | @@ -431,7 +431,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:159:5 + --> $DIR/bad-let-else-statement.rs:158:5 | LL | / let foo = become { LL | | @@ -443,7 +443,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:169:5 + --> $DIR/bad-let-else-statement.rs:168:5 | LL | / let foo = |x: i32| { LL | | @@ -455,7 +455,7 @@ LL | | } else { = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:179:5 + --> $DIR/bad-let-else-statement.rs:178:5 | LL | let ok = format_args!("") else { return; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -464,7 +464,7 @@ LL | let ok = format_args!("") else { return; }; = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:182:5 + --> $DIR/bad-let-else-statement.rs:181:5 | LL | let bad = format_args! {""} else { return; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -473,7 +473,7 @@ LL | let bad = format_args! {""} else { return; }; = help: consider removing the `else` clause warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:189:19 + --> $DIR/bad-let-else-statement.rs:188:19 | LL | () => { {} } | ___________________^ @@ -493,7 +493,7 @@ LL | b!(1); b!(2); = note: this warning originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:189:19 + --> $DIR/bad-let-else-statement.rs:188:19 | LL | () => { {} } | ___________________^ diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 00964cb8336..e925fe78f33 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -337,7 +337,10 @@ note: if `U` implemented `Clone`, you could clone the value --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5 | LL | struct U; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | - you could clone this value error[E0507]: cannot move out of `b` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 @@ -350,7 +353,10 @@ note: if `U` implemented `Clone`, you could clone the value --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5 | LL | struct U; - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | - you could clone this value = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0507]: cannot move out of `a` in pattern guard diff --git a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr index e25c30cd492..41d1b79d97d 100644 --- a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr +++ b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr @@ -70,13 +70,19 @@ error[E0384]: cannot assign twice to immutable variable `a` --> $DIR/pat-at-same-name-both.rs:13:15 | LL | Ok(a @ b @ a) - | - - | | - | first assignment to `a` - | help: consider making this binding mutable: `mut a` + | - first assignment to `a` LL | LL | | Err(a @ b @ a) | ^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | Ok(a @ b @ mut a) + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | Ok(a @ b @ ref mut a) + | ~~~~~~~~~ error: aborting due to 12 previous errors diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index a033cc0655e..1e7b990b67c 100644 --- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -15,12 +15,18 @@ error[E0384]: cannot assign twice to immutable variable `_x1` --> $DIR/borrowck-move-ref-pattern.rs:9:5 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; - | --- - | | - | first assignment to `_x1` - | help: consider making this binding mutable: `mut _x1` + | --- first assignment to `_x1` LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let [ref _x0_hold, mut _x1, ref xs_hold @ ..] = arr; + | ~~~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let [ref _x0_hold, ref mut _x1, ref xs_hold @ ..] = arr; + | ~~~~~~~~~~~ error[E0505]: cannot move out of `arr[..]` because it is borrowed --> $DIR/borrowck-move-ref-pattern.rs:11:10 @@ -73,12 +79,18 @@ error[E0384]: cannot assign twice to immutable variable `_x1` --> $DIR/borrowck-move-ref-pattern.rs:23:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; - | --- - | | - | first assignment to `_x1` - | help: consider making this binding mutable: `mut _x1` + | --- first assignment to `_x1` LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let (ref _x0, mut _x1, ref _x2, ..) = tup; + | ~~~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let (ref _x0, ref mut _x1, ref _x2, ..) = tup; + | ~~~~~~~~~~~ error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable --> $DIR/borrowck-move-ref-pattern.rs:24:20 diff --git a/tests/ui/pattern/mut-ref-mut-2021.stderr b/tests/ui/pattern/mut-ref-mut-2021.stderr index eb31ffa0e30..ebf7979edb6 100644 --- a/tests/ui/pattern/mut-ref-mut-2021.stderr +++ b/tests/ui/pattern/mut-ref-mut-2021.stderr @@ -2,12 +2,18 @@ error[E0384]: cannot assign twice to immutable variable `a` --> $DIR/mut-ref-mut-2021.rs:9:5 | LL | let Foo(a) = Foo(0); - | - - | | - | first assignment to `a` - | help: consider making this binding mutable: `mut a` + | - first assignment to `a` LL | a = 42; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let Foo(mut a) = Foo(0); + | ~~~~~ +help: to modify the original value, take a borrow instead + | +LL | let Foo(ref mut a) = Foo(0); + | ~~~~~~~~~ error[E0384]: cannot assign twice to immutable variable `a` --> $DIR/mut-ref-mut-2021.rs:15:5 diff --git a/tests/ui/polymorphization/coroutine.rs b/tests/ui/polymorphization/coroutine.rs index a989947f787..22ceadfb194 100644 --- a/tests/ui/polymorphization/coroutine.rs +++ b/tests/ui/polymorphization/coroutine.rs @@ -32,6 +32,7 @@ where #[rustc_polymorphize_error] pub fn unused_type<T>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { + #[coroutine] || { //~^ ERROR item has unused generic parameters yield 1; @@ -41,6 +42,7 @@ pub fn unused_type<T>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin #[rustc_polymorphize_error] pub fn used_type_in_yield<Y: Default>() -> impl Coroutine<(), Yield = Y, Return = u32> + Unpin { + #[coroutine] || { yield Y::default(); 2 @@ -49,6 +51,7 @@ pub fn used_type_in_yield<Y: Default>() -> impl Coroutine<(), Yield = Y, Return #[rustc_polymorphize_error] pub fn used_type_in_return<R: Default>() -> impl Coroutine<(), Yield = u32, Return = R> + Unpin { + #[coroutine] || { yield 3; R::default() @@ -57,6 +60,7 @@ pub fn used_type_in_return<R: Default>() -> impl Coroutine<(), Yield = u32, Retu #[rustc_polymorphize_error] pub fn unused_const<const T: u32>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { + #[coroutine] || { //~^ ERROR item has unused generic parameters yield 1; @@ -67,6 +71,7 @@ pub fn unused_const<const T: u32>() -> impl Coroutine<(), Yield = u32, Return = #[rustc_polymorphize_error] pub fn used_const_in_yield<const Y: u32>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { + #[coroutine] || { yield Y; 2 @@ -76,6 +81,7 @@ pub fn used_const_in_yield<const Y: u32>() -> impl Coroutine<(), Yield = u32, Re #[rustc_polymorphize_error] pub fn used_const_in_return<const R: u32>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { + #[coroutine] || { yield 4; R diff --git a/tests/ui/polymorphization/coroutine.stderr b/tests/ui/polymorphization/coroutine.stderr index 67b55a59883..07e29184226 100644 --- a/tests/ui/polymorphization/coroutine.stderr +++ b/tests/ui/polymorphization/coroutine.stderr @@ -8,18 +8,20 @@ LL | #![feature(generic_const_exprs, coroutines, coroutine_trait, rustc_attrs)] = note: `#[warn(incomplete_features)]` on by default error: item has unused generic parameters - --> $DIR/coroutine.rs:35:5 + --> $DIR/coroutine.rs:36:5 | LL | pub fn unused_type<T>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { | - generic parameter `T` is unused +LL | #[coroutine] LL | || { | ^^ error: item has unused generic parameters - --> $DIR/coroutine.rs:60:5 + --> $DIR/coroutine.rs:64:5 | LL | pub fn unused_const<const T: u32>() -> impl Coroutine<(), Yield = u32, Return = u32> + Unpin { | ------------ generic parameter `T` is unused +LL | #[coroutine] LL | || { | ^^ diff --git a/tests/ui/print_type_sizes/coroutine.rs b/tests/ui/print_type_sizes/coroutine.rs index 61488c51f05..15335788789 100644 --- a/tests/ui/print_type_sizes/coroutine.rs +++ b/tests/ui/print_type_sizes/coroutine.rs @@ -7,6 +7,7 @@ use std::ops::Coroutine; fn coroutine<const C: usize>(array: [u8; C]) -> impl Coroutine<Yield = (), Return = ()> { + #[coroutine] move |()| { yield (); let _ = array; diff --git a/tests/ui/print_type_sizes/coroutine.stdout b/tests/ui/print_type_sizes/coroutine.stdout index 5d51339558c..339bbddfc2a 100644 --- a/tests/ui/print_type_sizes/coroutine.stdout +++ b/tests/ui/print_type_sizes/coroutine.stdout @@ -1,4 +1,4 @@ -print-type-size type: `{coroutine@$DIR/coroutine.rs:10:5: 10:14}`: 8193 bytes, alignment: 1 bytes +print-type-size type: `{coroutine@$DIR/coroutine.rs:11:5: 11:14}`: 8193 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 8192 bytes print-type-size upvar `.array`: 8192 bytes diff --git a/tests/ui/print_type_sizes/coroutine_discr_placement.rs b/tests/ui/print_type_sizes/coroutine_discr_placement.rs index 4b9f67a7999..d97b0b28ed0 100644 --- a/tests/ui/print_type_sizes/coroutine_discr_placement.rs +++ b/tests/ui/print_type_sizes/coroutine_discr_placement.rs @@ -5,11 +5,12 @@ // Tests a coroutine that has its discriminant as the *final* field. // Avoid emitting panic handlers, like the rest of these tests... -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![allow(dropping_copy_types)] pub fn foo() { - let a = || { + let a = #[coroutine] + || { { let w: i32 = 4; yield; diff --git a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout index 71a7f3c6381..4ce1ce46f6e 100644 --- a/tests/ui/print_type_sizes/coroutine_discr_placement.stdout +++ b/tests/ui/print_type_sizes/coroutine_discr_placement.stdout @@ -1,4 +1,4 @@ -print-type-size type: `{coroutine@$DIR/coroutine_discr_placement.rs:12:13: 12:15}`: 8 bytes, alignment: 4 bytes +print-type-size type: `{coroutine@$DIR/coroutine_discr_placement.rs:13:5: 13:7}`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Suspend0`: 7 bytes diff --git a/tests/ui/regions/regions-addr-of-upvar-self.stderr b/tests/ui/regions/regions-addr-of-upvar-self.stderr index c16a6f8585b..3a028cc9e21 100644 --- a/tests/ui/regions/regions-addr-of-upvar-self.stderr +++ b/tests/ui/regions/regions-addr-of-upvar-self.stderr @@ -20,6 +20,8 @@ LL | let p: &'static mut usize = &mut self.food; error[E0597]: `self` does not live long enough --> $DIR/regions-addr-of-upvar-self.rs:8:46 | +LL | pub fn chase_cat(&mut self) { + | --------- binding `self` declared here LL | let _f = || { | -- value captured here LL | let p: &'static mut usize = &mut self.food; diff --git a/tests/ui/regions/regions-nested-fns-2.stderr b/tests/ui/regions/regions-nested-fns-2.stderr index 254497639a1..02359fe1213 100644 --- a/tests/ui/regions/regions-nested-fns-2.stderr +++ b/tests/ui/regions/regions-nested-fns-2.stderr @@ -1,6 +1,9 @@ error[E0597]: `y` does not live long enough --> $DIR/regions-nested-fns-2.rs:7:25 | +LL | let y = 3; + | - binding `y` declared here +LL | ignore( LL | |z| { | --- value captured here LL | if false { &y } else { z } diff --git a/tests/ui/regions/regions-nested-fns.stderr b/tests/ui/regions/regions-nested-fns.stderr index ee43f9fa572..23b3f78dd4e 100644 --- a/tests/ui/regions/regions-nested-fns.stderr +++ b/tests/ui/regions/regions-nested-fns.stderr @@ -27,6 +27,9 @@ LL | } error[E0597]: `y` does not live long enough --> $DIR/regions-nested-fns.rs:10:15 | +LL | let y = 3; + | - binding `y` declared here +... LL | ignore::<Box<dyn for<'z> FnMut(&'z isize)>>(Box::new(|z| { | --- value captured here LL | ay = x; diff --git a/tests/ui/regions/regions-steal-closure.stderr b/tests/ui/regions/regions-steal-closure.stderr index 9324eb892a6..50068b32fa3 100644 --- a/tests/ui/regions/regions-steal-closure.stderr +++ b/tests/ui/regions/regions-steal-closure.stderr @@ -4,6 +4,7 @@ error[E0597]: `i` does not live long enough LL | let mut cl_box = { | ---------- borrow later stored here LL | let mut i = 3; + | ----- binding `i` declared here LL | box_it(Box::new(|| i += 1)) | -- ^ borrowed value does not live long enough | | diff --git a/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs b/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs index d5c8a529e1e..9fdceefbf9b 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/tracked-closure.rs @@ -113,7 +113,7 @@ fn dyn_coroutine( } fn test_coroutine() { - let coroutine = #[track_caller] |arg: String| { + let coroutine = #[track_caller] #[coroutine] |arg: String| { yield ("first", arg.clone(), Location::caller()); yield ("second", arg.clone(), Location::caller()); }; @@ -136,7 +136,7 @@ fn test_coroutine() { assert_eq!(mono_loc.line(), mono_line); assert_eq!(mono_loc.column(), 42); - let non_tracked_coroutine = || { yield Location::caller(); }; + let non_tracked_coroutine = #[coroutine] || { yield Location::caller(); }; let non_tracked_line = line!() - 1; // This is the line of the coroutine, not its caller let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) { CoroutineState::Yielded(val) => val, @@ -144,7 +144,7 @@ fn test_coroutine() { }; assert_eq!(non_tracked_loc.file(), file!()); assert_eq!(non_tracked_loc.line(), non_tracked_line); - assert_eq!(non_tracked_loc.column(), 44); + assert_eq!(non_tracked_loc.column(), 57); } diff --git a/tests/ui/sanitizer/cfi-coroutine.rs b/tests/ui/sanitizer/cfi-coroutine.rs index 5c6a489a7e8..ad994fcf737 100644 --- a/tests/ui/sanitizer/cfi-coroutine.rs +++ b/tests/ui/sanitizer/cfi-coroutine.rs @@ -14,7 +14,7 @@ //@ compile-flags: --test -Z unstable-options //@ run-pass -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] #![feature(coroutine_trait)] #![feature(noop_waker)] #![feature(gen_blocks)] @@ -27,7 +27,7 @@ use std::async_iter::AsyncIterator; #[test] fn general_coroutine() { - let mut coro = |x: i32| { + let mut coro = #[coroutine] |x: i32| { yield x; "done" }; diff --git a/tests/ui/simd/const-err-trumps-simd-err.rs b/tests/ui/simd/const-err-trumps-simd-err.rs index 06a747273ab..fda04434451 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.rs +++ b/tests/ui/simd/const-err-trumps-simd-err.rs @@ -5,7 +5,7 @@ #![feature(generic_arg_infer)] #![feature(core_intrinsics)] #![feature(repr_simd)] -#![feature(inline_const)] + use std::intrinsics::simd::*; #[repr(simd)] diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs index 73003087819..a81d8ebdf50 100644 --- a/tests/ui/simd/intrinsic/generic-elements-pass.rs +++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs @@ -2,7 +2,6 @@ //@ ignore-emscripten FIXME(#45351) hits an LLVM assert #![feature(repr_simd, intrinsics)] -#![feature(inline_const)] #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] diff --git a/tests/ui/span/send-is-not-static-ensures-scoping.stderr b/tests/ui/span/send-is-not-static-ensures-scoping.stderr index bae0befcaca..c15547e8412 100644 --- a/tests/ui/span/send-is-not-static-ensures-scoping.stderr +++ b/tests/ui/span/send-is-not-static-ensures-scoping.stderr @@ -16,6 +16,9 @@ error[E0597]: `y` does not live long enough | LL | let bad = { | --- borrow later stored here +LL | let x = 1; +LL | let y = &x; + | - binding `y` declared here ... LL | scoped(|| { | -- value captured here diff --git a/tests/ui/suggestions/issue-84973-blacklist.rs b/tests/ui/suggestions/issue-84973-blacklist.rs index 6a35d779c1c..edc0637636b 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.rs +++ b/tests/ui/suggestions/issue-84973-blacklist.rs @@ -14,7 +14,7 @@ struct S; fn main() { f_copy("".to_string()); //~ ERROR: the trait bound `String: Copy` is not satisfied [E0277] f_clone(S); //~ ERROR: the trait bound `S: Clone` is not satisfied [E0277] - f_unpin(static || { yield; }); + f_unpin(#[coroutine] static || { yield; }); //~^ ERROR: cannot be unpinned [E0277] let cl = || (); diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr index 33338228328..4fd063e4692 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.stderr +++ b/tests/ui/suggestions/issue-84973-blacklist.stderr @@ -36,11 +36,11 @@ LL + #[derive(Clone)] LL | struct S; | -error[E0277]: `{static coroutine@$DIR/issue-84973-blacklist.rs:17:13: 17:22}` cannot be unpinned - --> $DIR/issue-84973-blacklist.rs:17:13 +error[E0277]: `{static coroutine@$DIR/issue-84973-blacklist.rs:17:26: 17:35}` cannot be unpinned + --> $DIR/issue-84973-blacklist.rs:17:26 | -LL | f_unpin(static || { yield; }); - | ------- ^^^^^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/issue-84973-blacklist.rs:17:13: 17:22}` +LL | f_unpin(#[coroutine] static || { yield; }); + | ------- ^^^^^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `{static coroutine@$DIR/issue-84973-blacklist.rs:17:26: 17:35}` | | | required by a bound introduced by this call | diff --git a/tests/ui/suggestions/option-content-move2.rs b/tests/ui/suggestions/option-content-move2.rs index 88e8a5b7aee..b0104d9bafb 100644 --- a/tests/ui/suggestions/option-content-move2.rs +++ b/tests/ui/suggestions/option-content-move2.rs @@ -1,8 +1,10 @@ struct NotCopyable; +#[derive(Clone)] +struct NotCopyableButCloneable; fn func<F: FnMut() -> H, H: FnMut()>(_: F) {} -fn parse() { +fn foo() { let mut var = None; func(|| { // Shouldn't suggest `move ||.as_ref()` here @@ -12,5 +14,15 @@ fn parse() { } }); } +fn bar() { + let mut var = None; + func(|| { + // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here + move || { + //~^ ERROR: cannot move out of `var` + var = Some(NotCopyableButCloneable); + } + }); +} fn main() {} diff --git a/tests/ui/suggestions/option-content-move2.stderr b/tests/ui/suggestions/option-content-move2.stderr index 0297c031ecc..be97cba17b9 100644 --- a/tests/ui/suggestions/option-content-move2.stderr +++ b/tests/ui/suggestions/option-content-move2.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure - --> $DIR/option-content-move2.rs:9:9 + --> $DIR/option-content-move2.rs:11:9 | LL | let mut var = None; | ------- captured outer variable @@ -15,6 +15,23 @@ LL | var = Some(NotCopyable); | variable moved due to use in closure | move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait -error: aborting due to 1 previous error +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move2.rs:21:9 + | +LL | let mut var = None; + | ------- captured outer variable +LL | func(|| { + | -- captured by this `FnMut` closure +LL | // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here +LL | move || { + | ^^^^^^^ `var` is moved here +LL | +LL | var = Some(NotCopyableButCloneable); + | --- + | | + | variable moved due to use in closure + | move occurs because `var` has type `Option<NotCopyableButCloneable>`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/suggestions/option-content-move3.rs b/tests/ui/suggestions/option-content-move3.rs new file mode 100644 index 00000000000..a245309d97f --- /dev/null +++ b/tests/ui/suggestions/option-content-move3.rs @@ -0,0 +1,30 @@ +#[derive(Debug)] +struct NotCopyable; +#[derive(Debug, Clone)] +struct NotCopyableButCloneable; + +fn func<F: FnMut() -> H, H: FnMut()>(_: F) {} + +fn foo() { + let var = NotCopyable; + func(|| { + // Shouldn't suggest `move ||.as_ref()` here + move || { //~ ERROR cannot move out of `var` + let x = var; //~ ERROR cannot move out of `var` + println!("{x:?}"); + } + }); +} + +fn bar() { + let var = NotCopyableButCloneable; + func(|| { + // Shouldn't suggest `move ||.as_ref()` here + move || { //~ ERROR cannot move out of `var` + let x = var; //~ ERROR cannot move out of `var` + println!("{x:?}"); + } + }); +} + +fn main() {} diff --git a/tests/ui/suggestions/option-content-move3.stderr b/tests/ui/suggestions/option-content-move3.stderr new file mode 100644 index 00000000000..a20dcce1ee3 --- /dev/null +++ b/tests/ui/suggestions/option-content-move3.stderr @@ -0,0 +1,95 @@ +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move3.rs:13:21 + | +LL | let var = NotCopyable; + | --- captured outer variable +... +LL | move || { + | ------- captured by this `FnMut` closure +LL | let x = var; + | ^^^ move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait + | +note: if `NotCopyable` implemented `Clone`, you could clone the value + --> $DIR/option-content-move3.rs:2:1 + | +LL | struct NotCopyable; + | ^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = var; + | --- you could clone this value +help: consider borrowing here + | +LL | let x = &var; + | + + +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move3.rs:12:9 + | +LL | let var = NotCopyable; + | --- captured outer variable +LL | func(|| { + | -- captured by this `FnMut` closure +LL | // Shouldn't suggest `move ||.as_ref()` here +LL | move || { + | ^^^^^^^ `var` is moved here +LL | let x = var; + | --- + | | + | variable moved due to use in closure + | move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait + | +note: if `NotCopyable` implemented `Clone`, you could clone the value + --> $DIR/option-content-move3.rs:2:1 + | +LL | struct NotCopyable; + | ^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = var; + | --- you could clone this value + +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move3.rs:24:21 + | +LL | let var = NotCopyableButCloneable; + | --- captured outer variable +... +LL | move || { + | ------- captured by this `FnMut` closure +LL | let x = var; + | ^^^ move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let x = &var; + | + + +error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure + --> $DIR/option-content-move3.rs:23:9 + | +LL | let var = NotCopyableButCloneable; + | --- captured outer variable +LL | func(|| { + | -- captured by this `FnMut` closure +LL | // Shouldn't suggest `move ||.as_ref()` here +LL | move || { + | ^^^^^^^ `var` is moved here +LL | let x = var; + | --- + | | + | variable moved due to use in closure + | move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait + | +help: clone the value before moving it into the closure + | +LL ~ { +LL + let value = var.clone(); +LL ~ move || { +LL ~ let x = value; +LL | println!("{x:?}"); +LL ~ } +LL + } + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/suggestions/suggest-split-at-mut.rs b/tests/ui/suggestions/suggest-split-at-mut.rs index d294c20b824..61704abbd36 100644 --- a/tests/ui/suggestions/suggest-split-at-mut.rs +++ b/tests/ui/suggestions/suggest-split-at-mut.rs @@ -1,4 +1,4 @@ -fn main() { +fn foo() { let mut foo = [1, 2, 3, 4]; let a = &mut foo[2]; let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time @@ -6,3 +6,57 @@ fn main() { *b = 6; println!("{:?} {:?}", a, b); } + +fn bar() { + let mut foo = [1,2,3,4]; + let a = &mut foo[..2]; + let b = &mut foo[2..]; //~ ERROR cannot borrow `foo` as mutable more than once at a time + a[0] = 5; + b[0] = 6; + println!("{:?} {:?}", a, b); +} + +fn baz() { + let mut foo = [1,2,3,4]; + let a = &foo[..2]; + let b = &mut foo[2..]; //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable + b[0] = 6; + println!("{:?} {:?}", a, b); +} + +fn qux() { + let mut foo = [1,2,3,4]; + let a = &mut foo[..2]; + let b = &foo[2..]; //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + a[0] = 5; + println!("{:?} {:?}", a, b); +} + +fn bad() { + let mut foo = [1,2,3,4]; + let a = &foo[1]; + let b = &mut foo[2]; //~ ERROR cannot borrow `foo[_]` as mutable because it is also borrowed as immutable + *b = 6; + println!("{:?} {:?}", a, b); +} + +fn bat() { + let mut foo = [1,2,3,4]; + let a = &mut foo[1]; + let b = &foo[2]; //~ ERROR cannot borrow `foo[_]` as immutable because it is also borrowed as mutable + *a = 5; + println!("{:?} {:?}", a, b); +} + +fn ang() { + let mut foo = [1,2,3,4]; + let a = &mut foo[0..]; + let b = &foo[0..]; //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + a[0] = 5; + println!("{:?} {:?}", a, b); +} + +fn main() { + foo(); + bar(); +} diff --git a/tests/ui/suggestions/suggest-split-at-mut.stderr b/tests/ui/suggestions/suggest-split-at-mut.stderr index c42f09e3201..4502ec1f393 100644 --- a/tests/ui/suggestions/suggest-split-at-mut.stderr +++ b/tests/ui/suggestions/suggest-split-at-mut.stderr @@ -8,9 +8,81 @@ LL | let b = &mut foo[3]; LL | *a = 5; | ------ first borrow later used here | - = help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices - = help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices -error: aborting due to 1 previous error +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/suggest-split-at-mut.rs:13:18 + | +LL | let a = &mut foo[..2]; + | --- first mutable borrow occurs here +LL | let b = &mut foo[2..]; + | ^^^ second mutable borrow occurs here +LL | a[0] = 5; + | ---- first borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/suggest-split-at-mut.rs:22:18 + | +LL | let a = &foo[..2]; + | --- immutable borrow occurs here +LL | let b = &mut foo[2..]; + | ^^^ mutable borrow occurs here +LL | b[0] = 6; +LL | println!("{:?} {:?}", a, b); + | - immutable borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/suggest-split-at-mut.rs:30:14 + | +LL | let a = &mut foo[..2]; + | --- mutable borrow occurs here +LL | let b = &foo[2..]; + | ^^^ immutable borrow occurs here +LL | a[0] = 5; + | ---- mutable borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo[_]` as mutable because it is also borrowed as immutable + --> $DIR/suggest-split-at-mut.rs:38:13 + | +LL | let a = &foo[1]; + | ------- immutable borrow occurs here +LL | let b = &mut foo[2]; + | ^^^^^^^^^^^ mutable borrow occurs here +LL | *b = 6; +LL | println!("{:?} {:?}", a, b); + | - immutable borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo[_]` as immutable because it is also borrowed as mutable + --> $DIR/suggest-split-at-mut.rs:46:13 + | +LL | let a = &mut foo[1]; + | ----------- mutable borrow occurs here +LL | let b = &foo[2]; + | ^^^^^^^ immutable borrow occurs here +LL | *a = 5; + | ------ mutable borrow later used here + | + = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/suggest-split-at-mut.rs:54:14 + | +LL | let a = &mut foo[0..]; + | --- mutable borrow occurs here +LL | let b = &foo[0..]; + | ^^^ immutable borrow occurs here +LL | a[0] = 5; + | ---- mutable borrow later used here + +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0499`. +Some errors have detailed explanations: E0499, E0502. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/suggestions/unnamable-types.rs b/tests/ui/suggestions/unnamable-types.rs index a4e32d7c806..dd2c3536eb9 100644 --- a/tests/ui/suggestions/unnamable-types.rs +++ b/tests/ui/suggestions/unnamable-types.rs @@ -1,7 +1,7 @@ // Test that we do not suggest to add type annotations for unnamable types. #![crate_type="lib"] -#![feature(coroutines)] +#![feature(coroutines, stmt_expr_attributes)] const A = 5; //~^ ERROR: missing type for `const` item @@ -34,6 +34,6 @@ const F = S { t: foo }; //~| HELP: provide a type for the constant -const G = || -> i32 { yield 0; return 1; }; +const G = #[coroutine] || -> i32 { yield 0; return 1; }; //~^ ERROR: missing type for `const` item //~| NOTE: however, the inferred type diff --git a/tests/ui/suggestions/unnamable-types.stderr b/tests/ui/suggestions/unnamable-types.stderr index d003b91691c..6623678fd0c 100644 --- a/tests/ui/suggestions/unnamable-types.stderr +++ b/tests/ui/suggestions/unnamable-types.stderr @@ -52,14 +52,14 @@ LL | const F = S { t: foo }; error: missing type for `const` item --> $DIR/unnamable-types.rs:37:8 | -LL | const G = || -> i32 { yield 0; return 1; }; +LL | const G = #[coroutine] || -> i32 { yield 0; return 1; }; | ^ | -note: however, the inferred type `{coroutine@$DIR/unnamable-types.rs:37:11: 37:20}` cannot be named - --> $DIR/unnamable-types.rs:37:11 +note: however, the inferred type `{coroutine@$DIR/unnamable-types.rs:37:24: 37:33}` cannot be named + --> $DIR/unnamable-types.rs:37:24 | -LL | const G = || -> i32 { yield 0; return 1; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const G = #[coroutine] || -> i32 { yield 0; return 1; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/traits/mutual-recursion-issue-75860.rs b/tests/ui/traits/mutual-recursion-issue-75860.rs index d7d7307b424..65c3dd132c3 100644 --- a/tests/ui/traits/mutual-recursion-issue-75860.rs +++ b/tests/ui/traits/mutual-recursion-issue-75860.rs @@ -6,10 +6,10 @@ pub fn iso<A, B, F1, F2>(a: F1, b: F2) -> (Box<dyn Fn(A) -> B>, Box<dyn Fn(B) -> (Box::new(a), Box::new(b)) } pub fn iso_un_option<A, B>() -> (Box<dyn Fn(A) -> B>, Box<dyn Fn(B) -> A>) { - let left = |o_a: Option<_>| o_a.unwrap(); + let left = |o_a: Option<_>| o_a.unwrap(); + //~^ ERROR overflow let right = |o_b: Option<_>| o_b.unwrap(); iso(left, right) - //~^ ERROR overflow } fn main() {} diff --git a/tests/ui/traits/mutual-recursion-issue-75860.stderr b/tests/ui/traits/mutual-recursion-issue-75860.stderr index 8f83bab003d..272c56301bc 100644 --- a/tests/ui/traits/mutual-recursion-issue-75860.stderr +++ b/tests/ui/traits/mutual-recursion-issue-75860.stderr @@ -1,12 +1,8 @@ -error[E0275]: overflow evaluating the requirement `Option<_>: Sized` - --> $DIR/mutual-recursion-issue-75860.rs:11:5 +error[E0275]: overflow assigning `_` to `Option<_>` + --> $DIR/mutual-recursion-issue-75860.rs:9:33 | -LL | iso(left, right) - | ^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mutual_recursion_issue_75860`) -note: required by an implicit `Sized` bound in `Option` - --> $SRC_DIR/core/src/option.rs:LL:COL +LL | let left = |o_a: Option<_>| o_a.unwrap(); + | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs b/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs new file mode 100644 index 00000000000..78dffcbf6ab --- /dev/null +++ b/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs @@ -0,0 +1,17 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +trait Local {} + +trait Overlap { fn f(); } +impl<T> Overlap for Option<T> where Self: Clone, { fn f() {} } +impl<T> Overlap for Option<T> where Self: Local, { fn f() {} } + +fn test<T>() +where + Option<T>: Clone + Local, +{ + <Option<T> as Overlap>::f(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/coroutine.fail.stderr b/tests/ui/traits/next-solver/coroutine.fail.stderr index 14e67727d0b..e880d05a4dd 100644 --- a/tests/ui/traits/next-solver/coroutine.fail.stderr +++ b/tests/ui/traits/next-solver/coroutine.fail.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `{coroutine@$DIR/coroutine.rs:18:21: 18:23}: Coroutine<A>` is not satisfied - --> $DIR/coroutine.rs:18:21 +error[E0277]: the trait bound `{coroutine@$DIR/coroutine.rs:20:9: 20:11}: Coroutine<A>` is not satisfied + --> $DIR/coroutine.rs:20:9 | -LL | needs_coroutine(|| { - | _____---------------_^ - | | | - | | required by a bound introduced by this call +LL | needs_coroutine( + | --------------- required by a bound introduced by this call +LL | #[coroutine] +LL | / || { LL | | LL | | LL | | -LL | | yield (); -LL | | }); - | |_____^ the trait `Coroutine<A>` is not implemented for `{coroutine@$DIR/coroutine.rs:18:21: 18:23}` +LL | | yield (); +LL | | }, + | |_________^ the trait `Coroutine<A>` is not implemented for `{coroutine@$DIR/coroutine.rs:20:9: 20:11}` | note: required by a bound in `needs_coroutine` --> $DIR/coroutine.rs:14:28 @@ -18,19 +18,19 @@ note: required by a bound in `needs_coroutine` LL | fn needs_coroutine(_: impl Coroutine<A, Yield = B, Return = C>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_coroutine` -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:18:21: 18:23} as Coroutine<A>>::Yield == B` - --> $DIR/coroutine.rs:18:21 +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:20:9: 20:11} as Coroutine<A>>::Yield == B` + --> $DIR/coroutine.rs:20:9 | -LL | needs_coroutine(|| { - | _____---------------_^ - | | | - | | required by a bound introduced by this call +LL | needs_coroutine( + | --------------- required by a bound introduced by this call +LL | #[coroutine] +LL | / || { LL | | LL | | LL | | -LL | | yield (); -LL | | }); - | |_____^ types differ +LL | | yield (); +LL | | }, + | |_________^ types differ | note: required by a bound in `needs_coroutine` --> $DIR/coroutine.rs:14:41 @@ -38,19 +38,19 @@ note: required by a bound in `needs_coroutine` LL | fn needs_coroutine(_: impl Coroutine<A, Yield = B, Return = C>) {} | ^^^^^^^^^ required by this bound in `needs_coroutine` -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:18:21: 18:23} as Coroutine<A>>::Return == C` - --> $DIR/coroutine.rs:18:21 +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:20:9: 20:11} as Coroutine<A>>::Return == C` + --> $DIR/coroutine.rs:20:9 | -LL | needs_coroutine(|| { - | _____---------------_^ - | | | - | | required by a bound introduced by this call +LL | needs_coroutine( + | --------------- required by a bound introduced by this call +LL | #[coroutine] +LL | / || { LL | | LL | | LL | | -LL | | yield (); -LL | | }); - | |_____^ types differ +LL | | yield (); +LL | | }, + | |_________^ types differ | note: required by a bound in `needs_coroutine` --> $DIR/coroutine.rs:14:52 diff --git a/tests/ui/traits/next-solver/coroutine.rs b/tests/ui/traits/next-solver/coroutine.rs index 2b5bf01cefd..1882a62cf29 100644 --- a/tests/ui/traits/next-solver/coroutine.rs +++ b/tests/ui/traits/next-solver/coroutine.rs @@ -15,18 +15,24 @@ fn needs_coroutine(_: impl Coroutine<A, Yield = B, Return = C>) {} #[cfg(fail)] fn main() { - needs_coroutine(|| { - //[fail]~^ ERROR Coroutine<A>` is not satisfied - //[fail]~| ERROR as Coroutine<A>>::Yield == B` - //[fail]~| ERROR as Coroutine<A>>::Return == C` - yield (); - }); + needs_coroutine( + #[coroutine] + || { + //[fail]~^ ERROR Coroutine<A>` is not satisfied + //[fail]~| ERROR as Coroutine<A>>::Yield == B` + //[fail]~| ERROR as Coroutine<A>>::Return == C` + yield (); + }, + ); } #[cfg(pass)] fn main() { - needs_coroutine(|_: A| { - let _: A = yield B; - C - }) + needs_coroutine( + #[coroutine] + |_: A| { + let _: A = yield B; + C + }, + ) } diff --git a/tests/ui/transmute/ambiguity-in-closure-arg.rs b/tests/ui/transmute/ambiguity-in-closure-arg.rs new file mode 100644 index 00000000000..4c2d1ce2ad4 --- /dev/null +++ b/tests/ui/transmute/ambiguity-in-closure-arg.rs @@ -0,0 +1,11 @@ +// Minimized test for <https://github.com/rust-lang/rust/issues/123461>. + +struct Unconstrained<T>(T); + +fn main() { + unsafe { std::mem::transmute::<_, ()>(|o_b: Unconstrained<_>| {}) }; + //~^ ERROR type annotations needed + // We unfortunately don't check `Wf(Unconstrained<_>)`, so we won't + // hit an ambiguity error before checking the transmute. That means + // we still may have inference variables in our transmute src. +} diff --git a/tests/ui/transmute/ambiguity-in-closure-arg.stderr b/tests/ui/transmute/ambiguity-in-closure-arg.stderr new file mode 100644 index 00000000000..24a10a6d210 --- /dev/null +++ b/tests/ui/transmute/ambiguity-in-closure-arg.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/ambiguity-in-closure-arg.rs:6:44 + | +LL | unsafe { std::mem::transmute::<_, ()>(|o_b: Unconstrained<_>| {}) }; + | ^^^^^^^^^^^^^^^^^^^^^ cannot infer type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs b/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs index cd14bc1fd09..0d9126d3993 100644 --- a/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs +++ b/tests/ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs @@ -9,6 +9,7 @@ mod gen { pub type CoroOnce<Y, R> = impl Coroutine<Yield = Y, Return = R>; pub const fn const_coroutine<Y, R>(yielding: Y, returning: R) -> CoroOnce<Y, R> { + #[coroutine] move || { yield yielding; diff --git a/tests/ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs b/tests/ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs index 78a1d5116be..899e81ed562 100644 --- a/tests/ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs +++ b/tests/ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs @@ -8,6 +8,7 @@ use std::pin::Pin; type RandCoroutine<'a> = impl Coroutine<Return = (), Yield = u64> + 'a; fn rand_coroutine<'a>(rng: &'a ()) -> RandCoroutine<'a> { + #[coroutine] move || { let _rng = rng; loop { @@ -19,6 +20,7 @@ fn rand_coroutine<'a>(rng: &'a ()) -> RandCoroutine<'a> { pub type RandCoroutineWithIndirection<'c> = impl Coroutine<Return = (), Yield = u64> + 'c; pub fn rand_coroutine_with_indirection<'a>(rng: &'a ()) -> RandCoroutineWithIndirection<'a> { fn helper<'b>(rng: &'b ()) -> impl 'b + Coroutine<Return = (), Yield = u64> { + #[coroutine] move || { let _rng = rng; loop { diff --git a/tests/ui/type-alias-impl-trait/issue-94429.rs b/tests/ui/type-alias-impl-trait/issue-94429.rs index 306e73003fa..11beed06a20 100644 --- a/tests/ui/type-alias-impl-trait/issue-94429.rs +++ b/tests/ui/type-alias-impl-trait/issue-94429.rs @@ -14,6 +14,7 @@ impl Runnable for Implementor { fn run(&mut self) -> Self::Coro { //~^ ERROR: type mismatch resolving + #[coroutine] move || { yield 1; } diff --git a/tests/ui/type-alias-impl-trait/issue-94429.stderr b/tests/ui/type-alias-impl-trait/issue-94429.stderr index 5d081e6b1ef..4c2020becbe 100644 --- a/tests/ui/type-alias-impl-trait/issue-94429.stderr +++ b/tests/ui/type-alias-impl-trait/issue-94429.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<{coroutine@$DIR/issue-94429.rs:17:9: 17:16} as Coroutine>::Yield == ()` +error[E0271]: type mismatch resolving `<{coroutine@$DIR/issue-94429.rs:18:9: 18:16} as Coroutine>::Yield == ()` --> $DIR/issue-94429.rs:15:26 | LL | fn run(&mut self) -> Self::Coro { diff --git a/tests/ui/type/type-check/unknown_type_for_closure.stderr b/tests/ui/type/type-check/unknown_type_for_closure.stderr index e5e29aabf37..960c0eff8ea 100644 --- a/tests/ui/type/type-check/unknown_type_for_closure.stderr +++ b/tests/ui/type/type-check/unknown_type_for_closure.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/unknown_type_for_closure.rs:2:13 + --> $DIR/unknown_type_for_closure.rs:2:14 | LL | let x = |b: Vec<_>| {}; - | ^^^^^^^^^^^^^^ cannot infer type for struct `Vec<_>` + | ^^^^^^^^^ cannot infer type error[E0282]: type annotations needed --> $DIR/unknown_type_for_closure.rs:6:14 diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr index 23aa18d7156..fc6f610ddd4 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr @@ -1,6 +1,9 @@ error[E0597]: `factorial` does not live long enough --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:15:17 | +LL | let mut factorial: Option<Box<dyn Fn(u32) -> u32>> = None; + | ------------- binding `factorial` declared here +LL | LL | let f = |x: u32| -> u32 { | --------------- value captured here LL | let g = factorial.as_ref().unwrap(); @@ -30,7 +33,9 @@ error[E0597]: `factorial` does not live long enough --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:28:17 | LL | let mut factorial: Option<Box<dyn Fn(u32) -> u32 + 'static>> = None; - | ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` + | ------------- ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` + | | + | binding `factorial` declared here LL | LL | let f = |x: u32| -> u32 { | --------------- value captured here diff --git a/tests/ui/union/union-borrow-move-parent-sibling.stderr b/tests/ui/union/union-borrow-move-parent-sibling.stderr index 782fa63280e..f8e9609cb1c 100644 --- a/tests/ui/union/union-borrow-move-parent-sibling.stderr +++ b/tests/ui/union/union-borrow-move-parent-sibling.stderr @@ -54,7 +54,10 @@ note: if `MockVec<u8>` implemented `Clone`, you could clone the value --> $DIR/union-borrow-move-parent-sibling.rs:25:1 | LL | struct MockVec<T> { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let a = (u.x.0).0; + | --------- you could clone this value help: consider borrowing here | LL | let a = &(u.x.0).0; diff --git a/tests/ui/union/union-move.stderr b/tests/ui/union/union-move.stderr index 5ebb2716e5a..d520fb00ea9 100644 --- a/tests/ui/union/union-move.stderr +++ b/tests/ui/union/union-move.stderr @@ -20,7 +20,10 @@ note: if `U1` implemented `Clone`, you could clone the value --> $DIR/union-move.rs:9:1 | LL | union U1 { - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | move_out(x.f1_nocopy); + | ----------- you could clone this value error[E0382]: use of moved value: `x` --> $DIR/union-move.rs:42:18 @@ -44,7 +47,10 @@ note: if `U1` implemented `Clone`, you could clone the value --> $DIR/union-move.rs:9:1 | LL | union U1 { - | ^^^^^^^^ + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | move_out(x.f2_nocopy); + | ----------- you could clone this value error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait --> $DIR/union-move.rs:49:18 diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop-move-semantics.stderr index 187dd66b2fe..bc9b3ea9903 100644 --- a/tests/ui/unop-move-semantics.stderr +++ b/tests/ui/unop-move-semantics.stderr @@ -33,6 +33,14 @@ LL | !x; ... LL | use_mut(n); use_imm(m); | - borrow later used here + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/unop-move-semantics.rs:11:18 + | +LL | fn move_borrowed<T: Not<Output=T>>(x: T, mut y: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let m = &x; + | -- you could clone this value error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/unop-move-semantics.rs:17:6 @@ -47,6 +55,15 @@ LL | !y; | ^ move out of `y` occurs here LL | use_mut(n); use_imm(m); | - borrow later used here + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/unop-move-semantics.rs:11:18 + | +LL | fn move_borrowed<T: Not<Output=T>>(x: T, mut y: T) { + | ^ consider constraining this type parameter with `Clone` +LL | let m = &x; +LL | let n = &mut y; + | ------ you could clone this value error[E0507]: cannot move out of `*m` which is behind a mutable reference --> $DIR/unop-move-semantics.rs:24:6 @@ -59,6 +76,14 @@ LL | !*m; | note: calling this operator moves the value --> $SRC_DIR/core/src/ops/bit.rs:LL:COL +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/unop-move-semantics.rs:20:24 + | +LL | fn illegal_dereference<T: Not<Output=T>>(mut x: T, y: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | !*m; + | -- you could clone this value error[E0507]: cannot move out of `*n` which is behind a shared reference --> $DIR/unop-move-semantics.rs:26:6 @@ -68,6 +93,15 @@ LL | !*n; | || | |move occurs because `*n` has type `T`, which does not implement the `Copy` trait | `*n` moved due to usage in operator + | +help: if `T` implemented `Clone`, you could clone the value + --> $DIR/unop-move-semantics.rs:20:24 + | +LL | fn illegal_dereference<T: Not<Output=T>>(mut x: T, y: T) { + | ^ consider constraining this type parameter with `Clone` +... +LL | !*n; + | -- you could clone this value error: aborting due to 5 previous errors diff --git a/tests/ui/variance/variance-issue-20533.stderr b/tests/ui/variance/variance-issue-20533.stderr index 4515d313ec0..03cada07a9e 100644 --- a/tests/ui/variance/variance-issue-20533.stderr +++ b/tests/ui/variance/variance-issue-20533.stderr @@ -14,7 +14,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value --> $DIR/variance-issue-20533.rs:26:1 | LL | struct AffineU32(u32); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = foo(&a); + | -- you could clone this value error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:41:14 @@ -32,7 +35,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value --> $DIR/variance-issue-20533.rs:26:1 | LL | struct AffineU32(u32); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = bar(&a); + | -- you could clone this value error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:47:14 @@ -50,7 +56,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value --> $DIR/variance-issue-20533.rs:26:1 | LL | struct AffineU32(u32); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = baz(&a); + | -- you could clone this value error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:53:14 diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index 0009ed0e34c..08b5517aae2 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -152,6 +152,7 @@ fn r#match() { } fn i_yield() { + #[coroutine] static || { yield yield yield yield yield yield yield yield yield; }; diff --git a/tests/ui/wf/closure-wf.rs b/tests/ui/wf/closure-wf.rs new file mode 100644 index 00000000000..48baeb30ce5 --- /dev/null +++ b/tests/ui/wf/closure-wf.rs @@ -0,0 +1,11 @@ +trait Bound {} +struct NeedsBound<T: Bound>(T); + +// Checks that we enforce that closure args are WF. + +fn constrain_inner<T, F: for<'a> FnOnce(&'a (), NeedsBound<T>)>(_: T, _: F) {} + +fn main() { + constrain_inner(1u32, |&(), _| ()); + //~^ ERROR the trait bound `u32: Bound` is not satisfied +} diff --git a/tests/ui/wf/closure-wf.stderr b/tests/ui/wf/closure-wf.stderr new file mode 100644 index 00000000000..4beef3bb7c5 --- /dev/null +++ b/tests/ui/wf/closure-wf.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `u32: Bound` is not satisfied + --> $DIR/closure-wf.rs:9:33 + | +LL | constrain_inner(1u32, |&(), _| ()); + | ^ the trait `Bound` is not implemented for `u32` + | +help: this trait has no implementations, consider adding one + --> $DIR/closure-wf.rs:1:1 + | +LL | trait Bound {} + | ^^^^^^^^^^^ +note: required by a bound in `NeedsBound` + --> $DIR/closure-wf.rs:2:22 + | +LL | struct NeedsBound<T: Bound>(T); + | ^^^^^ required by this bound in `NeedsBound` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. |
