diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86de37820003a..6e0808c0d5896 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,9 +32,9 @@ jobs: name: PR env: CI_JOB_NAME: "${{ matrix.name }}" - SCCACHE_BUCKET: rust-lang-gha-caches - TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate" - CACHE_DOMAIN: ci-caches-gha.rust-lang.org + 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'" strategy: matrix: @@ -63,6 +63,11 @@ jobs: with: github_token: "${{ secrets.github_token }}" if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" + - 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_JOBS && github.event_name == 'pull_request'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh env: @@ -133,14 +138,14 @@ jobs: name: try env: CI_JOB_NAME: "${{ matrix.name }}" - SCCACHE_BUCKET: rust-lang-gha-caches - DEPLOY_BUCKET: rust-lang-gha - TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate" - TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues" + 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: AKIA46X5W6CZOMUQATD5 - ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF - CACHE_DOMAIN: ci-caches-gha.rust-lang.org + CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL + ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 + CACHE_DOMAIN: ci-caches.rust-lang.org if: "github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'" strategy: matrix: @@ -162,6 +167,11 @@ jobs: with: github_token: "${{ secrets.github_token }}" if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" + - 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_JOBS && github.event_name == 'pull_request'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh env: @@ -232,14 +242,14 @@ jobs: name: auto env: CI_JOB_NAME: "${{ matrix.name }}" - SCCACHE_BUCKET: rust-lang-gha-caches - DEPLOY_BUCKET: rust-lang-gha - TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate" - TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues" + 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: AKIA46X5W6CZOMUQATD5 - ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF - CACHE_DOMAIN: ci-caches-gha.rust-lang.org + CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL + ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 + 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: @@ -479,6 +489,11 @@ jobs: with: github_token: "${{ secrets.github_token }}" if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" + - 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_JOBS && github.event_name == 'pull_request'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh env: @@ -604,6 +619,11 @@ jobs: with: github_token: "${{ secrets.github_token }}" if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" + - 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_JOBS && github.event_name == 'pull_request'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh env: @@ -674,14 +694,14 @@ jobs: name: master runs-on: ubuntu-latest env: - SCCACHE_BUCKET: rust-lang-gha-caches - DEPLOY_BUCKET: rust-lang-gha - TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate" - TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues" + 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: AKIA46X5W6CZOMUQATD5 - ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF - CACHE_DOMAIN: ci-caches-gha.rust-lang.org + CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL + ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 + CACHE_DOMAIN: ci-caches.rust-lang.org if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'" steps: - name: checkout the source code diff --git a/Cargo.lock b/Cargo.lock index 34a33eca3f40b..8391cba278631 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,9 +412,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fde55d2a2bfaa4c9668bbc63f531fbdeee3ffe188f4662511ce2c22b3eedebe" +checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" dependencies = [ "jobserver", ] @@ -1576,9 +1576,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "libc" -version = "0.2.71" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" dependencies = [ "rustc-std-workspace-core", ] diff --git a/src/backtrace b/src/backtrace index 8f89434446f72..5965cf5fc17af 160000 --- a/src/backtrace +++ b/src/backtrace @@ -1 +1 @@ -Subproject commit 8f89434446f72f27f8145d8bbc1a302c6ef29d1e +Subproject commit 5965cf5fc17affc84c11dc9972ae8f4dc2c32db1 diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 737176c48f878..c1e56347ab1e0 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1239,7 +1239,7 @@ impl<'a> Builder<'a> { && self.config.control_flow_guard && compiler.stage >= 1 { - rustflags.arg("-Zcontrol-flow-guard"); + rustflags.arg("-Ccontrol-flow-guard"); } // For `cargo doc` invocations, make rustdoc print the Rust version into the docs diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 263c7b93fe55d..14c22605e8188 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1005,7 +1005,7 @@ impl Step for Src { // (essentially libstd and all of its path dependencies) let std_src_dirs = [ "src/build_helper", - "src/backtrace", + "src/backtrace/src", "src/liballoc", "src/libcore", "src/libpanic_abort", diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index 1786baa0278b9..06e284c763c15 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -10,75 +10,23 @@ ##################################### # -# Azure Pipelines "auto" branch build for Rust on Linux, macOS, and Windows. +# Azure Pipelines "auto" branch build for Rust on macOS # pr: none trigger: - auto -variables: -- group: prod-credentials - jobs: -- job: Linux - timeoutInMinutes: 600 - pool: - vmImage: ubuntu-16.04 - steps: - - template: steps/run.yml - strategy: - matrix: - x86_64-gnu-llvm-8: - RUST_BACKTRACE: 1 - dist-x86_64-linux: {} - dist-x86_64-linux-alt: - IMAGE: dist-x86_64-linux - arm-android: {} - armhf-gnu: {} - dist-various-1: {} - dist-various-2: {} - dist-aarch64-linux: {} - dist-android: {} - dist-arm-linux: {} - dist-armhf-linux: {} - dist-armv7-linux: {} - dist-i586-gnu-i586-i686-musl: {} - dist-i686-freebsd: {} - dist-i686-linux: {} - dist-mips-linux: {} - dist-mips64-linux: {} - dist-mips64el-linux: {} - dist-mipsel-linux: {} - dist-powerpc-linux: {} - dist-powerpc64-linux: {} - dist-powerpc64le-linux: {} - dist-riscv64-linux: {} - dist-s390x-linux: {} - dist-x86_64-freebsd: {} - dist-x86_64-illumos: {} - dist-x86_64-musl: {} - dist-x86_64-netbsd: {} - i686-gnu: {} - i686-gnu-nopt: {} - test-various: {} - wasm32: {} - x86_64-gnu: {} - x86_64-gnu-full-bootstrap: {} - x86_64-gnu-aux: {} - x86_64-gnu-tools: - DEPLOY_TOOLSTATES_JSON: toolstates-linux.json - x86_64-gnu-debug: {} - x86_64-gnu-nopt: {} - x86_64-gnu-distcheck: {} - mingw-check: {} - - job: macOS timeoutInMinutes: 600 pool: vmImage: macos-10.15 steps: - template: steps/run.yml + variables: + # We're still uploading macOS builds from Azure Pipelines. + - group: prod-credentials strategy: matrix: # OSX builders running tests, these run the full test suite. @@ -112,115 +60,3 @@ jobs: MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 - - -- job: Windows - timeoutInMinutes: 600 - pool: - vmImage: 'vs2017-win2016' - steps: - - template: steps/run.yml - strategy: - matrix: - # 32/64 bit MSVC tests - x86_64-msvc-1: - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: make ci-subset-1 - # FIXME(#59637) - NO_DEBUG_ASSERTIONS: 1 - NO_LLVM_ASSERTIONS: 1 - x86_64-msvc-2: - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: make ci-subset-2 - i686-msvc-1: - INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-subset-1 - # FIXME(#59637) - NO_DEBUG_ASSERTIONS: 1 - NO_LLVM_ASSERTIONS: 1 - i686-msvc-2: - INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-subset-2 - # FIXME(#59637) - NO_DEBUG_ASSERTIONS: 1 - NO_LLVM_ASSERTIONS: 1 - x86_64-msvc-cargo: - SCRIPT: python x.py test src/tools/cargotest src/tools/cargo - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld - VCVARS_BAT: vcvars64.bat - # FIXME(#59637) - NO_DEBUG_ASSERTIONS: 1 - NO_LLVM_ASSERTIONS: 1 - # MSVC tools tests - x86_64-msvc-tools: - SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json - - # 32/64-bit MinGW builds. - # - # We are using MinGW with posix threads since LLVM does not compile with - # the win32 threads version due to missing support for C++'s std::thread. - # - # Instead of relying on the MinGW version installed on appveryor we download - # and install one ourselves so we won't be surprised by changes to appveyor's - # build image. - # - # Finally, note that the downloads below are all in the `rust-lang-ci` S3 - # bucket, but they cleraly 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. - i686-mingw-1: - INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make ci-mingw-subset-1 - CUSTOM_MINGW: 1 - # FIXME(#59637) - NO_DEBUG_ASSERTIONS: 1 - NO_LLVM_ASSERTIONS: 1 - i686-mingw-2: - INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu - SCRIPT: make ci-mingw-subset-2 - CUSTOM_MINGW: 1 - x86_64-mingw-1: - SCRIPT: make ci-mingw-subset-1 - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - CUSTOM_MINGW: 1 - # FIXME(#59637) - NO_DEBUG_ASSERTIONS: 1 - NO_LLVM_ASSERTIONS: 1 - x86_64-mingw-2: - SCRIPT: make ci-mingw-subset-2 - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - CUSTOM_MINGW: 1 - - # 32/64 bit MSVC and GNU deployment - dist-x86_64-msvc: - INITIAL_RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-msvc - --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc - --enable-full-tools - --enable-profiler - SCRIPT: python x.py dist - DIST_REQUIRE_ALL_TOOLS: 1 - dist-i686-msvc: - INITIAL_RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-msvc - --target=i586-pc-windows-msvc - --enable-full-tools - --enable-profiler - SCRIPT: python x.py dist - DIST_REQUIRE_ALL_TOOLS: 1 - dist-i686-mingw: - INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler - SCRIPT: python x.py dist - CUSTOM_MINGW: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - dist-x86_64-mingw: - SCRIPT: python x.py dist - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler - CUSTOM_MINGW: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - - # "alternate" deployment, see .travis.yml for more info - dist-x86_64-msvc-alt: - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler - SCRIPT: python x.py dist diff --git a/src/ci/azure-pipelines/master.yml b/src/ci/azure-pipelines/master.yml deleted file mode 100644 index 485b80398c8e4..0000000000000 --- a/src/ci/azure-pipelines/master.yml +++ /dev/null @@ -1,33 +0,0 @@ -##################################### -## READ BEFORE CHANGING THIS ## -##################################### - -# We're in the process of evaluating GitHub Actions as a possible replacement -# for Azure Pipelines, and at the moment the configuration is duplicated -# between the two CI providers. Be sure to also change the configuration in -# src/ci/github-actions when changing this file. - -##################################### - -# -# Azure Pipelines job to publish toolstate. Only triggers on pushes to master. -# - -pr: none -trigger: - - master - -variables: -- group: prod-credentials - -pool: - vmImage: ubuntu-16.04 - -steps: -- checkout: self - fetchDepth: 2 - -- script: src/ci/publish_toolstate.sh - displayName: Publish toolstate - env: - TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) diff --git a/src/ci/azure-pipelines/pr.yml b/src/ci/azure-pipelines/pr.yml deleted file mode 100644 index 1fc8d187242f8..0000000000000 --- a/src/ci/azure-pipelines/pr.yml +++ /dev/null @@ -1,35 +0,0 @@ -##################################### -## READ BEFORE CHANGING THIS ## -##################################### - -# We're in the process of evaluating GitHub Actions as a possible replacement -# for Azure Pipelines, and at the moment the configuration is duplicated -# between the two CI providers. Be sure to also change the configuration in -# src/ci/github-actions when changing this file. - -##################################### - -# -# Azure Pipelines pull request build for Rust -# - -trigger: none -pr: -- master - -variables: -- group: public-credentials - -jobs: -- job: Linux - timeoutInMinutes: 600 - pool: - vmImage: ubuntu-16.04 - steps: - - template: steps/run.yml - strategy: - matrix: - x86_64-gnu-llvm-8: {} - mingw-check: {} - x86_64-gnu-tools: - CI_ONLY_WHEN_SUBMODULES_CHANGED: 1 diff --git a/src/ci/azure-pipelines/try.yml b/src/ci/azure-pipelines/try.yml index 818306a009229..62bb6f4733412 100644 --- a/src/ci/azure-pipelines/try.yml +++ b/src/ci/azure-pipelines/try.yml @@ -13,70 +13,10 @@ pr: none trigger: - try -variables: -- group: prod-credentials - jobs: -- job: Linux +- job: Dummy timeoutInMinutes: 600 pool: vmImage: ubuntu-16.04 steps: - - template: steps/run.yml - strategy: - matrix: - dist-x86_64-linux: {} - -# The macOS and Windows builds here are currently disabled due to them not being -# overly necessary on `try` builds. We also don't actually have anything that -# consumes the artifacts currently. Perhaps one day we can re-enable, but for now -# it helps free up capacity on Azure. -# - job: macOS -# timeoutInMinutes: 600 -# pool: -# vmImage: macos-10.15 -# steps: -# - template: steps/run.yml -# strategy: -# matrix: -# dist-x86_64-apple: -# SCRIPT: ./x.py dist -# INITIAL_RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc -# DEPLOY: 1 -# RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 -# MACOSX_DEPLOYMENT_TARGET: 10.7 -# NO_LLVM_ASSERTIONS: 1 -# NO_DEBUG_ASSERTIONS: 1 -# DIST_REQUIRE_ALL_TOOLS: 1 -# -# dist-x86_64-apple-alt: -# SCRIPT: ./x.py dist -# INITIAL_RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc -# DEPLOY_ALT: 1 -# RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 -# MACOSX_DEPLOYMENT_TARGET: 10.7 -# NO_LLVM_ASSERTIONS: 1 -# NO_DEBUG_ASSERTIONS: 1 -# -# - job: Windows -# timeoutInMinutes: 600 -# pool: -# vmImage: 'vs2017-win2016' -# steps: -# - template: steps/run.yml -# strategy: -# matrix: -# dist-x86_64-msvc: -# INITIAL_RUST_CONFIGURE_ARGS: > -# --build=x86_64-pc-windows-msvc -# --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc -# --enable-full-tools -# --enable-profiler -# SCRIPT: python x.py dist -# DIST_REQUIRE_ALL_TOOLS: 1 -# DEPLOY: 1 -# -# dist-x86_64-msvc-alt: -# INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler -# SCRIPT: python x.py dist -# DEPLOY_ALT: 1 + - bash: echo "We're running this job since bors is still gating on Azure" diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 5573d87aa2e55..425e34f1af624 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -35,11 +35,26 @@ x--expand-yaml-anchors--remove: CI_JOB_NAME: ${{ matrix.name }} - &public-variables - SCCACHE_BUCKET: rust-lang-gha-caches - TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate - CACHE_DOMAIN: ci-caches-gha.rust-lang.org + SCCACHE_BUCKET: rust-lang-ci-sccache2 + TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate + CACHE_DOMAIN: ci-caches.rust-lang.org - &prod-variables + 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 + # 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 + CACHE_DOMAIN: ci-caches.rust-lang.org + + - &dummy-variables SCCACHE_BUCKET: rust-lang-gha-caches DEPLOY_BUCKET: rust-lang-gha TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate @@ -92,6 +107,15 @@ x--expand-yaml-anchors--remove: if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' <<: *step + # Rust Log Analyzer can't currently detect the PR number of a GitHub + # Actions build on its own, so a hint in the log message is needed to + # point it in the right direction. + - 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_JOBS && github.event_name == 'pull_request' + - name: add extra environment variables run: src/ci/scripts/setup-environment.sh env: @@ -556,7 +580,7 @@ jobs: <<: *base-ci-job name: auto-fallible env: - <<: [*shared-ci-variables, *prod-variables] + <<: [*shared-ci-variables, *dummy-variables] if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust' strategy: matrix: diff --git a/src/doc/book b/src/doc/book index 84a31397b34f9..a914f2c7e5cdb 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 84a31397b34f9d405df44f2899ff17a4828dba18 +Subproject commit a914f2c7e5cdb771fa465de142381a51c53b580e diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 82bec5877c77c..bd6e4a9f59c5c 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 82bec5877c77cfad530ca11095db4456d757f668 +Subproject commit bd6e4a9f59c5c1545f572266af77f5c7a5bad6d1 diff --git a/src/doc/reference b/src/doc/reference index 0ea7bc494f128..b329ce3742487 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 0ea7bc494f1289234d8800bb9185021e0ad946f0 +Subproject commit b329ce37424874ad4db94f829a55807c6e21d2cb diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 0b4bb05c1db23..35904e15d3fee 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. +## control-flow-guard + +This flag controls whether LLVM enables the Windows [Control Flow +Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) +platform security feature. This flag is currently ignored for non-Windows targets. +It takes one of the following values: + +* `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard. +* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this +should only be used for testing purposes as it does not provide security enforcement). +* `n`, `no`, `off`: do not enable Control Flow Guard (the default). + ## debug-assertions This flag lets you turn `cfg(debug_assertions)` [conditional diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 5e2e04c063bc4..93908e9190e64 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -26,6 +26,9 @@ of bugs: * Double-free, invalid free * Memory leaks +The memory leak detection is enabled by default on Linux, and can be enabled +with runtime flag `ASAN_OPTIONS=detect_leaks=1` on macOS. + AddressSanitizer is supported on the following targets: * `x86_64-apple-darwin` @@ -196,10 +199,6 @@ fn main() { ```shell $ export \ - CC=clang \ - CXX=clang++ \ - CFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \ - CXXFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \ RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \ RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' $ cargo clean diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index 15313e333ce73..8398cfa3bd34e 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -1,9 +1,9 @@ //! A priority queue implemented with a binary heap. //! -//! Insertion and popping the largest element have `O(log(n))` time complexity. -//! Checking the largest element is `O(1)`. Converting a vector to a binary heap -//! can be done in-place, and has `O(n)` complexity. A binary heap can also be -//! converted to a sorted vector in-place, allowing it to be used for an `O(n * log(n))` +//! Insertion and popping the largest element have *O*(log(*n*)) time complexity. +//! Checking the largest element is *O*(1). Converting a vector to a binary heap +//! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be +//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*)) //! in-place heapsort. //! //! # Examples @@ -235,7 +235,7 @@ use super::SpecExtend; /// /// | [push] | [pop] | [peek]/[peek\_mut] | /// |--------|-----------|--------------------| -/// | O(1)~ | O(log(n)) | O(1) | +/// | O(1)~ | *O*(log(*n*)) | *O*(1) | /// /// The value for `push` is an expected cost; the method documentation gives a /// more detailed analysis. @@ -398,7 +398,7 @@ impl<T: Ord> BinaryHeap<T> { /// /// # Time complexity /// - /// Cost is `O(1)` in the worst case. + /// Cost is *O*(1) in the worst case. #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> { if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) } @@ -422,7 +422,7 @@ impl<T: Ord> BinaryHeap<T> { /// /// # Time complexity /// - /// The worst case cost of `pop` on a heap containing *n* elements is `O(log(n))`. + /// The worst case cost of `pop` on a heap containing *n* elements is *O*(log(*n*)). #[stable(feature = "rust1", since = "1.0.0")] pub fn pop(&mut self) -> Option<T> { self.data.pop().map(|mut item| { @@ -455,15 +455,15 @@ impl<T: Ord> BinaryHeap<T> { /// /// The expected cost of `push`, averaged over every possible ordering of /// the elements being pushed, and over a sufficiently large number of - /// pushes, is `O(1)`. This is the most meaningful cost metric when pushing + /// pushes, is *O*(1). This is the most meaningful cost metric when pushing /// elements that are *not* already in any sorted pattern. /// /// The time complexity degrades if elements are pushed in predominantly /// ascending order. In the worst case, elements are pushed in ascending - /// sorted order and the amortized cost per push is `O(log(n))` against a heap + /// sorted order and the amortized cost per push is *O*(log(*n*)) against a heap /// containing *n* elements. /// - /// The worst case cost of a *single* call to `push` is `O(n)`. The worst case + /// The worst case cost of a *single* call to `push` is *O*(*n*). The worst case /// occurs when capacity is exhausted and needs a resize. The resize cost /// has been amortized in the previous figures. #[stable(feature = "rust1", since = "1.0.0")] @@ -643,7 +643,7 @@ impl<T: Ord> BinaryHeap<T> { /// The remaining elements will be removed on drop in heap order. /// /// Note: - /// * `.drain_sorted()` is `O(n * log(n))`; much slower than `.drain()`. + /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`. /// You should use the latter for most cases. /// /// # Examples @@ -756,7 +756,7 @@ impl<T> BinaryHeap<T> { /// /// # Time complexity /// - /// Cost is `O(1)` in the worst case. + /// Cost is *O*(1) in the worst case. #[stable(feature = "rust1", since = "1.0.0")] pub fn peek(&self) -> Option<&T> { self.data.get(0) @@ -1312,7 +1312,7 @@ unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, T> {} impl<T: Ord> From<Vec<T>> for BinaryHeap<T> { /// Converts a `Vec<T>` into a `BinaryHeap<T>`. /// - /// This conversion happens in-place, and has `O(n)` time complexity. + /// This conversion happens in-place, and has *O*(*n*) time complexity. fn from(vec: Vec<T>) -> BinaryHeap<T> { let mut heap = BinaryHeap { data: vec }; heap.rebuild(); diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 36b5785fdf6c5..1f875f6c5217f 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -404,7 +404,7 @@ impl<T> LinkedList<T> { /// This reuses all the nodes from `other` and moves them into `self`. After /// this operation, `other` becomes empty. /// - /// This operation should compute in `O(1)` time and `O(1)` memory. + /// This operation should compute in *O*(1) time and *O*(1) memory. /// /// # Examples /// @@ -561,7 +561,7 @@ impl<T> LinkedList<T> { /// Returns `true` if the `LinkedList` is empty. /// - /// This operation should compute in `O(1)` time. + /// This operation should compute in *O*(1) time. /// /// # Examples /// @@ -582,7 +582,7 @@ impl<T> LinkedList<T> { /// Returns the length of the `LinkedList`. /// - /// This operation should compute in `O(1)` time. + /// This operation should compute in *O*(1) time. /// /// # Examples /// @@ -608,7 +608,7 @@ impl<T> LinkedList<T> { /// Removes all elements from the `LinkedList`. /// - /// This operation should compute in `O(n)` time. + /// This operation should compute in *O*(*n*) time. /// /// # Examples /// @@ -751,7 +751,7 @@ impl<T> LinkedList<T> { /// Adds an element first in the list. /// - /// This operation should compute in `O(1)` time. + /// This operation should compute in *O*(1) time. /// /// # Examples /// @@ -774,7 +774,7 @@ impl<T> LinkedList<T> { /// Removes the first element and returns it, or `None` if the list is /// empty. /// - /// This operation should compute in `O(1)` time. + /// This operation should compute in *O*(1) time. /// /// # Examples /// @@ -797,7 +797,7 @@ impl<T> LinkedList<T> { /// Appends an element to the back of a list. /// - /// This operation should compute in `O(1)` time. + /// This operation should compute in *O*(1) time. /// /// # Examples /// @@ -817,7 +817,7 @@ impl<T> LinkedList<T> { /// Removes the last element from a list and returns it, or `None` if /// it is empty. /// - /// This operation should compute in `O(1)` time. + /// This operation should compute in *O*(1) time. /// /// # Examples /// @@ -838,7 +838,7 @@ impl<T> LinkedList<T> { /// Splits the list into two at the given index. Returns everything after the given index, /// including the index. /// - /// This operation should compute in `O(n)` time. + /// This operation should compute in *O*(*n*) time. /// /// # Panics /// @@ -894,7 +894,7 @@ impl<T> LinkedList<T> { /// Removes the element at the given index and returns it. /// - /// This operation should compute in `O(n)` time. + /// This operation should compute in *O*(*n*) time. /// /// # Panics /// Panics if at >= len diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 2efb94e8afe57..fa65d6ce8d725 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1,7 +1,7 @@ //! A double-ended queue implemented with a growable ring buffer. //! -//! This queue has `O(1)` amortized inserts and removals from both ends of the -//! container. It also has `O(1)` indexing like a vector. The contained elements +//! This queue has *O*(1) amortized inserts and removals from both ends of the +//! container. It also has *O*(1) indexing like a vector. The contained elements //! are not required to be copyable, and the queue will be sendable if the //! contained type is sendable. @@ -1512,7 +1512,7 @@ impl<T> VecDeque<T> { /// Removes an element from anywhere in the `VecDeque` and returns it, /// replacing it with the first element. /// - /// This does not preserve ordering, but is `O(1)`. + /// This does not preserve ordering, but is *O*(1). /// /// Returns `None` if `index` is out of bounds. /// @@ -1547,7 +1547,7 @@ impl<T> VecDeque<T> { /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the /// last element. /// - /// This does not preserve ordering, but is `O(1)`. + /// This does not preserve ordering, but is *O*(1). /// /// Returns `None` if `index` is out of bounds. /// @@ -2331,7 +2331,7 @@ impl<T> VecDeque<T> { /// /// # Complexity /// - /// Takes `O(min(mid, len() - mid))` time and no extra space. + /// Takes `*O*(min(mid, len() - mid))` time and no extra space. /// /// # Examples /// @@ -2374,7 +2374,7 @@ impl<T> VecDeque<T> { /// /// # Complexity /// - /// Takes `O(min(k, len() - k))` time and no extra space. + /// Takes `*O*(min(k, len() - k))` time and no extra space. /// /// # Examples /// @@ -3076,7 +3076,7 @@ impl<T> From<VecDeque<T>> for Vec<T> { /// [`Vec<T>`]: crate::vec::Vec /// [`VecDeque<T>`]: crate::collections::VecDeque /// - /// This never needs to re-allocate, but does need to do `O(n)` data movement if + /// This never needs to re-allocate, but does need to do *O*(*n*) data movement if /// the circular buffer doesn't happen to be at the beginning of the allocation. /// /// # Examples @@ -3084,7 +3084,7 @@ impl<T> From<VecDeque<T>> for Vec<T> { /// ``` /// use std::collections::VecDeque; /// - /// // This one is O(1). + /// // This one is *O*(1). /// let deque: VecDeque<_> = (1..5).collect(); /// let ptr = deque.as_slices().0.as_ptr(); /// let vec = Vec::from(deque); diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 1c3879c40c2f9..15f10df9a45cc 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1162,7 +1162,7 @@ impl String { /// Removes a [`char`] from this `String` at a byte position and returns it. /// - /// This is an `O(n)` operation, as it requires copying every element in the + /// This is an *O*(*n*) operation, as it requires copying every element in the /// buffer. /// /// # Panics @@ -1262,7 +1262,7 @@ impl String { /// Inserts a character into this `String` at a byte position. /// - /// This is an `O(n)` operation as it requires copying every element in the + /// This is an *O*(*n*) operation as it requires copying every element in the /// buffer. /// /// # Panics @@ -1309,7 +1309,7 @@ impl String { /// Inserts a string slice into this `String` at a byte position. /// - /// This is an `O(n)` operation as it requires copying every element in the + /// This is an *O*(*n*) operation as it requires copying every element in the /// buffer. /// /// # Panics @@ -1971,7 +1971,7 @@ impl hash::Hash for String { /// /// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if /// necessary). This is done to avoid allocating a new `String` and copying the entire contents on -/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by +/// every operation, which would lead to *O*(*n*^2) running time when building an *n*-byte string by /// repeated concatenation. /// /// The string on the right-hand side is only borrowed; its contents are copied into the returned diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 061d1ea6b1c46..9fb7296ce31cc 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -242,7 +242,7 @@ pub mod consts { /// The full circle constant (τ) /// /// Equal to 2π. - #[unstable(feature = "tau_constant", issue = "66770")] + #[stable(feature = "tau_constant", since = "1.47.0")] pub const TAU: f32 = 6.28318530717958647692528676655900577_f32; /// π/2 diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index b0df4d64f6ee1..bcb6cd4084691 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -242,7 +242,7 @@ pub mod consts { /// The full circle constant (τ) /// /// Equal to 2π. - #[unstable(feature = "tau_constant", issue = "66770")] + #[stable(feature = "tau_constant", since = "1.47.0")] pub const TAU: f64 = 6.28318530717958647692528676655900577_f64; /// π/2 diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index d86f39c4550c8..179038d1977c8 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -39,7 +39,7 @@ use crate::hash::Hash; /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html #[doc(alias = "..")] -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; @@ -71,7 +71,7 @@ impl fmt::Debug for RangeFull { /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` #[doc(alias = "..")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct Range<Idx> { /// The lower bound of the range (inclusive). diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 20b2c3d3c965a..210ac078b4fe7 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1672,7 +1672,7 @@ impl<T> [T] { /// Sorts the slice, but may not preserve the order of equal elements. /// /// This sort is unstable (i.e., may reorder equal elements), in-place - /// (i.e., does not allocate), and `O(n * log(n))` worst-case. + /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case. /// /// # Current implementation /// @@ -1708,7 +1708,7 @@ impl<T> [T] { /// elements. /// /// This sort is unstable (i.e., may reorder equal elements), in-place - /// (i.e., does not allocate), and `O(n * log(n))` worst-case. + /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case. /// /// The comparator function must define a total ordering for the elements in the slice. If /// the ordering is not total, the order of the elements is unspecified. An order is a @@ -1763,8 +1763,8 @@ impl<T> [T] { /// elements. /// /// This sort is unstable (i.e., may reorder equal elements), in-place - /// (i.e., does not allocate), and `O(m * n * log(n))` worst-case, where the key function is - /// `O(m)`. + /// (i.e., does not allocate), and *O*(m \* *n* \* log(*n*)) worst-case, where the key function is + /// *O*(*m*). /// /// # Current implementation /// @@ -1803,7 +1803,7 @@ impl<T> [T] { /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index`. Additionally, this reordering is /// unstable (i.e. any number of equal elements may end up at position `index`), in-place - /// (i.e. does not allocate), and `O(n)` worst-case. This function is also/ known as "kth + /// (i.e. does not allocate), and *O*(*n*) worst-case. This function is also/ known as "kth /// element" in other libraries. It returns a triplet of the following values: all elements less /// than the one at the given index, the value at the given index, and all elements greater than /// the one at the given index. @@ -1852,7 +1852,7 @@ impl<T> [T] { /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the comparator function. /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function + /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function /// is also known as "kth element" in other libraries. It returns a triplet of the following /// values: all elements less than the one at the given index, the value at the given index, /// and all elements greater than the one at the given index, using the provided comparator @@ -1906,7 +1906,7 @@ impl<T> [T] { /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the key extraction function. /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function + /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function /// is also known as "kth element" in other libraries. It returns a triplet of the following /// values: all elements less than the one at the given index, the value at the given index, and /// all elements greater than the one at the given index, using the provided key extraction diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 8b2ac294764ff..972a33d6489e9 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -121,7 +121,7 @@ where /// Partially sorts a slice by shifting several out-of-order elements around. /// -/// Returns `true` if the slice is sorted at the end. This function is `O(n)` worst-case. +/// Returns `true` if the slice is sorted at the end. This function is *O*(*n*) worst-case. #[cold] fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &mut F) -> bool where @@ -168,7 +168,7 @@ where false } -/// Sorts a slice using insertion sort, which is `O(n^2)` worst-case. +/// Sorts a slice using insertion sort, which is *O*(*n*^2) worst-case. fn insertion_sort<T, F>(v: &mut [T], is_less: &mut F) where F: FnMut(&T, &T) -> bool, @@ -178,7 +178,7 @@ where } } -/// Sorts `v` using heapsort, which guarantees `O(n * log(n))` worst-case. +/// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case. #[cold] pub fn heapsort<T, F>(v: &mut [T], is_less: &mut F) where @@ -751,7 +751,7 @@ where } } -/// Sorts `v` using pattern-defeating quicksort, which is `O(n * log(n))` worst-case. +/// Sorts `v` using pattern-defeating quicksort, which is *O*(*n* \* log(*n*)) worst-case. pub fn quicksort<T, F>(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool, diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 099c402703d09..7857ccb613bf8 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -366,7 +366,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { unsafe { llvm::LLVMPointerType( self.llvm_type(cx), - cx.data_layout().instruction_address_space as c_uint, + cx.data_layout().instruction_address_space.0 as c_uint, ) } } diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index d58aad340a1dc..8a1bb258d4274 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -1330,7 +1330,12 @@ impl Builder<'a, 'll, 'tcx> { self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None); } - fn phi(&mut self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value { + pub(crate) fn phi( + &mut self, + ty: &'ll Type, + vals: &[&'ll Value], + bbs: &[&'ll BasicBlock], + ) -> &'ll Value { assert_eq!(vals.len(), bbs.len()); let phi = unsafe { llvm::LLVMBuildPhi(self.llbuilder, ty, UNNAMED) }; unsafe { diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 7b341651adf3d..75b4f2e3ca5a5 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -13,7 +13,7 @@ use log::debug; use rustc_codegen_ssa::traits::*; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; -use rustc_middle::ty::{Instance, TypeFoldable}; +use rustc_middle::ty::{self, Instance, TypeFoldable}; /// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -29,14 +29,18 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value assert!(!instance.substs.needs_infer()); assert!(!instance.substs.has_escaping_bound_vars()); - assert!(!instance.substs.has_param_types_or_consts()); if let Some(&llfn) = cx.instances.borrow().get(&instance) { return llfn; } let sym = tcx.symbol_name(instance).name; - debug!("get_fn({:?}: {:?}) => {}", instance, instance.monomorphic_ty(cx.tcx()), sym); + debug!( + "get_fn({:?}: {:?}) => {}", + instance, + instance.ty(cx.tcx(), ty::ParamEnv::reveal_all()), + sym + ); let fn_abi = FnAbi::of_instance(cx, instance, &[]); diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index 64140747871fe..0e1cd8e493d9a 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -16,7 +16,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::symbol::Symbol; -use rustc_target::abi::{self, HasDataLayout, LayoutOf, Pointer, Size}; +use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size}; use libc::{c_char, c_uint}; use log::debug; @@ -244,7 +244,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } Scalar::Ptr(ptr) => { - let base_addr = match self.tcx.global_alloc(ptr.alloc_id) { + let (base_addr, base_addr_space) = match self.tcx.global_alloc(ptr.alloc_id) { GlobalAlloc::Memory(alloc) => { let init = const_alloc_to_llvm(self, alloc); let value = match alloc.mutability { @@ -254,18 +254,21 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { if !self.sess().fewer_names() { llvm::set_value_name(value, format!("{:?}", ptr.alloc_id).as_bytes()); } - value + (value, AddressSpace::DATA) } - GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance), + GlobalAlloc::Function(fn_instance) => ( + self.get_fn_addr(fn_instance), + self.data_layout().instruction_address_space, + ), GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); - self.get_static(def_id) + (self.get_static(def_id), AddressSpace::DATA) } }; let llval = unsafe { llvm::LLVMConstInBoundsGEP( - self.const_bitcast(base_addr, self.type_i8p()), + self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)), &self.const_usize(ptr.offset.bytes()), 1, ) diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index c954415f19f34..3e9e5d9c8c1f4 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -13,14 +13,14 @@ use rustc_hir::def_id::DefId; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ - read_target_uint, Allocation, ConstValue, ErrorHandled, Pointer, + read_target_uint, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer, }; use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size}; +use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size}; use std::ffi::CStr; @@ -53,10 +53,16 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll ) .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; + + let address_space = match cx.tcx.global_alloc(alloc_id) { + GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, + GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA, + }; + llvals.push(cx.scalar_to_backend( Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(), &Scalar { value: Primitive::Pointer, valid_range: 0..=!0 }, - cx.type_i8p(), + cx.type_i8p_ext(address_space), )); next_offset = offset + pointer_size; } @@ -203,7 +209,7 @@ impl CodegenCx<'ll, 'tcx> { def_id ); - let ty = instance.monomorphic_ty(self.tcx); + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); let sym = self.tcx.symbol_name(instance).name; debug!("get_static: sym={} instance={:?}", sym, instance); @@ -361,7 +367,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { }; let instance = Instance::mono(self.tcx, def_id); - let ty = instance.monomorphic_ty(self.tcx); + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); let llty = self.layout_of(ty).llvm_type(self); let g = if val_llty == llty { g diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 21ba97d15a485..a07f6c64edcb1 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -190,7 +190,7 @@ pub unsafe fn create_module( // Control Flow Guard is currently only supported by the MSVC linker on Windows. if sess.target.target.options.is_like_msvc { - match sess.opts.debugging_opts.control_flow_guard { + match sess.opts.cg.control_flow_guard { CFGuard::Disabled => {} CFGuard::NoChecks => { // Set `cfguard=1` module flag to emit metadata only. diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index ef9d42968ae2e..6ae7c7efaee62 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -700,6 +700,8 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA) .finalize(cx) } + // Type parameters from polymorphized functions. + ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false), _ => bug!("debuginfo: unexpected type in type_metadata: {:?}", t), }; @@ -955,6 +957,20 @@ fn pointer_type_metadata( } } +fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { + debug!("param_type_metadata: {:?}", t); + let name = format!("{:?}", t); + return unsafe { + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr().cast(), + name.len(), + Size::ZERO.bits(), + DW_ATE_unsigned, + ) + }; +} + pub fn compile_unit_metadata( tcx: TyCtxt<'_>, codegen_unit_name: &str, @@ -2465,7 +2481,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global }; let is_local_to_unit = is_node_local_to_unit(cx, def_id); - let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx); + let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all()); let type_metadata = type_metadata(cx, variable_type, span); let var_name = tcx.item_name(def_id).as_str(); let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name; diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 44993d7602fe6..a01b855372129 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -26,7 +26,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::mir; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, Instance, ParamEnv, Ty}; +use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable}; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::Symbol; use rustc_span::{self, BytePos, Span}; @@ -470,7 +470,9 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { match impl_self_ty.kind { ty::Adt(def, ..) if !def.is_box() => { // Again, only create type information if full debuginfo is enabled - if cx.sess().opts.debuginfo == DebugInfo::Full { + if cx.sess().opts.debuginfo == DebugInfo::Full + && !impl_self_ty.needs_subst() + { Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP)) } else { Some(namespace::item_namespace(cx, def.did)) diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 63ec8031483fe..2e5929a433de0 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -160,7 +160,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { caller_instance: ty::Instance<'tcx>, ) { let tcx = self.tcx; - let callee_ty = instance.monomorphic_ty(tcx); + let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); let (def_id, substs) = match callee_ty.kind { ty::FnDef(def_id, substs) => (def_id, substs), diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 486ea7f22dfff..0936deb7bb5a9 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; pub use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::layout::FnAbiExt; -use rustc_middle::ty::{Instance, TypeFoldable}; +use rustc_middle::ty::{self, Instance, TypeFoldable}; use rustc_target::abi::LayoutOf; impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { @@ -22,7 +22,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { symbol_name: &str, ) { let instance = Instance::mono(self.tcx, def_id); - let ty = instance.monomorphic_ty(self.tcx); + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); let llty = self.layout_of(ty).llvm_type(self); let g = self.define_global(symbol_name, llty).unwrap_or_else(|| { @@ -47,7 +47,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { visibility: Visibility, symbol_name: &str, ) { - assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types_or_consts()); + assert!(!instance.substs.needs_infer()); let fn_abi = FnAbi::of_instance(self, instance, &[]); let lldecl = self.declare_fn(symbol_name, &fn_abi); diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs index 854eff3173380..05e364884f66d 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/src/librustc_codegen_llvm/type_.rs @@ -15,7 +15,7 @@ use rustc_middle::bug; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::Ty; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; -use rustc_target::abi::{Align, Integer, Size}; +use rustc_target::abi::{AddressSpace, Align, Integer, Size}; use std::fmt; use std::ptr; @@ -198,9 +198,13 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { assert_ne!( self.type_kind(ty), TypeKind::Function, - "don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead" + "don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead or explicitly specify an address space if it makes sense" ); - ty.ptr_to() + ty.ptr_to(AddressSpace::DATA) + } + + fn type_ptr_to_ext(&self, ty: &'ll Type, address_space: AddressSpace) -> &'ll Type { + ty.ptr_to(address_space) } fn element_type(&self, ty: &'ll Type) -> &'ll Type { @@ -241,11 +245,11 @@ impl Type { } pub fn i8p_llcx(llcx: &llvm::Context) -> &Type { - Type::i8_llcx(llcx).ptr_to() + Type::i8_llcx(llcx).ptr_to(AddressSpace::DATA) } - fn ptr_to(&self) -> &Type { - unsafe { llvm::LLVMPointerType(&self, 0) } + fn ptr_to(&self, address_space: AddressSpace) -> &Type { + unsafe { llvm::LLVMPointerType(&self, address_space.0) } } } diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 5a0da6be5980e..1d0adc5783f3d 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -7,7 +7,7 @@ use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout}; use rustc_middle::ty::print::obsolete::DefPathBasedNames; use rustc_middle::ty::{self, Ty, TypeFoldable}; -use rustc_target::abi::{Abi, Align, FieldsShape}; +use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAndLayoutMethods, Variants}; @@ -310,12 +310,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { F64 => cx.type_f64(), Pointer => { // If we know the alignment, pick something better than i8. - let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { - cx.type_pointee_for_align(pointee.align) - } else { - cx.type_i8() - }; - cx.type_ptr_to(pointee) + let (pointee, address_space) = + if let Some(pointee) = self.pointee_info_at(cx, offset) { + (cx.type_pointee_for_align(pointee.align), pointee.address_space) + } else { + (cx.type_i8(), AddressSpace::DATA) + }; + cx.type_ptr_to_ext(pointee, address_space) } } } diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs index 8bc3579800ea8..54efa05aee81e 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/src/librustc_codegen_llvm/va_arg.rs @@ -3,8 +3,9 @@ use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use rustc_codegen_ssa::mir::operand::OperandRef; -use rustc_codegen_ssa::traits::{ - BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods, +use rustc_codegen_ssa::{ + common::IntPredicate, + traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods}, }; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::Ty; @@ -89,6 +90,81 @@ fn emit_ptr_va_arg( } } +fn emit_aapcs_va_arg( + bx: &mut Builder<'a, 'll, 'tcx>, + list: OperandRef<'tcx, &'ll Value>, + target_ty: Ty<'tcx>, +) -> &'ll Value { + // Implementation of the AAPCS64 calling convention for va_args see + // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst + let va_list_addr = list.immediate(); + let layout = bx.cx.layout_of(target_ty); + + let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg"); + let mut in_reg = bx.build_sibling_block("va_arg.in_reg"); + let mut on_stack = bx.build_sibling_block("va_arg.on_stack"); + let mut end = bx.build_sibling_block("va_arg.end"); + let zero = bx.const_i32(0); + let offset_align = Align::from_bytes(4).unwrap(); + assert!(&*bx.tcx().sess.target.target.target_endian == "little"); + + let gr_type = target_ty.is_any_ptr() || target_ty.is_integral(); + let (reg_off, reg_top_index, slot_size) = if gr_type { + let gr_offs = bx.struct_gep(va_list_addr, 7); + let nreg = (layout.size.bytes() + 7) / 8; + (gr_offs, 3, nreg * 8) + } else { + let vr_off = bx.struct_gep(va_list_addr, 9); + let nreg = (layout.size.bytes() + 15) / 16; + (vr_off, 5, nreg * 16) + }; + + // if the offset >= 0 then the value will be on the stack + let mut reg_off_v = bx.load(reg_off, offset_align); + let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero); + bx.cond_br(use_stack, &on_stack.llbb(), &maybe_reg.llbb()); + + // The value at this point might be in a register, but there is a chance that + // it could be on the stack so we have to update the offset and then check + // the offset again. + + if gr_type && layout.align.abi.bytes() > 8 { + reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(15)); + reg_off_v = maybe_reg.and(reg_off_v, bx.const_i32(-16)); + } + let new_reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(slot_size as i32)); + + maybe_reg.store(new_reg_off_v, reg_off, offset_align); + + // Check to see if we have overflowed the registers as a result of this. + // If we have then we need to use the stack for this value + let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero); + maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb()); + + let top = in_reg.struct_gep(va_list_addr, reg_top_index); + let top = in_reg.load(top, bx.tcx().data_layout.pointer_align.abi); + + // reg_value = *(@top + reg_off_v); + let top = in_reg.gep(top, &[reg_off_v]); + let top = in_reg.bitcast(top, bx.cx.type_ptr_to(layout.llvm_type(bx))); + let reg_value = in_reg.load(top, layout.align.abi); + in_reg.br(&end.llbb()); + + // On Stack block + let stack_value = + emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true); + on_stack.br(&end.llbb()); + + let val = end.phi( + layout.immediate_llvm_type(bx), + &[reg_value, stack_value], + &[&in_reg.llbb(), &on_stack.llbb()], + ); + + *bx = end; + val +} + pub(super) fn emit_va_arg( bx: &mut Builder<'a, 'll, 'tcx>, addr: OperandRef<'tcx, &'ll Value>, @@ -115,6 +191,7 @@ pub(super) fn emit_va_arg( ("aarch64", _) if target.target_os == "ios" => { emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true) } + ("aarch64", _) => emit_aapcs_va_arg(bx, addr, target_ty), // Windows x86_64 ("x86_64", true) => { let target_ty_size = bx.cx.size_of(target_ty).bytes(); diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 2d65282ce7798..7c153ba0d60cb 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1700,7 +1700,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // OBJECT-FILES-NO, AUDIT-ORDER - if sess.opts.debugging_opts.control_flow_guard != CFGuard::Disabled { + if sess.opts.cg.control_flow_guard != CFGuard::Disabled { cmd.control_flow_guard(); } diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs index 20d440433cbb0..fb8f5a6298911 100644 --- a/src/librustc_codegen_ssa/debuginfo/type_names.rs +++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs @@ -205,14 +205,17 @@ pub fn push_debuginfo_type_name<'tcx>( tcx.def_key(def_id).disambiguated_data.disambiguator )); } + // Type parameters from polymorphized functions. + ty::Param(_) => { + output.push_str(&format!("{:?}", t)); + } ty::Error(_) | ty::Infer(_) | ty::Placeholder(..) | ty::Projection(..) | ty::Bound(..) | ty::Opaque(..) - | ty::GeneratorWitness(..) - | ty::Param(_) => { + | ty::GeneratorWitness(..) => { bug!( "debuginfo: Trying to create type name for \ unexpected type: {:?}", diff --git a/src/librustc_codegen_ssa/meth.rs b/src/librustc_codegen_ssa/meth.rs index 199dd8c7df42f..bcc19c6a44bd8 100644 --- a/src/librustc_codegen_ssa/meth.rs +++ b/src/librustc_codegen_ssa/meth.rs @@ -75,7 +75,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( } // Not in the cache; build it. - let nullptr = cx.const_null(cx.type_i8p()); + let nullptr = cx.const_null(cx.type_i8p_ext(cx.data_layout().instruction_address_space)); let methods_root; let methods = if let Some(trait_ref) = trait_ref { @@ -94,7 +94,8 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( def_id, substs, ) - .unwrap(), + .unwrap() + .polymorphize(cx.tcx()), ) }) }); diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index db935c2b3e265..2e386c1e5946b 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -124,8 +124,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { let base_ty = self.fx.monomorphize(&base_ty); // ZSTs don't require any actual memory access. - let elem_ty = base_ty.projection_ty(cx.tcx(), elem).ty; - let elem_ty = self.fx.monomorphize(&elem_ty); + let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(&elem)).ty; let span = self.fx.mir.local_decls[place_ref.local].source_info.span; if cx.spanned_layout_of(elem_ty, span).is_zst() { return; diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 7116bb8c92517..e1de9677f807a 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -543,7 +543,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some( ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs) .unwrap() - .unwrap(), + .unwrap() + .polymorphize(bx.tcx()), ), None, ), diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 00b4bf96afa59..f4d83e8771082 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -6,6 +6,7 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_target::abi::call::{FnAbi, PassMode}; +use rustc_target::abi::HasDataLayout; use std::iter; @@ -323,7 +324,9 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // C++ personality function, but `catch (...)` has no type so // it's null. The 64 here is actually a bitfield which // represents that this is a catch-all block. - let null = bx.const_null(bx.type_i8p()); + let null = bx.const_null( + bx.type_i8p_ext(bx.cx().data_layout().instruction_address_space), + ); let sixty_four = bx.const_i32(64); funclet = cp_bx.catch_pad(cs, &[null, sixty_four, null]); cp_bx.br(llbb); diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 4b2be7b5321ff..9c108998bc907 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -190,17 +190,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { bug!("reifying a fn ptr that requires const arguments"); } - OperandValue::Immediate( - bx.get_fn_addr( - ty::Instance::resolve_for_fn_ptr( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .unwrap(), - ), + let instance = ty::Instance::resolve_for_fn_ptr( + bx.tcx(), + ty::ParamEnv::reveal_all(), + def_id, + substs, ) + .unwrap() + .polymorphize(bx.cx().tcx()); + OperandValue::Immediate(bx.get_fn_addr(instance)) } _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), } @@ -213,7 +211,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { def_id, substs, ty::ClosureKind::FnOnce, - ); + ) + .polymorphize(bx.cx().tcx()); OperandValue::Immediate(bx.cx().get_fn_addr(instance)) } _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty), diff --git a/src/librustc_codegen_ssa/traits/type_.rs b/src/librustc_codegen_ssa/traits/type_.rs index c55bf9858b972..726d948cfd40c 100644 --- a/src/librustc_codegen_ssa/traits/type_.rs +++ b/src/librustc_codegen_ssa/traits/type_.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty}; use rustc_span::DUMMY_SP; use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg}; -use rustc_target::abi::Integer; +use rustc_target::abi::{AddressSpace, Integer}; // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. @@ -27,6 +27,7 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type; fn type_kind(&self, ty: Self::Type) -> TypeKind; fn type_ptr_to(&self, ty: Self::Type) -> Self::Type; + fn type_ptr_to_ext(&self, ty: Self::Type, address_space: AddressSpace) -> Self::Type; fn element_type(&self, ty: Self::Type) -> Self::Type; /// Returns the number of elements in `self` if it is a LLVM vector type. @@ -42,7 +43,11 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { fn type_i8p(&self) -> Self::Type { - self.type_ptr_to(self.type_i8()) + self.type_i8p_ext(AddressSpace::DATA) + } + + fn type_i8p_ext(&self, address_space: AddressSpace) -> Self::Type { + self.type_ptr_to_ext(self.type_i8(), address_space) } fn type_int(&self) -> Self::Type { diff --git a/src/librustc_data_structures/sorted_map/index_map.rs b/src/librustc_data_structures/sorted_map/index_map.rs index b7005ccdc998b..2bb421a47efa6 100644 --- a/src/librustc_data_structures/sorted_map/index_map.rs +++ b/src/librustc_data_structures/sorted_map/index_map.rs @@ -7,8 +7,8 @@ use std::iter::FromIterator; use crate::stable_hasher::{HashStable, StableHasher}; use rustc_index::vec::{Idx, IndexVec}; -/// An indexed multi-map that preserves insertion order while permitting both `O(log n)` lookup of -/// an item by key and `O(1)` lookup by index. +/// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of +/// an item by key and *O*(1) lookup by index. /// /// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`, /// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order. @@ -20,7 +20,7 @@ use rustc_index::vec::{Idx, IndexVec}; /// items will be yielded in insertion order. /// /// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and -/// `SortedIndexMultiMap` require `O(n)` time to insert a single item. This is because we may need +/// `SortedIndexMultiMap` require *O*(*n*) time to insert a single item. This is because we may need /// to insert into the middle of the sorted array. Users should avoid mutating this data structure /// in-place. /// diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 97b02eaef35d0..c1c79b174f415 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -469,6 +469,15 @@ impl<R: vec::Idx, C: vec::Idx, CTX> HashStable<CTX> for bit_set::BitMatrix<R, C> } } +impl<T, CTX> HashStable<CTX> for bit_set::FiniteBitSet<T> +where + T: HashStable<CTX> + bit_set::FiniteBitSetTy, +{ + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.0.hash_stable(hcx, hasher); + } +} + impl_stable_hash_via_hash!(::std::path::Path); impl_stable_hash_via_hash!(::std::path::PathBuf); diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index bbbd8359f0126..72302962d8603 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -453,6 +453,7 @@ E0767: include_str!("./error_codes/E0767.md"), E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), E0770: include_str!("./error_codes/E0770.md"), +E0771: include_str!("./error_codes/E0771.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard @@ -632,4 +633,5 @@ E0770: include_str!("./error_codes/E0770.md"), E0755, // `#[ffi_pure]` is only allowed on foreign functions E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` + E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/src/librustc_error_codes/error_codes/E0771.md b/src/librustc_error_codes/error_codes/E0771.md new file mode 100644 index 0000000000000..824a955f6b3f4 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0771.md @@ -0,0 +1,23 @@ +A non-`'static` lifetime was used in a const generic. This is currently not +allowed. + +Erroneous code example: + +```compile_fail,E0771 +#![feature(const_generics)] + +fn function_with_str<'a, const STRING: &'a str>() {} // error! +``` + +To fix this issue, the lifetime in the const generic need to be changed to +`'static`: + +``` +#![feature(const_generics)] + +fn function_with_str<const STRING: &'static str>() {} // ok! +``` + +For more information, see [GitHub issue #74052]. + +[GitHub issue #74052]: https://github.com/rust-lang/rust/issues/74052 diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index 4e2aea34fe7fb..879f06f89a70a 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -568,6 +568,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)), + rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")), rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)), diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index f56522406b0a7..6474dc318d329 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2198,7 +2198,17 @@ pub enum IsAsync { NotAsync, } -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +#[derive( + Copy, + Clone, + PartialEq, + RustcEncodable, + RustcDecodable, + Debug, + HashStable_Generic, + Eq, + Hash +)] pub enum Defaultness { Default { has_value: bool }, Final, diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs index 3e1d4b68c6fa1..b369be252185b 100644 --- a/src/librustc_index/bit_set.rs +++ b/src/librustc_index/bit_set.rs @@ -4,6 +4,7 @@ use std::fmt; use std::iter; use std::marker::PhantomData; use std::mem; +use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl}; use std::slice; #[cfg(test)] @@ -772,7 +773,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> { } /// Returns those indices that are true in rows `a` and `b`. This - /// is an O(n) operation where `n` is the number of elements + /// is an *O*(*n*) operation where *n* is the number of elements /// (somewhat independent from the actual size of the /// intersection, in particular). pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> { @@ -1001,3 +1002,137 @@ fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) { let mask = 1 << (elem % WORD_BITS); (word_index, mask) } + +/// Integral type used to represent the bit set. +pub trait FiniteBitSetTy: + BitAnd<Output = Self> + + BitAndAssign + + BitOrAssign + + Clone + + Copy + + Shl + + Not<Output = Self> + + PartialEq + + Sized +{ + /// Size of the domain representable by this type, e.g. 64 for `u64`. + const DOMAIN_SIZE: u32; + + /// Value which represents the `FiniteBitSet` having every bit set. + const FILLED: Self; + /// Value which represents the `FiniteBitSet` having no bits set. + const EMPTY: Self; + + /// Value for one as the integral type. + const ONE: Self; + /// Value for zero as the integral type. + const ZERO: Self; + + /// Perform a checked left shift on the integral type. + fn checked_shl(self, rhs: u32) -> Option<Self>; + /// Perform a checked right shift on the integral type. + fn checked_shr(self, rhs: u32) -> Option<Self>; +} + +impl FiniteBitSetTy for u64 { + const DOMAIN_SIZE: u32 = 64; + + const FILLED: Self = Self::MAX; + const EMPTY: Self = Self::MIN; + + const ONE: Self = 1u64; + const ZERO: Self = 0u64; + + fn checked_shl(self, rhs: u32) -> Option<Self> { + self.checked_shl(rhs) + } + + fn checked_shr(self, rhs: u32) -> Option<Self> { + self.checked_shr(rhs) + } +} + +impl std::fmt::Debug for FiniteBitSet<u64> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:064b}", self.0) + } +} + +impl FiniteBitSetTy for u128 { + const DOMAIN_SIZE: u32 = 128; + + const FILLED: Self = Self::MAX; + const EMPTY: Self = Self::MIN; + + const ONE: Self = 1u128; + const ZERO: Self = 0u128; + + fn checked_shl(self, rhs: u32) -> Option<Self> { + self.checked_shl(rhs) + } + + fn checked_shr(self, rhs: u32) -> Option<Self> { + self.checked_shr(rhs) + } +} + +impl std::fmt::Debug for FiniteBitSet<u128> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:0128b}", self.0) + } +} + +/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range +/// representable by `T` are considered set. +#[derive(Copy, Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)] +pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T); + +impl<T: FiniteBitSetTy> FiniteBitSet<T> { + /// Creates a new, empty bitset. + pub fn new_empty() -> Self { + Self(T::EMPTY) + } + + /// Sets the `index`th bit. + pub fn set(&mut self, index: u32) { + self.0 |= T::ONE.checked_shl(index).unwrap_or(T::ZERO); + } + + /// Unsets the `index`th bit. + pub fn clear(&mut self, index: u32) { + self.0 &= !T::ONE.checked_shl(index).unwrap_or(T::ZERO); + } + + /// Sets the `i`th to `j`th bits. + pub fn set_range(&mut self, range: Range<u32>) { + let bits = T::FILLED + .checked_shl(range.end - range.start) + .unwrap_or(T::ZERO) + .not() + .checked_shl(range.start) + .unwrap_or(T::ZERO); + self.0 |= bits; + } + + /// Is the set empty? + pub fn is_empty(&self) -> bool { + self.0 == T::EMPTY + } + + /// Returns the domain size of the bitset. + pub fn within_domain(&self, index: u32) -> bool { + index < T::DOMAIN_SIZE + } + + /// Returns if the `index`th bit is set. + pub fn contains(&self, index: u32) -> Option<bool> { + self.within_domain(index) + .then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE) + } +} + +impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> { + fn default() -> Self { + Self::new_empty() + } +} diff --git a/src/librustc_index/lib.rs b/src/librustc_index/lib.rs index eaef4c7b54a62..7ee881b0639da 100644 --- a/src/librustc_index/lib.rs +++ b/src/librustc_index/lib.rs @@ -1,4 +1,5 @@ #![feature(allow_internal_unstable)] +#![feature(bool_to_option)] #![feature(const_fn)] #![feature(const_panic)] #![feature(extend_one)] diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 3b564e03d9a94..c63464e5baec9 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -36,12 +36,13 @@ use crate::traits::{Obligation, PredicateObligations}; use rustc_ast::ast; use rustc_hir::def_id::DefId; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -367,10 +368,11 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { }; debug!("generalize: for_universe = {:?}", for_universe); + debug!("generalize: trace = {:?}", self.trace); let mut generalize = Generalizer { infcx: self.infcx, - span: self.trace.cause.span, + cause: &self.trace.cause, for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), for_universe, ambient_variance, @@ -414,7 +416,7 @@ struct Generalizer<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, /// The span, used when creating new type variables and things. - span: Span, + cause: &'cx ObligationCause<'tcx>, /// The vid of the type variable that is in the process of being /// instantiated; if we find this within the type we are folding, @@ -639,7 +641,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // FIXME: This is non-ideal because we don't give a // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) + Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe)) } fn consts( diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 633589db2704c..ff905faa95a9f 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -2010,7 +2010,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::MiscVariable(_) => String::new(), infer::PatternRegion(_) => " for pattern".to_string(), infer::AddrOfRegion(_) => " for borrow expression".to_string(), - infer::Autoref(_) => " for autoref".to_string(), + infer::Autoref(_, _) => " for autoref".to_string(), infer::Coercion(_) => " for automatic coercion".to_string(), infer::LateBoundRegion(_, br, infer::FnCall) => { format!(" for lifetime parameter {}in function call", br_string(br)) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index b6e971feb0e5f..4fa6d9d239424 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -2,227 +2,504 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use rustc_errors::{struct_span_err, Applicability, ErrorReported}; -use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind}; -use rustc_middle::ty::RegionKind; +use crate::infer::{SubregionOrigin, TypeTrace}; +use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; +use rustc_hir::{ + self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem, + TyKind, +}; +use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor}; +use rustc_span::symbol::Ident; +use rustc_span::{MultiSpan, Span}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// Print the error message for lifetime errors when the return type is a static impl Trait. + /// Print the error message for lifetime errors when the return type is a static `impl Trait`, + /// `dyn Trait` or if a method call on a trait object introduces a static requirement. pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> { debug!("try_report_static_impl_trait(error={:?})", self.error); - if let Some(RegionResolutionError::SubSupConflict( - _, - var_origin, - ref sub_origin, - sub_r, - ref sup_origin, - sup_r, - )) = self.error - { - debug!( - "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", - var_origin, sub_origin, sub_r, sup_origin, sup_r - ); - let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; - debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); - let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id); - if fn_returns.is_empty() { + let tcx = self.tcx(); + let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? { + RegionResolutionError::SubSupConflict( + _, + var_origin, + sub_origin, + sub_r, + sup_origin, + sup_r, + ) if **sub_r == RegionKind::ReStatic => { + (var_origin, sub_origin, sub_r, sup_origin, sup_r) + } + RegionResolutionError::ConcreteFailure( + SubregionOrigin::Subtype(box TypeTrace { cause, .. }), + sub_r, + sup_r, + ) if **sub_r == RegionKind::ReStatic => { + // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. + if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { + let param = self.find_param_with_region(sup_r, sub_r)?; + let lifetime = if sup_r.has_name() { + format!("lifetime `{}`", sup_r) + } else { + "an anonymous lifetime `'_`".to_string() + }; + let mut err = struct_span_err!( + tcx.sess, + cause.span, + E0772, + "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ + requirement", + param + .param + .pat + .simple_ident() + .map(|s| format!("`{}`", s)) + .unwrap_or_else(|| "`fn` parameter".to_string()), + lifetime, + ctxt.assoc_item.ident, + ); + err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); + err.span_label( + cause.span, + &format!( + "...is captured and required to live as long as `'static` here \ + because of an implicit lifetime bound on the {}", + match ctxt.assoc_item.container { + AssocItemContainer::TraitContainer(id) => + format!("`impl` of `{}`", tcx.def_path_str(id)), + AssocItemContainer::ImplContainer(_) => + "inherent `impl`".to_string(), + }, + ), + ); + if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { + err.emit(); + return Some(ErrorReported); + } else { + err.cancel(); + } + } return None; } - debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); - if *sub_r == RegionKind::ReStatic { - let sp = var_origin.span(); - let return_sp = sub_origin.span(); - let param_info = self.find_param_with_region(sup_r, sub_r)?; - let (lifetime_name, lifetime) = if sup_r.has_name() { - (sup_r.to_string(), format!("lifetime `{}`", sup_r)) - } else { - ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) - }; - let mut err = struct_span_err!( - self.tcx().sess, - sp, - E0759, - "cannot infer an appropriate lifetime" - ); + _ => return None, + }; + debug!( + "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", + var_origin, sub_origin, sub_r, sup_origin, sup_r + ); + let anon_reg_sup = tcx.is_suitable_region(sup_r)?; + debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); + let sp = var_origin.span(); + let return_sp = sub_origin.span(); + let param = self.find_param_with_region(sup_r, sub_r)?; + let (lifetime_name, lifetime) = if sup_r.has_name() { + (sup_r.to_string(), format!("lifetime `{}`", sup_r)) + } else { + ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) + }; + let param_name = param + .param + .pat + .simple_ident() + .map(|s| format!("`{}`", s)) + .unwrap_or_else(|| "`fn` parameter".to_string()); + let mut err = struct_span_err!( + tcx.sess, + sp, + E0759, + "{} has {} but it needs to satisfy a `'static` lifetime requirement", + param_name, + lifetime, + ); + err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); + debug!("try_report_static_impl_trait: param_info={:?}", param); + + // We try to make the output have fewer overlapping spans if possible. + if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) + && sup_origin.span() != return_sp + { + // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` + + // Customize the spans and labels depending on their relative order so + // that split sentences flow correctly. + if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { + // Avoid the following: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } + // | ---- ---------^- + // + // and instead show: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } + // | ---- ^ err.span_label( - param_info.param_ty_span, - &format!("this data with {}...", lifetime), + sup_origin.span(), + "...is captured here, requiring it to live as long as `'static`", ); - debug!("try_report_static_impl_trait: param_info={:?}", param_info); + } else { + err.span_label(sup_origin.span(), "...is captured here..."); + if return_sp < sup_origin.span() { + err.span_note( + return_sp, + "...and is required to live as long as `'static` here", + ); + } else { + err.span_label( + return_sp, + "...and is required to live as long as `'static` here", + ); + } + } + } else { + err.span_label( + return_sp, + "...is captured and required to live as long as `'static` here", + ); + } + + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); - // We try to make the output have fewer overlapping spans if possible. - if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) - && sup_origin.span() != return_sp + let mut override_error_code = None; + if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { + if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { + // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a + // `'static` lifetime when called as a method on a binding: `bar.qux()`. + if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { + override_error_code = Some(ctxt.assoc_item.ident); + } + } + } + if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin { + if let ObligationCauseCode::ItemObligation(item_def_id) = cause.code { + // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static` + // lifetime as above, but called using a fully-qualified path to the method: + // `Foo::qux(bar)`. + let mut v = TraitObjectVisitor(vec![]); + v.visit_ty(param.param_ty); + if let Some((ident, self_ty)) = + self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0[..]) { - // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` - - // Customize the spans and labels depending on their relative order so - // that split sentences flow correctly. - if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { - // Avoid the following: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } - // | ---- ---------^- - // - // and instead show: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } - // | ---- ^ - err.span_label( - sup_origin.span(), - "...is captured here, requiring it to live as long as `'static`", + if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0[..], ident, self_ty) + { + override_error_code = Some(ident); + } + } + } + } + if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) { + // Provide a more targetted error code and description. + err.code(rustc_errors::error_code!(E0772)); + err.set_primary_message(&format!( + "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ + requirement", + param_name, lifetime, ident, + )); + } + + debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); + // FIXME: account for the need of parens in `&(dyn Trait + '_)` + let consider = "consider changing the"; + let declare = "to declare that the"; + let arg = match param.param.pat.simple_ident() { + Some(simple_ident) => format!("argument `{}`", simple_ident), + None => "the argument".to_string(), + }; + let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name); + let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg); + let captures = format!("captures data from {}", arg); + let add_static_bound = "alternatively, add an explicit `'static` bound to this reference"; + let plus_lt = format!(" + {}", lifetime_name); + for fn_return in fn_returns { + if fn_return.span.desugaring_kind().is_some() { + // Skip `async` desugaring `impl Future`. + continue; + } + match fn_return.kind { + TyKind::OpaqueDef(item_id, _) => { + let item = tcx.hir().item(item_id.id); + let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { + opaque + } else { + err.emit(); + return Some(ErrorReported); + }; + + if let Some(span) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { + name: LifetimeName::Static, + span, + .. + }) => Some(*span), + _ => None, + }) + .next() + { + err.span_suggestion_verbose( + span, + &format!("{} `impl Trait`'s {}", consider, explicit_static), + lifetime_name.clone(), + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param.param_ty_span, + add_static_bound, + param.param_ty.to_string(), + Applicability::MaybeIncorrect, ); + } else if let Some(_) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { name, span, .. }) + if name.ident().to_string() == lifetime_name => + { + Some(*span) + } + _ => None, + }) + .next() + { } else { - err.span_label(sup_origin.span(), "...is captured here..."); - if return_sp < sup_origin.span() { - err.span_note( - return_sp, - "...and is required to live as long as `'static` here", - ); - } else { - err.span_label( - return_sp, - "...and is required to live as long as `'static` here", - ); - } + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} `impl Trait` {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt.clone(), + Applicability::MaybeIncorrect, + ); } - } else { - err.span_label( - return_sp, - "...is captured and required to live as long as `'static` here", - ); } + TyKind::TraitObject(_, lt) => match lt.name { + LifetimeName::ImplicitObjectLifetimeDefault => { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} trait object {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt.clone(), + Applicability::MaybeIncorrect, + ); + } + name if name.ident().to_string() != lifetime_name => { + // With this check we avoid suggesting redundant bounds. This + // would happen if there are nested impl/dyn traits and only + // one of them has the bound we'd suggest already there, like + // in `impl Foo<X = dyn Bar> + '_`. + err.span_suggestion_verbose( + lt.span, + &format!("{} trait object's {}", consider, explicit_static), + lifetime_name.clone(), + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param.param_ty_span, + add_static_bound, + param.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } + _ => {} + }, + _ => {} + } + } + err.emit(); + Some(ErrorReported) + } - // FIXME: account for the need of parens in `&(dyn Trait + '_)` - let consider = "consider changing the"; - let declare = "to declare that the"; - let arg = match param_info.param.pat.simple_ident() { - Some(simple_ident) => format!("argument `{}`", simple_ident), - None => "the argument".to_string(), - }; - let explicit = - format!("you can add an explicit `{}` lifetime bound", lifetime_name); - let explicit_static = - format!("explicit `'static` bound to the lifetime of {}", arg); - let captures = format!("captures data from {}", arg); - let add_static_bound = - "alternatively, add an explicit `'static` bound to this reference"; - let plus_lt = format!(" + {}", lifetime_name); - for fn_return in fn_returns { - if fn_return.span.desugaring_kind().is_some() { - // Skip `async` desugaring `impl Future`. - continue; + fn get_impl_ident_and_self_ty_from_trait( + &self, + def_id: DefId, + trait_objects: &[DefId], + ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> { + let tcx = self.tcx(); + match tcx.hir().get_if_local(def_id) { + Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => { + match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) { + Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => { + Some((*ident, self_ty)) } - match fn_return.kind { - TyKind::OpaqueDef(item_id, _) => { - let item = self.tcx().hir().item(item_id.id); - let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { - opaque - } else { - err.emit(); - return Some(ErrorReported); - }; - - if let Some(span) = opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { - name: LifetimeName::Static, - span, + _ => None, + } + } + Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => { + let parent_id = tcx.hir().get_parent_item(*hir_id); + match tcx.hir().find(parent_id) { + Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => { + // The method being called is defined in the `trait`, but the `'static` + // obligation comes from the `impl`. Find that `impl` so that we can point + // at it in the suggestion. + let trait_did = tcx.hir().local_def_id(parent_id).to_def_id(); + match tcx + .hir() + .trait_impls(trait_did) + .iter() + .filter_map(|impl_node| { + let impl_did = tcx.hir().local_def_id(*impl_node); + match tcx.hir().get_if_local(impl_did.to_def_id()) { + Some(Node::Item(Item { + kind: ItemKind::Impl { self_ty, .. }, .. - }) => Some(*span), - _ => None, - }) - .next() - { - err.span_suggestion_verbose( - span, - &format!("{} `impl Trait`'s {}", consider, explicit_static), - lifetime_name.clone(), - Applicability::MaybeIncorrect, - ); - err.span_suggestion_verbose( - param_info.param_ty_span, - add_static_bound, - param_info.param_ty.to_string(), - Applicability::MaybeIncorrect, - ); - } else if let Some(_) = opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { name, span, .. }) - if name.ident().to_string() == lifetime_name => + })) if trait_objects.iter().all(|did| { + // FIXME: we should check `self_ty` against the receiver + // type in the `UnifyReceiver` context, but for now, use + // this imperfect proxy. This will fail if there are + // multiple `impl`s for the same trait like + // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`. + // In that case, only the first one will get suggestions. + let mut hir_v = HirTraitObjectVisitor(vec![], *did); + hir_v.visit_ty(self_ty); + !hir_v.0.is_empty() + }) => { - Some(*span) + Some(self_ty) } _ => None, - }) - .next() - { - } else { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "{declare} `impl Trait` {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), - plus_lt.clone(), - Applicability::MaybeIncorrect, - ); - } + } + }) + .next() + { + Some(self_ty) => Some((*ident, self_ty)), + _ => None, } - TyKind::TraitObject(_, lt) => match lt.name { - LifetimeName::ImplicitObjectLifetimeDefault => { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "{declare} trait object {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), - plus_lt.clone(), - Applicability::MaybeIncorrect, - ); - } - name if name.ident().to_string() != lifetime_name => { - // With this check we avoid suggesting redundant bounds. This - // would happen if there are nested impl/dyn traits and only - // one of them has the bound we'd suggest already there, like - // in `impl Foo<X = dyn Bar> + '_`. - err.span_suggestion_verbose( - lt.span, - &format!("{} trait object's {}", consider, explicit_static), - lifetime_name.clone(), - Applicability::MaybeIncorrect, - ); - err.span_suggestion_verbose( - param_info.param_ty_span, - add_static_bound, - param_info.param_ty.to_string(), - Applicability::MaybeIncorrect, - ); - } - _ => {} - }, - _ => {} + } + _ => None, + } + } + _ => None, + } + } + + /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default + /// `'static` obligation. Suggest relaxing that implicit bound. + fn find_impl_on_dyn_trait( + &self, + err: &mut DiagnosticBuilder<'_>, + ty: Ty<'_>, + ctxt: &UnifyReceiverContext<'tcx>, + ) -> bool { + let tcx = self.tcx(); + + // Find the method being called. + let instance = match ty::Instance::resolve( + tcx, + ctxt.param_env, + ctxt.assoc_item.def_id, + self.infcx.resolve_vars_if_possible(&ctxt.substs), + ) { + Ok(Some(instance)) => instance, + _ => return false, + }; + + let mut v = TraitObjectVisitor(vec![]); + v.visit_ty(ty); + + // Get the `Ident` of the method being called and the corresponding `impl` (to point at + // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called). + let (ident, self_ty) = + match self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0[..]) { + Some((ident, self_ty)) => (ident, self_ty), + None => return false, + }; + + // Find the trait object types in the argument, so we point at *only* the trait object. + self.suggest_constrain_dyn_trait_in_impl(err, &v.0[..], ident, self_ty) + } + + fn suggest_constrain_dyn_trait_in_impl( + &self, + err: &mut DiagnosticBuilder<'_>, + found_dids: &[DefId], + ident: Ident, + self_ty: &hir::Ty<'_>, + ) -> bool { + let mut suggested = false; + for found_did in found_dids { + let mut hir_v = HirTraitObjectVisitor(vec![], *found_did); + hir_v.visit_ty(&self_ty); + for span in &hir_v.0 { + let mut multi_span: MultiSpan = vec![*span].into(); + multi_span.push_span_label( + *span, + "this has an implicit `'static` lifetime requirement".to_string(), + ); + multi_span.push_span_label( + ident.span, + "calling this method introduces the `impl`'s 'static` requirement".to_string(), + ); + err.span_note(multi_span, "the used `impl` has a `'static` requirement"); + err.span_suggestion_verbose( + span.shrink_to_hi(), + "consider relaxing the implicit `'static` requirement", + " + '_".to_string(), + Applicability::MaybeIncorrect, + ); + suggested = true; + } + } + suggested + } +} + +/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime. +struct TraitObjectVisitor(Vec<DefId>); + +impl TypeVisitor<'_> for TraitObjectVisitor { + fn visit_ty(&mut self, t: Ty<'_>) -> bool { + match t.kind { + ty::Dynamic(preds, RegionKind::ReStatic) => { + if let Some(def_id) = preds.principal_def_id() { + self.0.push(def_id); + } + false + } + _ => t.super_visit_with(self), + } + } +} + +/// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime. +struct HirTraitObjectVisitor(Vec<Span>, DefId); + +impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor { + type Map = ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { + match t.kind { + TyKind::TraitObject( + poly_trait_refs, + Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) => { + for ptr in poly_trait_refs { + if Some(self.1) == ptr.trait_ref.trait_def_id() { + self.0.push(ptr.span); } } - err.emit(); - return Some(ErrorReported); } + _ => {} } - None + walk_ty(self, t); } } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs index fa999abb1a86c..28e9dd90cfd67 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs @@ -7,20 +7,18 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, DefIdTree, Region, Ty}; use rustc_span::Span; -// The struct contains the information about the anonymous region -// we are searching for. +/// Information about the anonymous region we are searching for. #[derive(Debug)] pub(super) struct AnonymousParamInfo<'tcx> { - // the parameter corresponding to the anonymous region + /// The parameter corresponding to the anonymous region. pub param: &'tcx hir::Param<'tcx>, - // the type corresponding to the anonymopus region parameter + /// The type corresponding to the anonymous region parameter. pub param_ty: Ty<'tcx>, - // the ty::BoundRegion corresponding to the anonymous region + /// The ty::BoundRegion corresponding to the anonymous region. pub bound_region: ty::BoundRegion, - // param_ty_span contains span of parameter type + /// The `Span` of the parameter type. pub param_ty_span: Span, - // corresponds to id the argument is the first parameter - // in the declaration + /// Signals that the argument is the first parameter in the declaration. pub is_first: bool, } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 37883fcb07468..3744ad5d0324a 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -463,7 +463,7 @@ pub enum RegionVariableOrigin { AddrOfRegion(Span), /// Regions created as part of an autoref of a method receiver - Autoref(Span), + Autoref(Span, ty::AssocItem), /// Regions created as part of an automatic coercion Coercion(Span), @@ -1800,15 +1800,15 @@ impl<'tcx> SubregionOrigin<'tcx> { impl RegionVariableOrigin { pub fn span(&self) -> Span { match *self { - MiscVariable(a) => a, - PatternRegion(a) => a, - AddrOfRegion(a) => a, - Autoref(a) => a, - Coercion(a) => a, - EarlyBoundRegion(a, ..) => a, - LateBoundRegion(a, ..) => a, + MiscVariable(a) + | PatternRegion(a) + | AddrOfRegion(a) + | Autoref(a, _) + | Coercion(a) + | EarlyBoundRegion(a, ..) + | LateBoundRegion(a, ..) + | UpvarRegion(_, a) => a, BoundRegionInCoherence(_) => rustc_span::DUMMY_SP, - UpvarRegion(_, a) => a, NLL(..) => bug!("NLL variable used with `span`"), } } diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs index 0cd6585163c4e..bacb7fa153e43 100644 --- a/src/librustc_infer/lib.rs +++ b/src/librustc_infer/lib.rs @@ -13,6 +13,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 3c549b8852368..22197a66530dd 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -420,6 +420,7 @@ fn test_codegen_options_tracking_hash() { // Make sure that changing a [TRACKED] option changes the hash. // This list is in alphabetical order. tracked!(code_model, Some(CodeModel::Large)); + tracked!(control_flow_guard, CFGuard::Checks); tracked!(debug_assertions, Some(true)); tracked!(debuginfo, 0xdeadbeef); tracked!(embed_bitcode, false); @@ -537,7 +538,6 @@ fn test_debugging_options_tracking_hash() { tracked!(binary_dep_depinfo, true); tracked!(chalk, true); tracked!(codegen_backend, Some("abc".to_string())); - tracked!(control_flow_guard, CFGuard::Checks); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index 4fc02e348f646..1a034294cd8eb 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -14,8 +14,8 @@ static-libstdcpp = [] emscripten = [] [dependencies] -libc = "0.2" +libc = "0.2.73" [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0.1" +cc = "1.0.58" diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 4746e53ce59a9..a6d708ebe9048 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -1132,6 +1132,16 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } + fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u64> { + self.root + .tables + .unused_generic_params + .get(self, id) + .filter(|_| !self.is_proc_macro(id)) + .map(|params| params.decode(self)) + .unwrap_or_default() + } + fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> { self.root .tables diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index be153758a2a0c..9160327c1d1b5 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -113,6 +113,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, } optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } + unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index a8c46d3e32e6a..186828b6a19f6 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -1065,6 +1065,8 @@ impl EncodeContext<'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) { record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id)); + record!(self.tables.unused_generic_params[def_id.to_def_id()] <- + self.tcx.unused_generic_params(def_id)); } } diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 8abc3784d6d2f..e616e8cf00a2f 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -9,7 +9,7 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, DefIndex}; use rustc_hir::lang_items; -use rustc_index::vec::IndexVec; +use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; @@ -277,6 +277,7 @@ define_tables! { super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>, mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>, promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>, + unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u64>>>, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs index 1ad5008d28a98..bb204223b6060 100644 --- a/src/librustc_middle/mir/mono.rs +++ b/src/librustc_middle/mir/mono.rs @@ -168,7 +168,7 @@ impl<'tcx> MonoItem<'tcx> { MonoItem::GlobalAsm(..) => return true, }; - tcx.substitute_normalize_and_test_predicates((def_id, &substs)) + !tcx.subst_and_check_impossible_predicates((def_id, &substs)) } pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String { diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 4dd8723bd72a1..f857af28622d1 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -103,9 +103,13 @@ rustc_queries! { /// // ^ While calling `opt_const_param_of` for other bodies returns `None`. /// } /// ``` + // It looks like caching this query on disk actually slightly + // worsened performance in #74376. + // + // Once const generics are more prevalently used, we might want to + // consider only caching calls returning `Some`. query opt_const_param_of(key: LocalDefId) -> Option<DefId> { desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) } - // FIXME(#74113): consider storing this query on disk. } /// Records the type of every item. @@ -1309,6 +1313,13 @@ rustc_queries! { query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } + query unused_generic_params(key: DefId) -> FiniteBitSet<u64> { + cache_on_disk_if { key.is_local() } + desc { + |tcx| "determining which generic parameters are unused by `{}`", + tcx.def_path_str(key) + } + } query backend_optimization_level(_: CrateNum) -> OptLevel { desc { "optimization level used by backend" } } @@ -1461,9 +1472,9 @@ rustc_queries! { desc { "normalizing `{:?}`", goal } } - query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { + query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { desc { |tcx| - "testing substituted normalized predicates:`{}`", + "impossible substituted predicates:`{}`", tcx.def_path_str(key.0) } } diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index c15c31a53f0c9..d2747e5fc659b 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -169,6 +169,13 @@ impl<'tcx> ObligationCause<'tcx> { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct UnifyReceiverContext<'tcx> { + pub assoc_item: ty::AssocItem, + pub param_env: ty::ParamEnv<'tcx>, + pub substs: SubstsRef<'tcx>, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. @@ -300,6 +307,8 @@ pub enum ObligationCauseCode<'tcx> { /// Method receiver MethodReceiver, + UnifyReceiver(Box<UnifyReceiverContext<'tcx>>), + /// `return` with no expression ReturnNoExpression, diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index 334462790edbc..18b4371053a89 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -213,12 +213,26 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::StartFunctionType => Some(super::StartFunctionType), super::IntrinsicType => Some(super::IntrinsicType), super::MethodReceiver => Some(super::MethodReceiver), + super::UnifyReceiver(ref ctxt) => tcx.lift(ctxt).map(|ctxt| super::UnifyReceiver(ctxt)), super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), super::TrivialBound => Some(super::TrivialBound), } } } +impl<'a, 'tcx> Lift<'tcx> for traits::UnifyReceiverContext<'a> { + type Lifted = traits::UnifyReceiverContext<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + tcx.lift(&self.param_env).and_then(|param_env| { + tcx.lift(&self.substs).map(|substs| traits::UnifyReceiverContext { + assoc_item: self.assoc_item, + param_env, + substs, + }) + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { type Lifted = traits::DerivedObligationCause<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index 0e86fcf53b247..11a8bedb6605b 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -85,7 +85,19 @@ impl FlagComputation { } &ty::Generator(_, ref substs, _) => { - self.add_substs(substs); + let substs = substs.as_generator(); + let should_remove_further_specializable = + !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + self.add_substs(substs.parent_substs()); + if should_remove_further_specializable { + self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; + } + + self.add_ty(substs.resume_ty()); + self.add_ty(substs.return_ty()); + self.add_ty(substs.witness()); + self.add_ty(substs.yield_ty()); + self.add_ty(substs.tupled_upvars_ty()); } &ty::GeneratorWitness(ts) => { @@ -95,7 +107,17 @@ impl FlagComputation { } &ty::Closure(_, substs) => { - self.add_substs(substs); + let substs = substs.as_closure(); + let should_remove_further_specializable = + !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + self.add_substs(substs.parent_substs()); + if should_remove_further_specializable { + self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; + } + + self.add_ty(substs.sig_as_fn_ptr_ty()); + self.add_ty(substs.kind_ty()); + self.add_ty(substs.tupled_upvars_ty()); } &ty::Bound(debruijn, _) => { diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index f627d05d3e9d2..cdb883da32bb0 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -1,5 +1,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::print::{FmtPrinter, Printer}; +use crate::ty::subst::InternalSubsts; use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable}; use rustc_errors::ErrorReported; use rustc_hir::def::Namespace; @@ -106,32 +107,9 @@ pub enum InstanceDef<'tcx> { } impl<'tcx> Instance<'tcx> { - /// Returns the `Ty` corresponding to this `Instance`, - /// with generic substitutions applied and lifetimes erased. - /// - /// This method can only be called when the 'substs' for this Instance - /// are fully monomorphic (no `ty::Param`'s are present). - /// This is usually the case (e.g. during codegen). - /// However, during constant evaluation, we may want - /// to try to resolve a `Instance` using generic parameters - /// (e.g. when we are attempting to to do const-propagation). - /// In this case, `Instance.ty_env` should be used to provide - /// the `ParamEnv` for our generic context. - pub fn monomorphic_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - let ty = tcx.type_of(self.def.def_id()); - // There shouldn't be any params - if there are, then - // Instance.ty_env should have been used to provide the proper - // ParamEnv - if self.substs.has_param_types_or_consts() { - bug!("Instance.ty called for type {:?} with params in substs: {:?}", ty, self.substs); - } - tcx.subst_and_normalize_erasing_regions(self.substs, ty::ParamEnv::reveal_all(), &ty) - } - - /// Like `Instance.ty`, but allows a `ParamEnv` to be specified for use during - /// normalization. This method is only really useful during constant evaluation, - /// where we are dealing with potentially generic types. - pub fn ty_env(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> { + /// Returns the `Ty` corresponding to this `Instance`, with generic substitutions applied and + /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization. + pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> { let ty = tcx.type_of(self.def.def_id()); tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty) } @@ -486,6 +464,42 @@ impl<'tcx> Instance<'tcx> { | InstanceDef::VtableShim(..) => Some(self.substs), } } + + /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by + /// identify parameters if they are determined to be unused in `instance.def`. + pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self { + debug!("polymorphize: running polymorphization analysis"); + if !tcx.sess.opts.debugging_opts.polymorphize { + return self; + } + + if let InstanceDef::Item(def) = self.def { + let unused = tcx.unused_generic_params(def.did); + + if unused.is_empty() { + // Exit early if every parameter was used. + return self; + } + + debug!("polymorphize: unused={:?}", unused); + let polymorphized_substs = + InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind { + // If parameter is a const or type parameter.. + ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if + // ..and is within range and unused.. + unused.contains(param.index).unwrap_or(false) => + // ..then use the identity for this parameter. + tcx.mk_param_from_def(param), + // Otherwise, use the parameter as before. + _ => self.substs[param.index as usize], + }); + + debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); + Self { def: self.def, substs: polymorphized_substs } + } else { + self + } + } } fn needs_fn_once_adapter_shim( diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 8ae9269a6bf68..dc775b15927fa 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -2166,16 +2166,31 @@ where } fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<PointeeInfo> { - match this.ty.kind { + let addr_space_of_ty = |ty: Ty<'tcx>| { + if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA } + }; + + let pointee_info = match this.ty.kind { ty::RawPtr(mt) if offset.bytes() == 0 => { cx.layout_of(mt.ty).to_result().ok().map(|layout| PointeeInfo { size: layout.size, align: layout.align.abi, safe: None, + address_space: addr_space_of_ty(mt.ty), + }) + } + ty::FnPtr(fn_sig) if offset.bytes() == 0 => { + cx.layout_of(cx.tcx().mk_fn_ptr(fn_sig)).to_result().ok().map(|layout| { + PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: None, + address_space: cx.data_layout().instruction_address_space, + } }) } - ty::Ref(_, ty, mt) if offset.bytes() == 0 => { + let address_space = addr_space_of_ty(ty); let tcx = cx.tcx(); let is_freeze = ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()); let kind = match mt { @@ -2210,6 +2225,7 @@ where size: layout.size, align: layout.align.abi, safe: Some(kind), + address_space, }) } @@ -2254,7 +2270,9 @@ where result = field.to_result().ok().and_then(|field| { if ptr_end <= field_start + field.size { // We found the right field, look inside it. - field.pointee_info_at(cx, offset - field_start) + let field_info = + field.pointee_info_at(cx, offset - field_start); + field_info } else { None } @@ -2277,7 +2295,14 @@ where result } - } + }; + + debug!( + "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}", + offset, this.ty.kind, pointee_info + ); + + pointee_info } } @@ -2299,12 +2324,22 @@ impl<'tcx> ty::Instance<'tcx> { // or should go through `FnAbi` instead, to avoid losing any // adjustments `FnAbi::of_instance` might be performing. fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - let ty = self.monomorphic_ty(tcx); + // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function. + let ty = self.ty(tcx, ty::ParamEnv::reveal_all()); match ty.kind { - ty::FnDef(..) | - // Shims currently have type FnPtr. Not sure this should remain. - ty::FnPtr(_) => { - let mut sig = ty.fn_sig(tcx); + ty::FnDef(..) => { + // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering + // parameters unused if they show up in the signature, but not in the `mir::Body` + // (i.e. due to being inside a projection that got normalized, see + // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping + // track of a polymorphization `ParamEnv` to allow normalizing later. + let mut sig = match ty.kind { + ty::FnDef(def_id, substs) => tcx + .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id)) + .subst(tcx, substs), + _ => unreachable!(), + }; + if let ty::InstanceDef::VtableShim(..) = self.def { // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. sig = sig.map_bound(|mut sig| { @@ -2320,13 +2355,15 @@ impl<'tcx> ty::Instance<'tcx> { let sig = substs.as_closure().sig(); let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); - sig.map_bound(|sig| tcx.mk_fn_sig( - iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi - )) + sig.map_bound(|sig| { + tcx.mk_fn_sig( + iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), + sig.output(), + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }) } ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); @@ -2342,10 +2379,8 @@ impl<'tcx> ty::Instance<'tcx> { sig.map_bound(|sig| { let state_did = tcx.require_lang_item(GeneratorStateLangItem, None); let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[ - sig.yield_ty.into(), - sig.return_ty.into(), - ]); + let state_substs = + tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); tcx.mk_fn_sig( @@ -2353,11 +2388,11 @@ impl<'tcx> ty::Instance<'tcx> { &ret_ty, false, hir::Unsafety::Normal, - rustc_target::spec::abi::Abi::Rust + rustc_target::spec::abi::Abi::Rust, ) }) } - _ => bug!("unexpected type {:?} in Instance::fn_sig", ty) + _ => bug!("unexpected type {:?} in Instance::fn_sig", ty), } } } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 21745977b04b1..9007bd99d7e4b 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -136,7 +136,7 @@ pub struct ResolverOutputs { pub extern_prelude: FxHashMap<Symbol, bool>, } -#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)] pub enum AssocItemContainer { TraitContainer(DefId), ImplContainer(DefId), @@ -184,7 +184,7 @@ pub enum ImplPolarity { Reservation, } -#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)] pub struct AssocItem { pub def_id: DefId, #[stable_hasher(project(name))] @@ -199,7 +199,7 @@ pub struct AssocItem { pub fn_has_self_parameter: bool, } -#[derive(Copy, Clone, PartialEq, Debug, HashStable)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)] pub enum AssocKind { Const, Fn, @@ -316,7 +316,7 @@ impl<'tcx> AssociatedItems<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable, Hash)] pub enum Visibility { /// Visible everywhere (including in other crates). Public, @@ -890,6 +890,7 @@ impl<'tcx> Generics { false } + /// Returns the `GenericParamDef` with the given index. pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef { if let Some(index) = param_index.checked_sub(self.parent_count) { &self.params[index] @@ -899,6 +900,7 @@ impl<'tcx> Generics { } } + /// Returns the `GenericParamDef` associated with this `EarlyBoundRegion`. pub fn region_param( &'tcx self, param: &EarlyBoundRegion, @@ -920,7 +922,7 @@ impl<'tcx> Generics { } } - /// Returns the `ConstParameterDef` associated with this `ParamConst`. + /// Returns the `GenericParamDef` associated with this `ParamConst`. pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { let param = self.param_at(param.index as usize, tcx); match param.kind { diff --git a/src/librustc_middle/ty/normalize_erasing_regions.rs b/src/librustc_middle/ty/normalize_erasing_regions.rs index 2f0a57c59eb14..48a62b6460467 100644 --- a/src/librustc_middle/ty/normalize_erasing_regions.rs +++ b/src/librustc_middle/ty/normalize_erasing_regions.rs @@ -54,7 +54,6 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable<'tcx>, { - assert!(!value.needs_subst()); let value = self.erase_late_bound_regions(value); self.normalize_erasing_regions(param_env, value) } diff --git a/src/librustc_middle/ty/print/obsolete.rs b/src/librustc_middle/ty/print/obsolete.rs index 67b6433b61143..2ea7cd2a6dc7a 100644 --- a/src/librustc_middle/ty/print/obsolete.rs +++ b/src/librustc_middle/ty/print/obsolete.rs @@ -144,12 +144,14 @@ impl DefPathBasedNames<'tcx> { let substs = substs.truncate_to(self.tcx, generics); self.push_generic_params(substs, iter::empty(), output, debug); } + ty::Param(_) => { + output.push_str(&t.to_string()); + } ty::Error(_) | ty::Bound(..) | ty::Infer(_) | ty::Placeholder(..) | ty::Projection(..) - | ty::Param(_) | ty::GeneratorWitness(_) | ty::Opaque(..) => { if debug { diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs index 2ad49b1acce43..2f7a9aee536d8 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/src/librustc_middle/ty/query/mod.rs @@ -44,7 +44,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate}; -use rustc_index::vec::IndexVec; +use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::utils::NativeLibKind; use rustc_session::CrateDisambiguator; diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 2f17db6223362..03bf51c95c5a3 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -318,6 +318,7 @@ pub struct ClosureSubsts<'tcx> { /// Struct returned by `split()`. Note that these are subslices of the /// parent slice and not canonical substs themselves. struct SplitClosureSubsts<'tcx> { + parent: &'tcx [GenericArg<'tcx>], closure_kind_ty: GenericArg<'tcx>, closure_sig_as_fn_ptr_ty: GenericArg<'tcx>, tupled_upvars_ty: GenericArg<'tcx>, @@ -329,8 +330,13 @@ impl<'tcx> ClosureSubsts<'tcx> { /// ordering. fn split(self) -> SplitClosureSubsts<'tcx> { match self.substs[..] { - [.., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { - SplitClosureSubsts { closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty } + [ref parent @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { + SplitClosureSubsts { + parent, + closure_kind_ty, + closure_sig_as_fn_ptr_ty, + tupled_upvars_ty, + } } _ => bug!("closure substs missing synthetics"), } @@ -345,9 +351,20 @@ impl<'tcx> ClosureSubsts<'tcx> { self.substs.len() >= 3 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_)) } + /// Returns the substitutions of the closure's parent. + pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] { + self.split().parent + } + #[inline] pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx { - self.split().tupled_upvars_ty.expect_ty().tuple_fields() + self.tupled_upvars_ty().tuple_fields() + } + + /// Returns the tuple type representing the upvars for this closure. + #[inline] + pub fn tupled_upvars_ty(self) -> Ty<'tcx> { + self.split().tupled_upvars_ty.expect_ty() } /// Returns the closure kind for this closure; may return a type @@ -392,6 +409,7 @@ pub struct GeneratorSubsts<'tcx> { } struct SplitGeneratorSubsts<'tcx> { + parent: &'tcx [GenericArg<'tcx>], resume_ty: GenericArg<'tcx>, yield_ty: GenericArg<'tcx>, return_ty: GenericArg<'tcx>, @@ -402,8 +420,15 @@ struct SplitGeneratorSubsts<'tcx> { impl<'tcx> GeneratorSubsts<'tcx> { fn split(self) -> SplitGeneratorSubsts<'tcx> { match self.substs[..] { - [.., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => { - SplitGeneratorSubsts { resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty } + [ref parent @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => { + SplitGeneratorSubsts { + parent, + resume_ty, + yield_ty, + return_ty, + witness, + tupled_upvars_ty, + } } _ => bug!("generator substs missing synthetics"), } @@ -418,6 +443,11 @@ impl<'tcx> GeneratorSubsts<'tcx> { self.substs.len() >= 5 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_)) } + /// Returns the substitutions of the generator's parent. + pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] { + self.split().parent + } + /// This describes the types that can be contained in a generator. /// It will be a type variable initially and unified in the last stages of typeck of a body. /// It contains a tuple of all the types that could end up on a generator frame. @@ -429,7 +459,13 @@ impl<'tcx> GeneratorSubsts<'tcx> { #[inline] pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx { - self.split().tupled_upvars_ty.expect_ty().tuple_fields() + self.tupled_upvars_ty().tuple_fields() + } + + /// Returns the tuple type representing the upvars for this generator. + #[inline] + pub fn tupled_upvars_ty(self) -> Ty<'tcx> { + self.split().tupled_upvars_ty.expect_ty() } /// Returns the type representing the resume type of the generator. diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index dc3e01f3d1561..705a1b2ae79e5 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -240,7 +240,7 @@ pub fn const_eval_validated_provider<'tcx>( // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty_env(tcx, key.param_env); + let ty = key.value.instance.ty(tcx, key.param_env); let substs = match ty.kind { ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 5836fc9c95a80..29549041d258c 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size}; @@ -54,6 +54,9 @@ crate fn eval_nullary_intrinsic<'tcx>( let name = tcx.item_name(def_id); Ok(match name { sym::type_name => { + if tp_ty.needs_subst() { + throw_inval!(TooGeneric); + } let alloc = type_name::alloc_type_name(tcx, tp_ty); ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } } @@ -68,7 +71,12 @@ crate fn eval_nullary_intrinsic<'tcx>( }; ConstValue::from_machine_usize(n, &tcx) } - sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)), + sym::type_id => { + if tp_ty.needs_subst() { + throw_inval!(TooGeneric); + } + ConstValue::from_u64(tcx.type_id_hash(tp_ty)) + } sym::variant_count => { if let ty::Adt(ref adt, _) = tp_ty.kind { ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 4681079a22ddf..663f61b11554c 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -221,7 +221,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // ABI check { let callee_abi = { - let instance_ty = instance.ty_env(*self.tcx, self.param_env); + let instance_ty = instance.ty(*self.tcx, self.param_env); match instance_ty.kind { ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(), ty::Closure(..) => Abi::RustCall, diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index a1d124bb7602e..49a80ca13457d 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -142,7 +142,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // to determine the type. let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?; trace!("Found drop fn: {:?}", drop_instance); - let fn_sig = drop_instance.ty_env(*self.tcx, self.param_env).fn_sig(*self.tcx); + let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig); // The drop function takes `*mut T` where `T` is the type being dropped, so get that. let args = fn_sig.inputs(); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index cd6c38997f18f..4e7142a93aedc 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -51,6 +51,7 @@ pub fn provide(providers: &mut Providers) { shim::provide(providers); transform::provide(providers); monomorphize::partitioning::provide(providers); + monomorphize::polymorphize::provide(providers); providers.const_eval_validated = const_eval::const_eval_validated_provider; providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.const_caller_location = const_eval::const_caller_location; diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 35fb950ce66b9..0b5f27fc17a72 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -358,9 +358,9 @@ fn collect_items_rec<'tcx>( let instance = Instance::mono(tcx, def_id); // Sanity check whether this ended up being collected accidentally - debug_assert!(should_monomorphize_locally(tcx, &instance)); + debug_assert!(should_codegen_locally(tcx, &instance)); - let ty = instance.monomorphic_ty(tcx); + let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors); recursion_depth_reset = None; @@ -371,7 +371,7 @@ fn collect_items_rec<'tcx>( } MonoItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally - debug_assert!(should_monomorphize_locally(tcx, &instance)); + debug_assert!(should_codegen_locally(tcx, &instance)); // Keep track of the monomorphization recursion depth recursion_depth_reset = @@ -584,8 +584,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { substs, ty::ClosureKind::FnOnce, ); - if should_monomorphize_locally(self.tcx, &instance) { - self.output.push(create_fn_mono_item(instance, span)); + if should_codegen_locally(self.tcx, &instance) { + self.output.push(create_fn_mono_item(self.tcx, instance, span)); } } _ => bug!(), @@ -596,14 +596,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let exchange_malloc_fn_def_id = tcx.require_lang_item(ExchangeMallocFnLangItem, None); let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); - if should_monomorphize_locally(tcx, &instance) { - self.output.push(create_fn_mono_item(instance, span)); + if should_codegen_locally(tcx, &instance) { + self.output.push(create_fn_mono_item(self.tcx, instance, span)); } } mir::Rvalue::ThreadLocalRef(def_id) => { assert!(self.tcx.is_thread_local_static(def_id)); let instance = Instance::mono(self.tcx, def_id); - if should_monomorphize_locally(self.tcx, &instance) { + if should_codegen_locally(self.tcx, &instance) { trace!("collecting thread-local static {:?}", def_id); self.output.push(respan(span, MonoItem::Static(def_id))); } @@ -664,7 +664,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::InlineAsmOperand::SymStatic { def_id } => { let instance = Instance::mono(self.tcx, def_id); - if should_monomorphize_locally(self.tcx, &instance) { + if should_codegen_locally(self.tcx, &instance) { trace!("collecting asm sym static {:?}", def_id); self.output.push(respan(source, MonoItem::Static(def_id))); } @@ -735,7 +735,7 @@ fn visit_instance_use<'tcx>( output: &mut Vec<Spanned<MonoItem<'tcx>>>, ) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); - if !should_monomorphize_locally(tcx, &instance) { + if !should_codegen_locally(tcx, &instance) { return; } @@ -748,7 +748,7 @@ fn visit_instance_use<'tcx>( ty::InstanceDef::DropGlue(_, None) => { // Don't need to emit noop drop glue if we are calling directly. if !is_direct_call { - output.push(create_fn_mono_item(instance, source)); + output.push(create_fn_mono_item(tcx, instance, source)); } } ty::InstanceDef::DropGlue(_, Some(_)) @@ -758,7 +758,7 @@ fn visit_instance_use<'tcx>( | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::CloneShim(..) => { - output.push(create_fn_mono_item(instance, source)); + output.push(create_fn_mono_item(tcx, instance, source)); } } } @@ -766,7 +766,7 @@ fn visit_instance_use<'tcx>( // Returns `true` if we should codegen an instance in the local crate. // Returns `false` if we can just link to the upstream crate and therefore don't // need a mono item. -fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { +fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { let def_id = match instance.def { ty::InstanceDef::Item(def) => def.did, ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id, @@ -781,20 +781,19 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx }; if tcx.is_foreign_item(def_id) { - // Foreign items are always linked against, there's no way of - // instantiating them. + // Foreign items are always linked against, there's no way of instantiating them. return false; } if def_id.is_local() { - // Local items cannot be referred to locally without - // monomorphizing them locally. + // Local items cannot be referred to locally without monomorphizing them locally. return true; } - if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() { - // We can link to the item in question, no instance needed - // in this crate. + if tcx.is_reachable_non_generic(def_id) + || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() + { + // We can link to the item in question, no instance needed in this crate. return false; } @@ -903,9 +902,13 @@ fn find_vtable_types_for_unsizing<'tcx>( } } -fn create_fn_mono_item(instance: Instance<'_>, source: Span) -> Spanned<MonoItem<'_>> { +fn create_fn_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + source: Span, +) -> Spanned<MonoItem<'tcx>> { debug!("create_fn_mono_item(instance={})", instance); - respan(source, MonoItem::Fn(instance)) + respan(source, MonoItem::Fn(instance.polymorphize(tcx))) } /// Creates a `MonoItem` for each method that is referenced by the vtable for @@ -917,12 +920,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( source: Span, output: &mut Vec<Spanned<MonoItem<'tcx>>>, ) { - assert!( - !trait_ty.needs_subst() - && !trait_ty.has_escaping_bound_vars() - && !impl_ty.needs_subst() - && !impl_ty.has_escaping_bound_vars() - ); + assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars()); if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind { if let Some(principal) = trait_ty.principal() { @@ -944,8 +942,8 @@ fn create_mono_items_for_vtable_methods<'tcx>( ) .unwrap() }) - .filter(|&instance| should_monomorphize_locally(tcx, &instance)) - .map(|item| create_fn_mono_item(item, source)); + .filter(|&instance| should_codegen_locally(tcx, &instance)) + .map(|item| create_fn_mono_item(tcx, item, source)); output.extend(methods); } @@ -997,7 +995,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { ); let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty()) - .monomorphic_ty(self.tcx); + .ty(self.tcx, ty::ParamEnv::reveal_all()); visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output); } } @@ -1069,7 +1067,7 @@ impl RootCollector<'_, 'v> { debug!("RootCollector::push_if_root: found root def_id={:?}", def_id); let instance = Instance::mono(self.tcx, def_id.to_def_id()); - self.output.push(create_fn_mono_item(instance, DUMMY_SP)); + self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP)); } } @@ -1106,7 +1104,7 @@ impl RootCollector<'_, 'v> { .unwrap() .unwrap(); - self.output.push(create_fn_mono_item(start_instance, DUMMY_SP)); + self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); } } @@ -1163,9 +1161,8 @@ fn create_mono_items_for_default_impls<'tcx>( .unwrap() .unwrap(); - let mono_item = create_fn_mono_item(instance, DUMMY_SP); - if mono_item.node.is_instantiable(tcx) - && should_monomorphize_locally(tcx, &instance) + let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); + if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance) { output.push(mono_item); } @@ -1186,7 +1183,7 @@ fn collect_miri<'tcx>( GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); let instance = Instance::mono(tcx, def_id); - if should_monomorphize_locally(tcx, &instance) { + if should_codegen_locally(tcx, &instance) { trace!("collecting static {:?}", def_id); output.push(dummy_spanned(MonoItem::Static(def_id))); } @@ -1200,9 +1197,9 @@ fn collect_miri<'tcx>( } } GlobalAlloc::Function(fn_instance) => { - if should_monomorphize_locally(tcx, &fn_instance) { + if should_codegen_locally(tcx, &fn_instance) { trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); - output.push(create_fn_mono_item(fn_instance, DUMMY_SP)); + output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); } } } diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 76c1c465a8be0..15d7b11124071 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -6,6 +6,7 @@ use rustc_hir::lang_items::CoerceUnsizedTraitLangItem; pub mod collector; pub mod partitioning; +pub mod polymorphize; pub fn custom_coerce_unsize_info<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs new file mode 100644 index 0000000000000..071b9bb971139 --- /dev/null +++ b/src/librustc_mir/monomorphize/polymorphize.rs @@ -0,0 +1,285 @@ +//! Polymorphization Analysis +//! ========================= +//! +//! This module implements an analysis of functions, methods and closures to determine which +//! generic parameters are unused (and eventually, in what ways generic parameters are used - only +//! for their size, offset of a field, etc.). + +use rustc_hir::{def::DefKind, def_id::DefId}; +use rustc_index::bit_set::FiniteBitSet; +use rustc_middle::mir::{ + visit::{TyContext, Visitor}, + Local, LocalDecl, Location, +}; +use rustc_middle::ty::{ + self, + fold::{TypeFoldable, TypeVisitor}, + query::Providers, + Const, Ty, TyCtxt, +}; +use rustc_span::symbol::sym; +use std::convert::TryInto; + +/// Provide implementations of queries relating to polymorphization analysis. +pub fn provide(providers: &mut Providers) { + providers.unused_generic_params = unused_generic_params; +} + +/// Determine which generic parameters are used by the function/method/closure represented by +/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty` +/// indicates all parameters are used). +fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u64> { + debug!("unused_generic_params({:?})", def_id); + + if !tcx.sess.opts.debugging_opts.polymorphize { + // If polymorphization disabled, then all parameters are used. + return FiniteBitSet::new_empty(); + } + + let generics = tcx.generics_of(def_id); + debug!("unused_generic_params: generics={:?}", generics); + + // Exit early when there are no parameters to be unused. + if generics.count() == 0 { + return FiniteBitSet::new_empty(); + } + + // Exit early when there is no MIR available. + if !tcx.is_mir_available(def_id) { + debug!("unused_generic_params: (no mir available) def_id={:?}", def_id); + return FiniteBitSet::new_empty(); + } + + // Create a bitset with N rightmost ones for each parameter. + let generics_count: u32 = + generics.count().try_into().expect("more generic parameters than can fit into a `u32`"); + let mut unused_parameters = FiniteBitSet::<u64>::new_empty(); + unused_parameters.set_range(0..generics_count); + debug!("unused_generic_params: (start) unused_parameters={:?}", unused_parameters); + mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); + debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters); + + // Visit MIR and accumululate used generic parameters. + let body = tcx.optimized_mir(def_id); + let mut vis = + UsedGenericParametersVisitor { tcx, def_id, unused_parameters: &mut unused_parameters }; + vis.visit_body(body); + debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters); + + mark_used_by_predicates(tcx, def_id, &mut unused_parameters); + debug!("unused_generic_params: (end) unused_parameters={:?}", unused_parameters); + + // Emit errors for debugging and testing if enabled. + if !unused_parameters.is_empty() { + emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters); + } + + unused_parameters +} + +/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy +/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should +/// be `true` if the item that `unused_generic_params` was invoked on is a closure. +fn mark_used_by_default_parameters<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + generics: &'tcx ty::Generics, + unused_parameters: &mut FiniteBitSet<u64>, +) { + if !tcx.is_trait(def_id) && (tcx.is_closure(def_id) || tcx.type_of(def_id).is_generator()) { + for param in &generics.params { + debug!("mark_used_by_default_parameters: (closure/gen) param={:?}", param); + unused_parameters.clear(param.index); + } + } else { + for param in &generics.params { + debug!("mark_used_by_default_parameters: (other) param={:?}", param); + if let ty::GenericParamDefKind::Lifetime = param.kind { + unused_parameters.clear(param.index); + } + } + } + + if let Some(parent) = generics.parent { + mark_used_by_default_parameters(tcx, parent, tcx.generics_of(parent), unused_parameters); + } +} + +/// Search the predicates on used generic parameters for any unused generic parameters, and mark +/// those as used. +fn mark_used_by_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + unused_parameters: &mut FiniteBitSet<u64>, +) { + let def_id = tcx.closure_base_def_id(def_id); + + let is_self_ty_used = |unused_parameters: &mut FiniteBitSet<u64>, self_ty: Ty<'tcx>| { + debug!("unused_generic_params: self_ty={:?}", self_ty); + if let ty::Param(param) = self_ty.kind { + !unused_parameters.contains(param.index).unwrap_or(false) + } else { + false + } + }; + + let mark_ty = |unused_parameters: &mut FiniteBitSet<u64>, ty: Ty<'tcx>| { + let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters }; + ty.visit_with(&mut vis); + }; + + let predicates = tcx.explicit_predicates_of(def_id); + debug!("mark_parameters_used_in_predicates: predicates_of={:?}", predicates); + for (predicate, _) in predicates.predicates { + match predicate.kind() { + ty::PredicateKind::Trait(predicate, ..) => { + let trait_ref = predicate.skip_binder().trait_ref; + if is_self_ty_used(unused_parameters, trait_ref.self_ty()) { + for ty in trait_ref.substs.types() { + debug!("unused_generic_params: (trait) ty={:?}", ty); + mark_ty(unused_parameters, ty); + } + } + } + ty::PredicateKind::Projection(predicate, ..) => { + let self_ty = predicate.skip_binder().projection_ty.self_ty(); + if is_self_ty_used(unused_parameters, self_ty) { + let ty = predicate.ty(); + debug!("unused_generic_params: (projection) ty={:?}", ty); + mark_ty(unused_parameters, ty.skip_binder()); + } + } + _ => (), + } + } +} + +/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic +/// parameter which was unused. +fn emit_unused_generic_params_error<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + generics: &'tcx ty::Generics, + unused_parameters: &FiniteBitSet<u64>, +) { + debug!("emit_unused_generic_params_error: def_id={:?}", def_id); + let base_def_id = tcx.closure_base_def_id(def_id); + if !tcx.get_attrs(base_def_id).iter().any(|a| a.check_name(sym::rustc_polymorphize_error)) { + return; + } + + debug!("emit_unused_generic_params_error: unused_parameters={:?}", unused_parameters); + let fn_span = match tcx.opt_item_name(def_id) { + Some(ident) => ident.span, + _ => tcx.def_span(def_id), + }; + + let mut err = tcx.sess.struct_span_err(fn_span, "item has unused generic parameters"); + + let mut next_generics = Some(generics); + while let Some(generics) = next_generics { + for param in &generics.params { + if unused_parameters.contains(param.index).unwrap_or(false) { + debug!("emit_unused_generic_params_error: param={:?}", param); + let def_span = tcx.def_span(param.def_id); + err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name)); + } + } + + next_generics = generics.parent.map(|did| tcx.generics_of(did)); + } + + err.emit(); +} + +/// Visitor used to aggregate generic parameter uses. +struct UsedGenericParametersVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + def_id: DefId, + unused_parameters: &'a mut FiniteBitSet<u64>, +} + +impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> { + fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { + debug!("visit_local_decl: local_decl={:?}", local_decl); + if local == Local::from_usize(1) { + let def_kind = self.tcx.def_kind(self.def_id); + if matches!(def_kind, DefKind::Closure | DefKind::Generator) { + // Skip visiting the closure/generator that is currently being processed. This only + // happens because the first argument to the closure is a reference to itself and + // that will call `visit_substs`, resulting in each generic parameter captured being + // considered used by default. + debug!("visit_local_decl: skipping closure substs"); + return; + } + } + + self.super_local_decl(local, local_decl); + } + + fn visit_const(&mut self, c: &&'tcx Const<'tcx>, _: Location) { + c.visit_with(self); + } + + fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) { + ty.visit_with(self); + } +} + +impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> { + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool { + debug!("visit_const: c={:?}", c); + if !c.has_param_types_or_consts() { + return false; + } + + match c.val { + ty::ConstKind::Param(param) => { + debug!("visit_const: param={:?}", param); + self.unused_parameters.clear(param.index); + false + } + _ => c.super_visit_with(self), + } + } + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + debug!("visit_ty: ty={:?}", ty); + if !ty.has_param_types_or_consts() { + return false; + } + + match ty.kind { + ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => { + debug!("visit_ty: def_id={:?}", def_id); + // Avoid cycle errors with generators. + if def_id == self.def_id { + return false; + } + + // Consider any generic parameters used by any closures/generators as used in the + // parent. + let unused = self.tcx.unused_generic_params(def_id); + debug!( + "visit_ty: unused_parameters={:?} unused={:?}", + self.unused_parameters, unused + ); + for (i, arg) in substs.iter().enumerate() { + let i = i.try_into().unwrap(); + if !unused.contains(i).unwrap_or(false) { + arg.visit_with(self); + } + } + debug!("visit_ty: unused_parameters={:?}", self.unused_parameters); + + false + } + ty::Param(param) => { + debug!("visit_ty: param={:?}", param); + self.unused_parameters.clear(param.index); + false + } + _ => ty.super_visit_with(self), + } + } +} diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 98286cddea68b..bfa9bb9e0f0e1 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -4,7 +4,7 @@ use rustc_hir::lang_items::FnMutTraitLangItem; use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use rustc_index::vec::{Idx, IndexVec}; @@ -36,11 +36,6 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None) } ty::InstanceDef::FnPtrShim(def_id, ty) => { - // FIXME(eddyb) support generating shims for a "shallow type", - // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic - // `Foo<Bar>` or `[String]` etc. - assert!(!ty.needs_subst()); - let trait_ = tcx.trait_of_item(def_id).unwrap(); let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) { Some(ty::ClosureKind::FnOnce) => Adjustment::Identity, @@ -83,22 +78,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' None, ) } - ty::InstanceDef::DropGlue(def_id, ty) => { - // FIXME(eddyb) support generating shims for a "shallow type", - // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic - // `Foo<Bar>` or `[String]` etc. - assert!(!ty.needs_subst()); - - build_drop_shim(tcx, def_id, ty) - } - ty::InstanceDef::CloneShim(def_id, ty) => { - // FIXME(eddyb) support generating shims for a "shallow type", - // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic - // `Foo<Bar>` or `[String]` etc. - assert!(!ty.needs_subst()); - - build_clone_shim(tcx, def_id, ty) - } + ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty), + ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), ty::InstanceDef::Virtual(..) => { bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 237a5a64f8bf8..3073bf53afd78 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -116,7 +116,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { .predicates .iter() .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); - if !traits::normalize_and_test_predicates( + if traits::impossible_predicates( tcx, traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(), ) { diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index ed88e54969215..261c2031364f6 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1500,11 +1500,17 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { pat_src: PatternSource, bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>, ) { + let is_tuple_struct_pat = matches!(pat.kind, PatKind::TupleStruct(_, _)); + // Visit all direct subpatterns of this pattern. pat.walk(&mut |pat| { debug!("resolve_pattern pat={:?} node={:?}", pat, pat.kind); match pat.kind { - PatKind::Ident(bmode, ident, ref sub) => { + // In tuple struct patterns ignore the invalid `ident @ ...`. + // It will be handled as an error by the AST lowering. + PatKind::Ident(bmode, ident, ref sub) + if !(is_tuple_struct_pat && sub.as_ref().filter(|p| p.is_rest()).is_some()) => + { // First try to resolve the identifier as some existing entity, // then fall back to a fresh binding. let has_sub = sub.is_some(); diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 9323c15a94109..c86b414184759 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -1141,6 +1141,24 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { err.emit(); } + // FIXME(const_generics): This patches over a ICE caused by non-'static lifetimes in const + // generics. We are disallowing this until we can decide on how we want to handle non-'static + // lifetimes in const generics. See issue #74052 for discussion. + crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &hir::Lifetime) { + let mut err = struct_span_err!( + self.tcx.sess, + lifetime_ref.span, + E0771, + "use of non-static lifetime `{}` in const generic", + lifetime_ref + ); + err.note( + "for more information, see issue #74052 \ + <https://github.com/rust-lang/rust/issues/74052>", + ); + err.emit(); + } + crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool { if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res { if [ diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index 567db8edec9af..6009e48a54f5e 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -173,6 +173,8 @@ crate struct LifetimeContext<'a, 'tcx> { /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. is_in_fn_syntax: bool, + is_in_const_generic: bool, + /// List of labels in the function/method currently under analysis. labels_in_fn: Vec<Ident>, @@ -333,6 +335,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap { scope: ROOT_SCOPE, trait_ref_hack: false, is_in_fn_syntax: false, + is_in_const_generic: false, labels_in_fn: vec![], xcrate_object_lifetime_defaults: Default::default(), lifetime_uses: &mut Default::default(), @@ -828,6 +831,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, Region::Static); return; } + if self.is_in_const_generic && lifetime_ref.name != LifetimeName::Error { + self.emit_non_static_lt_in_const_generic_error(lifetime_ref); + return; + } self.resolve_lifetime_ref(lifetime_ref); } @@ -860,8 +867,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } GenericParamKind::Const { ref ty, .. } => { + let was_in_const_generic = self.is_in_const_generic; + self.is_in_const_generic = true; walk_list!(self, visit_param_bound, param.bounds); self.visit_ty(&ty); + self.is_in_const_generic = was_in_const_generic; } } } @@ -1317,6 +1327,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope: &wrap_scope, trait_ref_hack: self.trait_ref_hack, is_in_fn_syntax: self.is_in_fn_syntax, + is_in_const_generic: self.is_in_const_generic, labels_in_fn, xcrate_object_lifetime_defaults, lifetime_uses, diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 839ffa5785ada..620a04b45b0e4 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -103,7 +103,7 @@ pub enum Strip { Symbols, } -/// The different settings that the `-Z control-flow-guard` flag can have. +/// The different settings that the `-C control-flow-guard` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum CFGuard { /// Do not emit Control Flow Guard metadata or checks. diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 8c1f6a7749740..099d11264225e 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -692,6 +692,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "choose the code model to use (`rustc --print code-models` for details)"), codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED], "divide crate into N units to optimize in parallel"), + 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], "explicitly enable the `cfg(debug_assertions)` directive"), debuginfo: usize = (0, parse_uint, [TRACKED], @@ -809,8 +811,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable the experimental Chalk-based trait solving engine"), codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED], "the backend to use"), - control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED], - "use Windows Control Flow Guard (default: no)"), crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), debug_macros: bool = (false, parse_bool, [TRACKED], @@ -949,6 +949,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, (default: PLT is disabled if full relro is enabled)"), polonius: bool = (false, parse_bool, [UNTRACKED], "enable polonius-based borrow-checker (default: no)"), + polymorphize: bool = (true, parse_bool, [TRACKED], + "perform polymorphization analysis"), pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED], "a single extra argument to prepend the linker invocation (can be used several times)"), pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED], diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 5d332ddf5f3df..22a5115c7f556 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -921,6 +921,7 @@ symbols! { rustc_peek_liveness, rustc_peek_maybe_init, rustc_peek_maybe_uninit, + rustc_polymorphize_error, rustc_private, rustc_proc_macro_decls, rustc_promotable, diff --git a/src/librustc_symbol_mangling/legacy.rs b/src/librustc_symbol_mangling/legacy.rs index 3038b0c6bd7eb..90c89ea6b0a86 100644 --- a/src/librustc_symbol_mangling/legacy.rs +++ b/src/librustc_symbol_mangling/legacy.rs @@ -116,7 +116,6 @@ fn get_symbol_hash<'tcx>( // also include any type parameters (for generic items) assert!(!substs.has_erasable_regions()); - assert!(!substs.needs_subst()); substs.hash_stable(&mut hcx, &mut hasher); if let Some(instantiating_crate) = instantiating_crate { diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index c79e9bb289008..b3e5f5c0c74b1 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -32,7 +32,7 @@ pub struct TargetDataLayout { /// Alignments for vector types. pub vector_align: Vec<(Size, AbiAndPrefAlign)>, - pub instruction_address_space: u32, + pub instruction_address_space: AddressSpace, } impl Default for TargetDataLayout { @@ -56,7 +56,7 @@ impl Default for TargetDataLayout { (Size::from_bits(64), AbiAndPrefAlign::new(align(64))), (Size::from_bits(128), AbiAndPrefAlign::new(align(128))), ], - instruction_address_space: 0, + instruction_address_space: AddressSpace::DATA, } } } @@ -65,7 +65,7 @@ impl TargetDataLayout { pub fn parse(target: &Target) -> Result<TargetDataLayout, String> { // Parse an address space index from a string. let parse_address_space = |s: &str, cause: &str| { - s.parse::<u32>().map_err(|err| { + s.parse::<u32>().map(AddressSpace).map_err(|err| { format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err) }) }; @@ -744,6 +744,17 @@ impl FieldsShape { } } +/// An identifier that specifies the address space that some operation +/// should operate on. Special address spaces have an effect on code generation, +/// depending on the target and the address spaces it implements. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct AddressSpace(pub u32); + +impl AddressSpace { + /// The default address space, corresponding to data space. + pub const DATA: Self = AddressSpace(0); +} + /// Describes how values of the type are passed by target ABIs, /// in terms of categories of C types there are ABI rules for. #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] @@ -1013,7 +1024,7 @@ impl<T, E> MaybeResult<T> for Result<T, E> { } } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PointerKind { /// Most general case, we know no restrictions to tell LLVM. Shared, @@ -1028,11 +1039,12 @@ pub enum PointerKind { UniqueOwned, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct PointeeInfo { pub size: Size, pub align: Align, pub safe: Option<PointerKind>, + pub address_space: AddressSpace, } pub trait TyAndLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized { diff --git a/src/librustc_target/spec/aarch64_apple_darwin.rs b/src/librustc_target/spec/aarch64_apple_darwin.rs new file mode 100644 index 0000000000000..60daf10b36afe --- /dev/null +++ b/src/librustc_target/spec/aarch64_apple_darwin.rs @@ -0,0 +1,30 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::apple_base::opts(); + base.cpu = "apple-a12".to_string(); + base.max_atomic_width = Some(128); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]); + + base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); + + // Clang automatically chooses a more specific target based on + // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work + // correctly, we do too. + let arch = "aarch64"; + let llvm_target = super::apple_base::macos_llvm_target(&arch); + + Ok(Target { + llvm_target, + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), + arch: arch.to_string(), + target_os: "macos".to_string(), + target_env: String::new(), + target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base }, + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index d53033ba3ba20..5a97ef441c203 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -574,6 +574,7 @@ supported_targets! { ("i686-unknown-haiku", i686_unknown_haiku), ("x86_64-unknown-haiku", x86_64_unknown_haiku), + ("aarch64-apple-darwin", aarch64_apple_darwin), ("x86_64-apple-darwin", x86_64_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), diff --git a/src/librustc_target/spec/x86_64_apple_darwin.rs b/src/librustc_target/spec/x86_64_apple_darwin.rs index 31011e8474958..909aebec70b58 100644 --- a/src/librustc_target/spec/x86_64_apple_darwin.rs +++ b/src/librustc_target/spec/x86_64_apple_darwin.rs @@ -5,7 +5,10 @@ pub fn target() -> TargetResult { base.cpu = "core2".to_string(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.eliminate_frame_pointer = false; - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); + base.pre_link_args.insert( + LinkerFlavor::Gcc, + vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()], + ); base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); base.stack_probes = true; diff --git a/src/librustc_trait_selection/traits/codegen/mod.rs b/src/librustc_trait_selection/traits/codegen/mod.rs index cf575d3eca9c2..dd7ea55cc1043 100644 --- a/src/librustc_trait_selection/traits/codegen/mod.rs +++ b/src/librustc_trait_selection/traits/codegen/mod.rs @@ -6,6 +6,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::{ FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, + Unimplemented, }; use rustc_errors::ErrorReported; use rustc_middle::ty::fold::TypeFoldable; @@ -58,6 +59,18 @@ pub fn codegen_fulfill_obligation<'tcx>( ); return Err(ErrorReported); } + Err(Unimplemented) => { + // This can trigger when we probe for the source of a `'static` lifetime requirement + // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. + infcx.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + &format!( + "Encountered error `Unimplemented` selecting `{:?}` during codegen", + trait_ref + ), + ); + return Err(ErrorReported); + } Err(e) => { bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 0a6fb72ca51ea..0632ce2319aee 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1706,6 +1706,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression + | ObligationCauseCode::UnifyReceiver(..) | ObligationCauseCode::MiscObligation => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index e8006129e3ef8..1c3755222495e 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -418,15 +418,14 @@ where Ok(resolved_value) } -/// Normalizes the predicates and checks whether they hold in an empty -/// environment. If this returns false, then either normalize -/// encountered an error or one of the predicates did not hold. Used -/// when creating vtables to check for unsatisfiable methods. -pub fn normalize_and_test_predicates<'tcx>( +/// Normalizes the predicates and checks whether they hold in an empty environment. If this +/// returns true, then either normalize encountered an error or one of the predicates did not +/// hold. Used when creating vtables to check for unsatisfiable methods. +pub fn impossible_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: Vec<ty::Predicate<'tcx>>, ) -> bool { - debug!("normalize_and_test_predicates(predicates={:?})", predicates); + debug!("impossible_predicates(predicates={:?})", predicates); let result = tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::reveal_all(); @@ -443,22 +442,23 @@ pub fn normalize_and_test_predicates<'tcx>( fulfill_cx.register_predicate_obligation(&infcx, obligation); } - fulfill_cx.select_all_or_error(&infcx).is_ok() + fulfill_cx.select_all_or_error(&infcx).is_err() }); - debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result); + debug!("impossible_predicates(predicates={:?}) = {:?}", predicates, result); result } -fn substitute_normalize_and_test_predicates<'tcx>( +fn subst_and_check_impossible_predicates<'tcx>( tcx: TyCtxt<'tcx>, key: (DefId, SubstsRef<'tcx>), ) -> bool { - debug!("substitute_normalize_and_test_predicates(key={:?})", key); + debug!("subst_and_check_impossible_predicates(key={:?})", key); - let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; - let result = normalize_and_test_predicates(tcx, predicates); + let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; + predicates.retain(|predicate| !predicate.needs_subst()); + let result = impossible_predicates(tcx, predicates); - debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result); + debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); result } @@ -510,7 +510,7 @@ fn vtable_methods<'tcx>( // Note that this method could then never be called, so we // do not want to try and codegen it, in that case (see #23435). let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); - if !normalize_and_test_predicates(tcx, predicates.predicates) { + if impossible_predicates(tcx, predicates.predicates) { debug!("vtable_methods: predicates do not hold"); return None; } @@ -558,8 +558,8 @@ pub fn provide(providers: &mut ty::query::Providers) { specializes: specialize::specializes, codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_methods, - substitute_normalize_and_test_predicates, type_implements_trait, + subst_and_check_impossible_predicates, ..*providers }; } diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs index 0bc6c47097868..324ae4ec29e9b 100644 --- a/src/librustc_ty/instance.rs +++ b/src/librustc_ty/instance.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable}; -use rustc_span::sym; +use rustc_span::{sym, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use traits::{translate_substs, Reveal}; @@ -67,12 +67,19 @@ fn inner_resolve_instance<'tcx>( let ty = substs.type_at(0); if ty.needs_drop(tcx, param_env) { - // `DropGlue` requires a monomorphic aka concrete type. - if ty.needs_subst() { - return Ok(None); + debug!(" => nontrivial drop glue"); + match ty.kind { + ty::Closure(..) + | ty::Generator(..) + | ty::Tuple(..) + | ty::Adt(..) + | ty::Dynamic(..) + | ty::Array(..) + | ty::Slice(..) => {} + // Drop shims can only be built from ADTs. + _ => return Ok(None), } - debug!(" => nontrivial drop glue"); ty::InstanceDef::DropGlue(def_id, Some(ty)) } else { debug!(" => trivial drop glue"); @@ -224,17 +231,13 @@ fn resolve_associated_item<'tcx>( trait_closure_kind, )) } - traits::ImplSourceFnPointer(ref data) => { - // `FnPtrShim` requires a monomorphic aka concrete type. - if data.fn_ty.needs_subst() { - return Ok(None); - } - - Some(Instance { + traits::ImplSourceFnPointer(ref data) => match data.fn_ty.kind { + ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), substs: rcvr_substs, - }) - } + }), + _ => None, + }, traits::ImplSourceObject(ref data) => { let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) @@ -246,10 +249,12 @@ fn resolve_associated_item<'tcx>( if name == sym::clone { let self_ty = trait_ref.self_ty(); - // `CloneShim` requires a monomorphic aka concrete type. - if self_ty.needs_subst() { - return Ok(None); - } + let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); + match self_ty.kind { + _ if is_copy => (), + ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {} + _ => return Ok(None), + }; Some(Instance { def: ty::InstanceDef::CloneShim(def_id, self_ty), diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 96248e18aaf87..ed84095ae6b0c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -6,6 +6,7 @@ use crate::hir::def_id::DefId; use crate::hir::GenericArg; use rustc_hir as hir; use rustc_infer::infer::{self, InferOk}; +use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; @@ -91,7 +92,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // signature (which is also done during probing). let method_sig_rcvr = self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]); - self.unify_receivers(self_ty, method_sig_rcvr); + debug!( + "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}", + self_ty, method_sig_rcvr, method_sig, method_predicates + ); + self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs); let (method_sig, method_predicates) = self.normalize_associated_types_in(self.span, &(method_sig, method_predicates)); @@ -150,7 +155,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); if let Some(mutbl) = pick.autoref { - let region = self.next_region_var(infer::Autoref(self.span)); + let region = self.next_region_var(infer::Autoref(self.span, pick.item)); target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target }); let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, @@ -334,8 +339,26 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) } - fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { - match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) { + fn unify_receivers( + &mut self, + self_ty: Ty<'tcx>, + method_self_ty: Ty<'tcx>, + pick: &probe::Pick<'tcx>, + substs: SubstsRef<'tcx>, + ) { + debug!( + "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}", + self_ty, method_self_ty, self.span, pick + ); + let cause = self.cause( + self.span, + ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext { + assoc_item: pick.item, + param_env: self.param_env, + substs, + })), + ); + match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 845a4fcafc224..dabae6cbc4137 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; use rustc_session::parse::feature_err; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -142,8 +142,8 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { _ => unreachable!(), } } - hir::ItemKind::Fn(..) => { - check_item_fn(tcx, item); + hir::ItemKind::Fn(ref sig, ..) => { + check_item_fn(tcx, item.hir_id, item.ident, item.span, sig.decl); } hir::ItemKind::Static(ref ty, ..) => { check_item_type(tcx, item.hir_id, ty.span, false); @@ -153,8 +153,14 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { } hir::ItemKind::ForeignMod(ref module) => { for it in module.items.iter() { - if let hir::ForeignItemKind::Static(ref ty, ..) = it.kind { - check_item_type(tcx, it.hir_id, ty.span, true); + match it.kind { + hir::ForeignItemKind::Fn(ref decl, ..) => { + check_item_fn(tcx, it.hir_id, it.ident, it.span, decl) + } + hir::ForeignItemKind::Static(ref ty, ..) => { + check_item_type(tcx, it.hir_id, ty.span, true) + } + hir::ForeignItemKind::Type => (), } } } @@ -303,7 +309,7 @@ fn check_associated_item( fcx, item.ident.span, sig, - hir_sig, + hir_sig.decl, item.def_id, &mut implied_bounds, ); @@ -564,22 +570,24 @@ fn check_associated_type_defaults(fcx: &FnCtxt<'_, '_>, trait_def_id: DefId) { } } -fn check_item_fn(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { - for_item(tcx, item).with_fcx(|fcx, tcx| { - let def_id = fcx.tcx.hir().local_def_id(item.hir_id); +fn check_item_fn( + tcx: TyCtxt<'_>, + item_id: hir::HirId, + ident: Ident, + span: Span, + decl: &hir::FnDecl<'_>, +) { + for_id(tcx, item_id, span).with_fcx(|fcx, tcx| { + let def_id = fcx.tcx.hir().local_def_id(item_id); let sig = fcx.tcx.fn_sig(def_id); - let sig = fcx.normalize_associated_types_in(item.span, &sig); + let sig = fcx.normalize_associated_types_in(span, &sig); let mut implied_bounds = vec![]; - let hir_sig = match &item.kind { - ItemKind::Fn(sig, ..) => sig, - _ => bug!("expected `ItemKind::Fn`, found `{:?}`", item.kind), - }; check_fn_or_method( tcx, fcx, - item.ident.span, + ident.span, sig, - hir_sig, + decl, def_id.to_def_id(), &mut implied_bounds, ); @@ -835,28 +843,28 @@ fn check_fn_or_method<'fcx, 'tcx>( fcx: &FnCtxt<'fcx, 'tcx>, span: Span, sig: ty::PolyFnSig<'tcx>, - hir_sig: &hir::FnSig<'_>, + hir_decl: &hir::FnDecl<'_>, def_id: DefId, implied_bounds: &mut Vec<Ty<'tcx>>, ) { let sig = fcx.normalize_associated_types_in(span, &sig); let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig); - for (&input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) { + for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) { fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation); } implied_bounds.extend(sig.inputs()); fcx.register_wf_obligation( sig.output().into(), - hir_sig.decl.output.span(), + hir_decl.output.span(), ObligationCauseCode::ReturnType, ); // FIXME(#25759) return types should not be implied bounds implied_bounds.push(sig.output()); - check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_sig.decl.output.span()))); + check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_decl.output.span()))); } /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ec534aa925d4f..c3b54f1461426 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1927,7 +1927,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let re_root_empty = tcx.lifetimes.re_root_empty; let predicate = ty::OutlivesPredicate(ty, re_root_empty); predicates.push(( - ty::PredicateKind::TypeOutlives(ty::Binder::dummy(predicate)) + ty::PredicateKind::TypeOutlives(ty::Binder::bind(predicate)) .to_predicate(tcx), span, )); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 85c125e5efdd4..d0312d77a7c5d 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1521,6 +1521,11 @@ h4 > .important-traits { #main > .line-numbers { margin-top: 0; } + + .important-traits .important-traits-tooltiptext { + left: 0; + top: 100%; + } } @media print { diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index e0ab7170ea877..96ba5c46a3cde 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -237,16 +237,6 @@ a { #crate-search+.search-input:focus { box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent; - color: #ffffff; - background-color: #141920; - box-shadow: none; - transition: box-shadow 150ms ease-in-out; - border-radius: 4px; - margin-left: 8px; -} - -#crate-search+.search-input:focus { - box-shadow: 0px 6px 20px 0px black; } .search-focus:disabled { @@ -318,12 +308,12 @@ a.test-arrow { font-size: 100%; color: #788797; border-radius: 4px; - background-color: rgba(255, 255, 255, 0); + background-color: rgba(57, 175, 215, 0.09); } a.test-arrow:hover { - background-color: rgba(242, 151, 24, 0.05); - color: #ffb44c; + background-color: rgba(57, 175, 215, 0.368); + color: #c5c5c5; } .toggle-label { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index e187b9251f71e..6f221da1168c6 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,5 +1,5 @@ use rustc_ast::ast; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::SyntaxExtensionKind; use rustc_feature::UnstableFeatures; use rustc_hir as hir; @@ -45,7 +45,17 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { enum ErrorKind { ResolutionFailure, - AnchorFailure(&'static str), + AnchorFailure(AnchorFailure), +} + +enum AnchorFailure { + MultipleAnchors, + Primitive, + Variant, + AssocConstant, + AssocType, + Field, + Method, } struct LinkCollector<'a, 'tcx> { @@ -197,9 +207,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Not a trait item; just return what we found. Res::PrimTy(..) => { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure( - "primitive types cannot be followed by anchors", - )); + return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } return Ok((res, Some(path_str.to_owned()))); } @@ -209,9 +217,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if disambiguator == Some("type") { if let Some(prim) = is_primitive(path_str, ns) { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure( - "primitive types cannot be followed by anchors", - )); + return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } return Ok((prim, Some(path_str.to_owned()))); } @@ -228,9 +234,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } else if let Some(prim) = is_primitive(path_str, ns) { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure( - "primitive types cannot be followed by anchors", - )); + return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } return Ok((prim, Some(path_str.to_owned()))); } else { @@ -338,9 +342,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Fn { - "methods cannot be followed by anchors" + AnchorFailure::Method } else { - "associated constants cannot be followed by anchors" + AnchorFailure::AssocConstant })) } else { Ok((ty_res, Some(format!("{}.{}", out, item_name)))) @@ -358,9 +362,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } { if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(if def.is_enum() { - "enum variants cannot be followed by anchors" + AnchorFailure::Variant } else { - "struct fields cannot be followed by anchors" + AnchorFailure::Field })) } else { Ok(( @@ -404,11 +408,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { - "associated constants cannot be followed by anchors" + AnchorFailure::AssocConstant } else if item.kind == ty::AssocKind::Type { - "associated types cannot be followed by anchors" + AnchorFailure::AssocType } else { - "methods cannot be followed by anchors" + AnchorFailure::Method })) } else { Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) @@ -559,16 +563,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let link = ori_link.replace("`", ""); let parts = link.split('#').collect::<Vec<_>>(); let (link, extra_fragment) = if parts.len() > 2 { - build_diagnostic( - cx, - &item, - &link, - &dox, - link_range, - "has an issue with the link anchor.", - "only one `#` is allowed in a link", - None, - ); + anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors); continue; } else if parts.len() == 2 { if parts[0].trim().is_empty() { @@ -803,21 +798,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { && (item.visibility == Visibility::Public) && !self.cx.render_options.document_private { - let item_name = item.name.as_deref().unwrap_or("<unknown>"); - let err_msg = format!( - "public documentation for `{}` links to a private item", - item_name - ); - build_diagnostic( - cx, - &item, - path_str, - &dox, - link_range, - &err_msg, - "this item is private", - None, - ); + privacy_error(cx, &item, &path_str, &dox, link_range); continue; } } @@ -851,24 +832,33 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } -fn build_diagnostic( +/// Reports a diagnostic for an intra-doc link. +/// +/// If no link range is provided, or the source span of the link cannot be determined, the span of +/// the entire documentation block is used for the lint. If a range is provided but the span +/// calculation fails, a note is added to the diagnostic pointing to the link in the markdown. +/// +/// The `decorate` callback is invoked in all cases to allow further customization of the +/// diagnostic before emission. If the span of the link was able to be determined, the second +/// parameter of the callback will contain it, and the primary span of the diagnostic will be set +/// to it. +fn report_diagnostic( cx: &DocContext<'_>, + msg: &str, item: &Item, - path_str: &str, dox: &str, link_range: Option<Range<usize>>, - err_msg: &str, - short_err_msg: &str, - help_msg: Option<&str>, + decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option<rustc_span::Span>), ) { let hir_id = match cx.as_local_hir_id(item.def_id) { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - info!("ignoring warning from parent crate: {}", err_msg); + info!("ignoring warning from parent crate: {}", msg); return; } }; + let attrs = &item.attrs; let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); @@ -877,12 +867,15 @@ fn build_diagnostic( hir_id, sp, |lint| { - let mut diag = lint.build(&format!("`[{}]` {}", path_str, err_msg)); + let mut diag = lint.build(msg); + + let span = link_range + .as_ref() + .and_then(|range| super::source_span_for_markdown_range(cx, dox, range, attrs)); + if let Some(link_range) = link_range { - if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) - { + if let Some(sp) = span { diag.set_span(sp); - diag.span_label(sp, short_err_msg); } else { // blah blah blah\nblah\nblah [blah] blah blah\nblah blah // ^ ~~~~ @@ -902,20 +895,15 @@ fn build_diagnostic( found = link_range.len(), )); } - }; - if let Some(help_msg) = help_msg { - diag.help(help_msg); } + + decorate(&mut diag, span); + diag.emit(); }, ); } -/// Reports a resolution failure diagnostic. -/// -/// If we cannot find the exact source span of the resolution failure, we use the span of the -/// documentation attributes themselves. This is a little heavy-handed, so we display the markdown -/// line containing the failure as a note as well. fn resolution_failure( cx: &DocContext<'_>, item: &Item, @@ -923,15 +911,19 @@ fn resolution_failure( dox: &str, link_range: Option<Range<usize>>, ) { - build_diagnostic( + report_diagnostic( cx, + &format!("unresolved link to `{}`", path_str), item, - path_str, dox, link_range, - "cannot be resolved, ignoring it.", - "cannot be resolved, ignoring", - Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`"), + |diag, sp| { + if let Some(sp) = sp { + diag.span_label(sp, "unresolved link"); + } + + diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + }, ); } @@ -941,18 +933,39 @@ fn anchor_failure( path_str: &str, dox: &str, link_range: Option<Range<usize>>, - msg: &str, + failure: AnchorFailure, ) { - build_diagnostic( - cx, - item, - path_str, - dox, - link_range, - "has an issue with the link anchor.", - msg, - None, - ); + let msg = match failure { + AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str), + AnchorFailure::Primitive + | AnchorFailure::Variant + | AnchorFailure::AssocConstant + | AnchorFailure::AssocType + | AnchorFailure::Field + | AnchorFailure::Method => { + let kind = match failure { + AnchorFailure::Primitive => "primitive type", + AnchorFailure::Variant => "enum variant", + AnchorFailure::AssocConstant => "associated constant", + AnchorFailure::AssocType => "associated type", + AnchorFailure::Field => "struct field", + AnchorFailure::Method => "method", + AnchorFailure::MultipleAnchors => unreachable!("should be handled already"), + }; + + format!( + "`{}` contains an anchor, but links to {kind}s are already anchored", + path_str, + kind = kind + ) + } + }; + + report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + if let Some(sp) = sp { + diag.span_label(sp, "contains invalid anchor"); + } + }); } fn ambiguity_error( @@ -963,121 +976,100 @@ fn ambiguity_error( link_range: Option<Range<usize>>, candidates: PerNS<Option<Res>>, ) { - let hir_id = match cx.as_local_hir_id(item.def_id) { - Some(hir_id) => hir_id, - None => { - // If non-local, no need to check anything. - return; + let mut msg = format!("`{}` is ", path_str); + + let candidates = [TypeNS, ValueNS, MacroNS] + .iter() + .filter_map(|&ns| candidates[ns].map(|res| (res, ns))) + .collect::<Vec<_>>(); + match candidates.as_slice() { + [(first_def, _), (second_def, _)] => { + msg += &format!( + "both {} {} and {} {}", + first_def.article(), + first_def.descr(), + second_def.article(), + second_def.descr(), + ); } - }; - let attrs = &item.attrs; - let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); - - cx.tcx.struct_span_lint_hir( - lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - hir_id, - sp, - |lint| { - let mut msg = format!("`{}` is ", path_str); - - let candidates = [TypeNS, ValueNS, MacroNS] - .iter() - .filter_map(|&ns| candidates[ns].map(|res| (res, ns))) - .collect::<Vec<_>>(); - match candidates.as_slice() { - [(first_def, _), (second_def, _)] => { - msg += &format!( - "both {} {} and {} {}", - first_def.article(), - first_def.descr(), - second_def.article(), - second_def.descr(), - ); - } - _ => { - let mut candidates = candidates.iter().peekable(); - while let Some((res, _)) = candidates.next() { - if candidates.peek().is_some() { - msg += &format!("{} {}, ", res.article(), res.descr()); - } else { - msg += &format!("and {} {}", res.article(), res.descr()); - } - } + _ => { + let mut candidates = candidates.iter().peekable(); + while let Some((res, _)) = candidates.next() { + if candidates.peek().is_some() { + msg += &format!("{} {}, ", res.article(), res.descr()); + } else { + msg += &format!("and {} {}", res.article(), res.descr()); } } + } + } - let mut diag = lint.build(&msg); + report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| { + if let Some(sp) = sp { + diag.span_label(sp, "ambiguous link"); - if let Some(link_range) = link_range { - if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) - { - diag.set_span(sp); - diag.span_label(sp, "ambiguous link"); + let link_range = link_range.expect("must have a link range if we have a span"); - for (res, ns) in candidates { - let (action, mut suggestion) = match res { - Res::Def(DefKind::AssocFn | DefKind::Fn, _) => { - ("add parentheses", format!("{}()", path_str)) - } - Res::Def(DefKind::Macro(MacroKind::Bang), _) => { - ("add an exclamation mark", format!("{}!", path_str)) - } - _ => { - let type_ = match (res, ns) { - (Res::Def(DefKind::Const, _), _) => "const", - (Res::Def(DefKind::Static, _), _) => "static", - (Res::Def(DefKind::Struct, _), _) => "struct", - (Res::Def(DefKind::Enum, _), _) => "enum", - (Res::Def(DefKind::Union, _), _) => "union", - (Res::Def(DefKind::Trait, _), _) => "trait", - (Res::Def(DefKind::Mod, _), _) => "module", - (_, TypeNS) => "type", - (_, ValueNS) => "value", - (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => { - "derive" - } - (_, MacroNS) => "macro", - }; - - // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` - ("prefix with the item type", format!("{}@{}", type_, path_str)) - } + for (res, ns) in candidates { + let (action, mut suggestion) = match res { + Res::Def(DefKind::AssocFn | DefKind::Fn, _) => { + ("add parentheses", format!("{}()", path_str)) + } + Res::Def(DefKind::Macro(MacroKind::Bang), _) => { + ("add an exclamation mark", format!("{}!", path_str)) + } + _ => { + let type_ = match (res, ns) { + (Res::Def(DefKind::Const, _), _) => "const", + (Res::Def(DefKind::Static, _), _) => "static", + (Res::Def(DefKind::Struct, _), _) => "struct", + (Res::Def(DefKind::Enum, _), _) => "enum", + (Res::Def(DefKind::Union, _), _) => "union", + (Res::Def(DefKind::Trait, _), _) => "trait", + (Res::Def(DefKind::Mod, _), _) => "module", + (_, TypeNS) => "type", + (_, ValueNS) => "value", + (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => "derive", + (_, MacroNS) => "macro", }; - if dox.bytes().nth(link_range.start) == Some(b'`') { - suggestion = format!("`{}`", suggestion); - } - - diag.span_suggestion( - sp, - &format!("to link to the {}, {}", res.descr(), action), - suggestion, - Applicability::MaybeIncorrect, - ); + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + ("prefix with the item type", format!("{}@{}", type_, path_str)) } - } else { - // blah blah blah\nblah\nblah [blah] blah blah\nblah blah - // ^ ~~~~ - // | link_range - // last_new_line_offset - let last_new_line_offset = - dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); - let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); + }; - // Print the line containing the `link_range` and manually mark it with '^'s. - diag.note(&format!( - "the link appears in this line:\n\n{line}\n\ - {indicator: <before$}{indicator:^<found$}", - line = line, - indicator = "", - before = link_range.start - last_new_line_offset, - found = link_range.len(), - )); + if dox.bytes().nth(link_range.start) == Some(b'`') { + suggestion = format!("`{}`", suggestion); } + + // FIXME: Create a version of this suggestion for when we don't have the span. + diag.span_suggestion( + sp, + &format!("to link to the {}, {}", res.descr(), action), + suggestion, + Applicability::MaybeIncorrect, + ); } - diag.emit(); - }, - ); + } + }); +} + +fn privacy_error( + cx: &DocContext<'_>, + item: &Item, + path_str: &str, + dox: &str, + link_range: Option<Range<usize>>, +) { + let item_name = item.name.as_deref().unwrap_or("<unknown>"); + let msg = + format!("public documentation for `{}` links to private item `{}`", item_name, path_str); + + report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + if let Some(sp) = sp { + diag.span_label(sp, "this item is private"); + } + }); } /// Given an enum variant's res, return the res of its enum and the associated fragment. @@ -1089,7 +1081,7 @@ fn handle_variant( use rustc_middle::ty::DefIdTree; if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure("variants cannot be followed by anchors")); + return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant)); } let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index cc6663bebd3d4..b6488ae61b153 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -86,7 +86,7 @@ //! cost are suffixed with a `~`. //! //! All amortized costs are for the potential need to resize when capacity is -//! exhausted. If a resize occurs it will take O(n) time. Our collections never +//! exhausted. If a resize occurs it will take *O*(*n*) time. Our collections never //! automatically shrink, so removal operations aren't amortized. Over a //! sufficiently large series of operations, the average cost per operation will //! deterministically equal the given cost. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 11b8f953be460..02de3fff29f87 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -224,10 +224,7 @@ all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform, ptr_wrapping_offset_from) )] -#![cfg_attr( - all(test, target_vendor = "fortanix", target_env = "sgx"), - feature(fixed_size_array, maybe_uninit_extra) -)] +#![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))] // std is implemented with unstable features, many of which are internal // compiler details that will never be stable // NB: the following list is sorted to minimize merge conflicts. diff --git a/src/libstd/sys/wasi/ext/mod.rs b/src/libstd/sys/wasi/ext/mod.rs index 5f8b1cbfa0b53..58c8c46c969c1 100644 --- a/src/libstd/sys/wasi/ext/mod.rs +++ b/src/libstd/sys/wasi/ext/mod.rs @@ -18,5 +18,5 @@ pub mod prelude { pub use crate::sys::ext::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::sys::ext::io::{AsRawFd, FromRawFd, IntoRawFd}; + pub use crate::sys::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; } diff --git a/src/test/codegen-units/item-collection/static-init.rs b/src/test/codegen-units/item-collection/static-init.rs index f6005eed43c7d..aebccff01fc69 100644 --- a/src/test/codegen-units/item-collection/static-init.rs +++ b/src/test/codegen-units/item-collection/static-init.rs @@ -6,7 +6,7 @@ pub static FN : fn() = foo::<i32>; pub fn foo<T>() { } -//~ MONO_ITEM fn static_init::foo[0]<i32> +//~ MONO_ITEM fn static_init::foo[0]<T> //~ MONO_ITEM static static_init::FN[0] //~ MONO_ITEM fn static_init::start[0] diff --git a/src/test/codegen-units/item-collection/trait-method-default-impl.rs b/src/test/codegen-units/item-collection/trait-method-default-impl.rs index 11f6cc62d49e3..abe2d108eae7d 100644 --- a/src/test/codegen-units/item-collection/trait-method-default-impl.rs +++ b/src/test/codegen-units/item-collection/trait-method-default-impl.rs @@ -27,7 +27,7 @@ impl SomeGenericTrait<u64> for i32 { // For the non-generic foo(), we should generate a codegen-item even if it // is not called anywhere - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0]<i32, u64> + //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0]<i32, T1> } // Non-generic impl of generic trait diff --git a/src/test/codegen-units/polymorphization/unused_type_parameters.rs b/src/test/codegen-units/polymorphization/unused_type_parameters.rs new file mode 100644 index 0000000000000..dc2ad0559b34f --- /dev/null +++ b/src/test/codegen-units/polymorphization/unused_type_parameters.rs @@ -0,0 +1,323 @@ +// compile-flags:-Zprint-mono-items=lazy -Copt-level=1 +// ignore-tidy-linelength + +#![crate_type = "rlib"] + +// This test checks that the polymorphization analysis correctly reduces the +// generated mono items. + +mod functions { + // Function doesn't have any type parameters to be unused. + pub fn no_parameters() {} + +//~ MONO_ITEM fn unused_type_parameters::functions[0]::no_parameters[0] + + // Function has an unused type parameter. + pub fn unused<T>() { + } + +//~ MONO_ITEM fn unused_type_parameters::functions[0]::unused[0]<T> + + // Function uses type parameter in value of a binding. + pub fn used_binding_value<T: Default>() { + let _: T = Default::default(); + } + +//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0]<u64> + + // Function uses type parameter in type of a binding. + pub fn used_binding_type<T>() { + let _: Option<T> = None; + } + +//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0]<u64> + + // Function uses type parameter in argument. + pub fn used_argument<T>(_: T) { + } + +//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0]<u64> +// + // Function uses type parameter in substitutions to another function. + pub fn used_substs<T>() { + unused::<T>() + } + +//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0]<u64> +} + + +mod closures { + // Function doesn't have any type parameters to be unused. + pub fn no_parameters() { + let _ = || {}; + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::no_parameters[0] + + // Function has an unused type parameter in parent and closure. + pub fn unused<T>() -> u32 { + let add_one = |x: u32| x + 1; + add_one(3) + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0]::{{closure}}[0]<T, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0]<T> + + // Function has an unused type parameter in closure, but not in parent. + pub fn used_parent<T: Default>() -> u32 { + let _: T = Default::default(); + let add_one = |x: u32| x + 1; + add_one(3) + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]::{{closure}}[0]<T, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]<u64> + + // Function uses type parameter in value of a binding in closure. + pub fn used_binding_value<T: Default>() -> T { + let x = || { + let y: T = Default::default(); + y + }; + + x() + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()) -> u64, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]<u64> + + // Function uses type parameter in type of a binding in closure. + pub fn used_binding_type<T>() -> Option<T> { + let x = || { + let y: Option<T> = None; + y + }; + + x() + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()) -> core::option[0]::Option[0]<u32>, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()) -> core::option[0]::Option[0]<u64>, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]<u64> + + // Function and closure uses type parameter in argument. + pub fn used_argument<T>(t: T) -> u32 { + let x = |_: T| 3; + x(t) + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn((u64)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]<u64> + + // Closure uses type parameter in argument. + pub fn used_argument_closure<T: Default>() -> u32 { + let t: T = Default::default(); + let x = |_: T| 3; + x(t) + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn((u64)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]<u64> + + // Closure uses type parameter as upvar. + pub fn used_upvar<T: Default>() -> T { + let x: T = Default::default(); + let y = || x; + y() + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0]<u32, i32, extern "rust-call" fn(()) -> u32, (u32)> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0]<u64, i32, extern "rust-call" fn(()) -> u64, (u64)> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]<u64> + + // Closure uses type parameter in substitutions to another function. + pub fn used_substs<T>() { + let x = || super::functions::unused::<T>(); + x() + } + +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()), ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()), ()> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]<u64> +} + +mod methods { + pub struct Foo<F>(F); + + impl<F: Default> Foo<F> { + // Function has an unused type parameter from impl. + pub fn unused_impl() { + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_impl[0]<F> + + // Function has an unused type parameter from impl and fn. + pub fn unused_both<G: Default>() { + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_both[0]<F, G> + + // Function uses type parameter from impl. + pub fn used_impl() { + let _: F = Default::default(); + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0]<u64> + + // Function uses type parameter from impl. + pub fn used_fn<G: Default>() { + let _: G = Default::default(); + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0]<F, u32> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0]<F, u64> + + // Function uses type parameter from impl. + pub fn used_both<G: Default>() { + let _: F = Default::default(); + let _: G = Default::default(); + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0]<u32, u32> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0]<u64, u64> + + // Function uses type parameter in substitutions to another function. + pub fn used_substs() { + super::functions::unused::<F>() + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0]<u64> + + // Function has an unused type parameter from impl and fn. + pub fn closure_unused_all<G: Default>() -> u32 { + let add_one = |x: u32| x + 1; + add_one(3) + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0]::{{closure}}[0]<F, G, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0]<F, G> + + // Function uses type parameter from impl and fn in closure. + pub fn closure_used_both<G: Default>() -> u32 { + let add_one = |x: u32| { + let _: F = Default::default(); + let _: G = Default::default(); + x + 1 + }; + + add_one(3) + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0]<u32, u32, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0]<u64, u64, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]<u32, u32> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]<u64, u64> + + // Function uses type parameter from fn in closure. + pub fn closure_used_fn<G: Default>() -> u32 { + let add_one = |x: u32| { + let _: G = Default::default(); + x + 1 + }; + + add_one(3) + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0]<F, u32, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0]<F, u64, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]<F, u32> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]<F, u64> + + // Function uses type parameter from impl in closure. + pub fn closure_used_impl<G: Default>() -> u32 { + let add_one = |x: u32| { + let _: F = Default::default(); + x + 1 + }; + + add_one(3) + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0]<u32, G, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0]<u64, G, i8, extern "rust-call" fn((u32)) -> u32, ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]<u32, G> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]<u64, G> + + // Closure uses type parameter in substitutions to another function. + pub fn closure_used_substs() { + let x = || super::functions::unused::<F>(); + x() + } + +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()), ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()), ()> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]<u64> + } +} + + + +fn dispatch<T: Default>() { + functions::no_parameters(); + functions::unused::<T>(); + functions::used_binding_value::<T>(); + functions::used_binding_type::<T>(); + functions::used_argument::<T>(Default::default()); + functions::used_substs::<T>(); + + closures::no_parameters(); + let _ = closures::unused::<T>(); + let _ = closures::used_parent::<T>(); + let _ = closures::used_binding_value::<T>(); + let _ = closures::used_binding_type::<T>(); + let _ = closures::used_argument::<T>(Default::default()); + let _ = closures::used_argument_closure::<T>(); + let _ = closures::used_upvar::<T>(); + let _ = closures::used_substs::<T>(); + + methods::Foo::<T>::unused_impl(); + methods::Foo::<T>::unused_both::<T>(); + methods::Foo::<T>::used_impl(); + methods::Foo::<T>::used_fn::<T>(); + methods::Foo::<T>::used_both::<T>(); + methods::Foo::<T>::used_substs(); + let _ = methods::Foo::<T>::closure_unused_all::<T>(); + let _ = methods::Foo::<T>::closure_used_both::<T>(); + let _ = methods::Foo::<T>::closure_used_impl::<T>(); + let _ = methods::Foo::<T>::closure_used_fn::<T>(); + let _ = methods::Foo::<T>::closure_used_substs(); +} + +//~ MONO_ITEM fn unused_type_parameters::dispatch[0]<u32> +//~ MONO_ITEM fn unused_type_parameters::dispatch[0]<u64> + +pub fn foo() { + // Generate two copies of each function to check that where the type parameter is unused, + // there is only a single copy. + dispatch::<u32>(); + dispatch::<u64>(); +} + +//~ MONO_ITEM fn unused_type_parameters::foo[0] @@ unused_type_parameters-cgu.0[External] + +// These are all the items that aren't relevant to the test. +//~ MONO_ITEM fn core::default[0]::{{impl}}[6]::default[0] +//~ MONO_ITEM fn core::default[0]::{{impl}}[7]::default[0] diff --git a/src/test/codegen/abi-efiapi.rs b/src/test/codegen/abi-efiapi.rs index 8aeee5859d0ad..7c61b7809901f 100644 --- a/src/test/codegen/abi-efiapi.rs +++ b/src/test/codegen/abi-efiapi.rs @@ -2,7 +2,7 @@ // revisions:x86_64 i686 arm -// min-llvm-version 9.0 +// min-llvm-version: 9.0 //[x86_64] compile-flags: --target x86_64-unknown-uefi //[i686] compile-flags: --target i686-unknown-linux-musl diff --git a/src/test/codegen/avr/avr-func-addrspace.rs b/src/test/codegen/avr/avr-func-addrspace.rs new file mode 100644 index 0000000000000..7759d9603a5a4 --- /dev/null +++ b/src/test/codegen/avr/avr-func-addrspace.rs @@ -0,0 +1,93 @@ +// compile-flags: -O --target=avr-unknown-unknown --crate-type=rlib + +// This test validates that function pointers can be stored in global variables +// and called upon. It ensures that Rust emits function pointers in the correct +// address space to LLVM so that an assertion error relating to casting is +// not triggered. +// +// It also validates that functions can be called through function pointers +// through traits. + +#![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +pub trait Sized { } +#[lang = "copy"] +pub trait Copy { } +#[lang = "receiver"] +pub trait Receiver { } + +pub struct Result<T, E> { _a: T, _b: E } + +impl Copy for usize {} + +#[lang = "drop_in_place"] +pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +#[lang = "fn_mut"] +pub trait FnMut<Args> : FnOnce<Args> { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[lang = "fn"] +pub trait Fn<Args>: FnOnce<Args> { + /// Performs the call operation. + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +impl<'a, A, R> FnOnce<A> for &'a fn(A) -> R { + type Output = R; + + extern "rust-call" fn call_once(self, args: A) -> R { + (*self)(args) + } +} + +pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box; +pub static mut STORAGE_BAR: u32 = 12; + +fn arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()> { + let raw_ptr = ptr as *const usize; + let _v: usize = unsafe { *raw_ptr }; + loop {} +} + +#[inline(never)] +#[no_mangle] +fn call_through_fn_trait(a: &mut impl Fn<(), Output=()>) { + (*a)() +} + +#[inline(never)] +fn update_bar_value() { + unsafe { + STORAGE_BAR = 88; + } +} + +// CHECK: define void @test(){{.+}}addrspace(1) +#[no_mangle] +pub extern "C" fn test() { + let mut buf = 7; + + // A call through the Fn trait must use address space 1. + // + // CHECK: call{{.+}}addrspace(1) void @call_through_fn_trait() + call_through_fn_trait(&mut update_bar_value); + + // A call through a global variable must use address space 1. + // CHECK: load {{.*}}addrspace(1){{.+}}FOO + unsafe { + STORAGE_FOO(&1, &mut buf); + } +} diff --git a/src/test/codegen/cfguard-checks.rs b/src/test/codegen/cfguard-checks.rs index 96a0a321199a3..571a2654bcbfd 100644 --- a/src/test/codegen/cfguard-checks.rs +++ b/src/test/codegen/cfguard-checks.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control-flow-guard=checks +// compile-flags: -C control-flow-guard=checks // only-msvc #![crate_type = "lib"] diff --git a/src/test/codegen/cfguard-disabled.rs b/src/test/codegen/cfguard-disabled.rs index 925e4e8e2d155..c3f8f4116819c 100644 --- a/src/test/codegen/cfguard-disabled.rs +++ b/src/test/codegen/cfguard-disabled.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control-flow-guard=no +// compile-flags: -C control-flow-guard=no // only-msvc #![crate_type = "lib"] diff --git a/src/test/codegen/cfguard-nochecks.rs b/src/test/codegen/cfguard-nochecks.rs index d7dc3d7e89eea..3847c3e81ed7a 100644 --- a/src/test/codegen/cfguard-nochecks.rs +++ b/src/test/codegen/cfguard-nochecks.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control-flow-guard=nochecks +// compile-flags: -C control-flow-guard=nochecks // only-msvc #![crate_type = "lib"] diff --git a/src/test/codegen/cfguard-non-msvc.rs b/src/test/codegen/cfguard-non-msvc.rs index 4008f0187a0b0..6278a951e35f1 100644 --- a/src/test/codegen/cfguard-non-msvc.rs +++ b/src/test/codegen/cfguard-non-msvc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z control-flow-guard +// compile-flags: -C control-flow-guard // ignore-msvc #![crate_type = "lib"] diff --git a/src/test/codegen/force-unwind-tables.rs b/src/test/codegen/force-unwind-tables.rs index fbaf38d69df7f..eba4a7469f930 100644 --- a/src/test/codegen/force-unwind-tables.rs +++ b/src/test/codegen/force-unwind-tables.rs @@ -1,4 +1,4 @@ -// min-llvm-version 8.0 +// min-llvm-version: 8.0 // compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y #![crate_type="lib"] diff --git a/src/test/debuginfo/function-call.rs b/src/test/debuginfo/function-call.rs index 98ad8983a60a0..a5d5942b53953 100644 --- a/src/test/debuginfo/function-call.rs +++ b/src/test/debuginfo/function-call.rs @@ -1,5 +1,5 @@ // This test does not passed with gdb < 8.0. See #53497. -// min-gdb-version 8.0 +// min-gdb-version: 8.0 // compile-flags:-g diff --git a/src/test/debuginfo/pretty-huge-vec.rs b/src/test/debuginfo/pretty-huge-vec.rs index 2616c9465246e..cbd2278f7e27c 100644 --- a/src/test/debuginfo/pretty-huge-vec.rs +++ b/src/test/debuginfo/pretty-huge-vec.rs @@ -2,7 +2,7 @@ // ignore-freebsd: gdb package too new // ignore-android: FIXME(#10381) // compile-flags:-g -// min-gdb-version 8.1 +// min-gdb-version: 8.1 // min-lldb-version: 310 // === GDB TESTS =================================================================================== diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs index 4e95a028e0749..a4fbff5725c97 100644 --- a/src/test/debuginfo/pretty-std-collections.rs +++ b/src/test/debuginfo/pretty-std-collections.rs @@ -6,7 +6,7 @@ // The pretty printers being tested here require the patch from // https://sourceware.org/bugzilla/show_bug.cgi?id=21763 -// min-gdb-version 8.1 +// min-gdb-version: 8.1 // min-lldb-version: 310 diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 57721ce103c39..7ae82d522b09d 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -2,7 +2,7 @@ // only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155 // ignore-android: FIXME(#10381) // compile-flags:-g -// min-gdb-version 7.7 +// min-gdb-version: 7.7 // min-lldb-version: 310 // === GDB TESTS =================================================================================== diff --git a/src/test/debuginfo/pretty-uninitialized-vec.rs b/src/test/debuginfo/pretty-uninitialized-vec.rs index 7ce004681e100..61791f48f4db7 100644 --- a/src/test/debuginfo/pretty-uninitialized-vec.rs +++ b/src/test/debuginfo/pretty-uninitialized-vec.rs @@ -2,7 +2,7 @@ // ignore-freebsd: gdb package too new // ignore-android: FIXME(#10381) // compile-flags:-g -// min-gdb-version 8.1 +// min-gdb-version: 8.1 // min-lldb-version: 310 // === GDB TESTS =================================================================================== diff --git a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs index a0a5b141ec0e1..5830ef033d389 100644 --- a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs +++ b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs @@ -91,3 +91,58 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize { 0 } + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize { + continue_if!(ap.arg::<c_int>() == 1); + continue_if!(ap.arg::<c_int>() == 2); + continue_if!(ap.arg::<c_int>() == 3); + continue_if!(ap.arg::<c_int>() == 4); + continue_if!(ap.arg::<c_int>() == 5); + continue_if!(ap.arg::<c_int>() == 6); + continue_if!(ap.arg::<c_int>() == 7); + continue_if!(ap.arg::<c_int>() == 8); + continue_if!(ap.arg::<c_int>() == 9); + continue_if!(ap.arg::<c_int>() == 10); + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize { + continue_if!(ap.arg::<c_double>() == 1.0); + continue_if!(ap.arg::<c_double>() == 2.0); + continue_if!(ap.arg::<c_double>() == 3.0); + continue_if!(ap.arg::<c_double>() == 4.0); + continue_if!(ap.arg::<c_double>() == 5.0); + continue_if!(ap.arg::<c_double>() == 6.0); + continue_if!(ap.arg::<c_double>() == 7.0); + continue_if!(ap.arg::<c_double>() == 8.0); + continue_if!(ap.arg::<c_double>() == 9.0); + continue_if!(ap.arg::<c_double>() == 10.0); + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize { + continue_if!(ap.arg::<c_double>() == 1.0); + continue_if!(ap.arg::<c_int>() == 1); + continue_if!(ap.arg::<c_double>() == 2.0); + continue_if!(ap.arg::<c_int>() == 2); + continue_if!(ap.arg::<c_double>() == 3.0); + continue_if!(ap.arg::<c_int>() == 3); + continue_if!(ap.arg::<c_double>() == 4.0); + continue_if!(ap.arg::<c_int>() == 4); + continue_if!(ap.arg::<c_int>() == 5); + continue_if!(ap.arg::<c_double>() == 5.0); + continue_if!(ap.arg::<c_int>() == 6); + continue_if!(ap.arg::<c_double>() == 6.0); + continue_if!(ap.arg::<c_int>() == 7); + continue_if!(ap.arg::<c_double>() == 7.0); + continue_if!(ap.arg::<c_int>() == 8); + continue_if!(ap.arg::<c_double>() == 8.0); + continue_if!(ap.arg::<c_int>() == 9); + continue_if!(ap.arg::<c_double>() == 9.0); + continue_if!(ap.arg::<c_int>() == 10); + continue_if!(ap.arg::<c_double>() == 10.0); + 0 +} diff --git a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c index 91b060dce26f4..5bdb51680a656 100644 --- a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c +++ b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c @@ -11,6 +11,9 @@ extern size_t check_list_copy_0(va_list ap); extern size_t check_varargs_0(int fixed, ...); extern size_t check_varargs_1(int fixed, ...); extern size_t check_varargs_2(int fixed, ...); +extern size_t check_varargs_3(int fixed, ...); +extern size_t check_varargs_4(double fixed, ...); +extern size_t check_varargs_5(int fixed, ...); int test_rust(size_t (*fn)(va_list), ...) { size_t ret = 0; @@ -36,5 +39,12 @@ int main(int argc, char* argv[]) { assert(check_varargs_2(0, "All", "of", "these", "are", "ignored", ".") == 0); + assert(check_varargs_3(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 0); + + assert(check_varargs_4(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) == 0); + + assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0, + 9, 9.0, 10, 10.0) == 0); + return 0; } diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index bc21cfd47c5d1..894518faa3168 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -1,15 +1,15 @@ -error: `[v2]` cannot be resolved, ignoring it. +error: unresolved link to `v2` --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | LL | /// [v2] - | ^^ cannot be resolved, ignoring + | ^^ unresolved link | note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index cf26675163054..d2b2b90a4e50d 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -1,15 +1,15 @@ -error: `[TypeAlias::hoge]` cannot be resolved, ignoring it. +error: unresolved link to `TypeAlias::hoge` --> $DIR/intra-doc-alias-ice.rs:5:30 | LL | /// [broken cross-reference](TypeAlias::hoge) - | ^^^^^^^^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^^^^^^^^ unresolved link | note: the lint level is defined here --> $DIR/intra-doc-alias-ice.rs:1:9 | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs index 44997c90f5932..95388003f8470 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs @@ -7,7 +7,7 @@ /// ## For example: /// /// (arr[i]) -//~^ ERROR `[i]` cannot be resolved, ignoring it. +//~^ ERROR `i` pub fn test_ice() { unimplemented!(); } diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index ce31eb3a8a378..156e214a79ff0 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -1,15 +1,15 @@ -error: `[i]` cannot be resolved, ignoring it. +error: unresolved link to `i` --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) - | ^ cannot be resolved, ignoring + | ^ unresolved link | note: the lint level is defined here --> $DIR/intra-link-span-ice-55723.rs:1:9 | LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-links-anchors.rs b/src/test/rustdoc-ui/intra-links-anchors.rs index 7f8a8dd3c45e0..7e61bd725359a 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.rs +++ b/src/test/rustdoc-ui/intra-links-anchors.rs @@ -23,23 +23,23 @@ pub enum Enum { /// Like [Foo#hola]. /// /// Or maybe [Foo::f#hola]. -//~^ ERROR `[Foo::f#hola]` has an issue with the link anchor. +//~^ ERROR `Foo::f#hola` contains an anchor pub fn foo() {} /// Empty. /// /// Another anchor error: [hello#people#!]. -//~^ ERROR `[hello#people#!]` has an issue with the link anchor. +//~^ ERROR `hello#people#!` contains multiple anchors pub fn bar() {} /// Empty? /// /// Damn enum's variants: [Enum::A#whatever]. -//~^ ERROR `[Enum::A#whatever]` has an issue with the link anchor. +//~^ ERROR `Enum::A#whatever` contains an anchor pub fn enum_link() {} /// Primitives? /// /// [u32#hello] -//~^ ERROR `[u32#hello]` has an issue with the link anchor. +//~^ ERROR `u32#hello` contains an anchor pub fn x() {} diff --git a/src/test/rustdoc-ui/intra-links-anchors.stderr b/src/test/rustdoc-ui/intra-links-anchors.stderr index 11dee5547db4f..ef33d8f3e06fe 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.stderr +++ b/src/test/rustdoc-ui/intra-links-anchors.stderr @@ -1,8 +1,8 @@ -error: `[Foo::f#hola]` has an issue with the link anchor. +error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored --> $DIR/intra-links-anchors.rs:25:15 | LL | /// Or maybe [Foo::f#hola]. - | ^^^^^^^^^^^ struct fields cannot be followed by anchors + | ^^^^^^^^^^^ contains invalid anchor | note: the lint level is defined here --> $DIR/intra-links-anchors.rs:1:9 @@ -10,23 +10,23 @@ note: the lint level is defined here LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[hello#people#!]` has an issue with the link anchor. +error: `hello#people#!` contains multiple anchors --> $DIR/intra-links-anchors.rs:31:28 | LL | /// Another anchor error: [hello#people#!]. - | ^^^^^^^^^^^^^^ only one `#` is allowed in a link + | ^^^^^^^^^^^^^^ contains invalid anchor -error: `[Enum::A#whatever]` has an issue with the link anchor. +error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored --> $DIR/intra-links-anchors.rs:37:28 | LL | /// Damn enum's variants: [Enum::A#whatever]. - | ^^^^^^^^^^^^^^^^ variants cannot be followed by anchors + | ^^^^^^^^^^^^^^^^ contains invalid anchor -error: `[u32#hello]` has an issue with the link anchor. +error: `u32#hello` contains an anchor, but links to primitive types are already anchored --> $DIR/intra-links-anchors.rs:43:6 | LL | /// [u32#hello] - | ^^^^^^^^^ primitive types cannot be followed by anchors + | ^^^^^^^^^ contains invalid anchor error: aborting due to 4 previous errors diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-links-private.public.stderr index 0a8dafdaf9466..a124435b08a99 100644 --- a/src/test/rustdoc-ui/intra-links-private.public.stderr +++ b/src/test/rustdoc-ui/intra-links-private.public.stderr @@ -1,4 +1,4 @@ -warning: `[DontDocMe]` public documentation for `DocMe` links to a private item +warning: public documentation for `DocMe` links to private item `DontDocMe` --> $DIR/intra-links-private.rs:6:11 | LL | /// docs [DontDocMe] diff --git a/src/test/rustdoc-ui/intra-links-private.rs b/src/test/rustdoc-ui/intra-links-private.rs index 86cf9fed3dab4..1b97f6e61bd23 100644 --- a/src/test/rustdoc-ui/intra-links-private.rs +++ b/src/test/rustdoc-ui/intra-links-private.rs @@ -4,7 +4,7 @@ #![cfg_attr(private, deny(intra_doc_link_resolution_failure))] /// docs [DontDocMe] -//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item +//[public]~^ WARNING public documentation for `DocMe` links to private item `DontDocMe` // FIXME: for [private] we should also make sure the link was actually generated pub struct DocMe; struct DontDocMe; diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.rs b/src/test/rustdoc-ui/intra-links-warning-crlf.rs index 18c9837b0bb45..a19c33b53be09 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.rs +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.rs @@ -6,16 +6,16 @@ /// [error] pub struct A; -//~^^ WARNING `[error]` cannot be resolved +//~^^ WARNING `error` /// /// docs [error1] -//~^ WARNING `[error1]` cannot be resolved +//~^ WARNING `error1` /// docs [error2] /// pub struct B; -//~^^^ WARNING `[error2]` cannot be resolved +//~^^^ WARNING `error2` /** * This is a multi-line comment. @@ -23,4 +23,4 @@ pub struct B; * It also has an [error]. */ pub struct C; -//~^^^ WARNING `[error]` cannot be resolved +//~^^^ WARNING `error` diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index ac8691a8743ba..bc31264c170ea 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -1,35 +1,35 @@ -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | = note: `#[warn(intra_doc_link_resolution_failure)]` on by default - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error1]` cannot be resolved, ignoring it. +warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error2]` cannot be resolved, ignoring it. +warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: 4 warnings emitted diff --git a/src/test/rustdoc-ui/intra-links-warning.rs b/src/test/rustdoc-ui/intra-links-warning.rs index 623dcc320bb8d..eab1f03480460 100644 --- a/src/test/rustdoc-ui/intra-links-warning.rs +++ b/src/test/rustdoc-ui/intra-links-warning.rs @@ -1,37 +1,37 @@ // check-pass //! Test with [Foo::baz], [Bar::foo], ... -//~^ WARNING `[Foo::baz]` cannot be resolved -//~| WARNING `[Bar::foo]` cannot be resolved +//~^ WARNING `Foo::baz` +//~| WARNING `Bar::foo` //! , [Uniooon::X] and [Qux::Z]. -//~^ WARNING `[Uniooon::X]` cannot be resolved -//~| WARNING `[Qux::Z]` cannot be resolved +//~^ WARNING `Uniooon::X` +//~| WARNING `Qux::Z` //! //! , [Uniooon::X] and [Qux::Z]. -//~^ WARNING `[Uniooon::X]` cannot be resolved -//~| WARNING `[Qux::Z]` cannot be resolved +//~^ WARNING `Uniooon::X` +//~| WARNING `Qux::Z` /// [Qux:Y] -//~^ WARNING `[Qux:Y]` cannot be resolved +//~^ WARNING `Qux:Y` pub struct Foo { pub bar: usize, } /// Foo -/// bar [BarA] bar //~ WARNING `[BarA]` cannot be resolved +/// bar [BarA] bar //~ WARNING `BarA` /// baz pub fn a() {} /** * Foo - * bar [BarB] bar //~ WARNING `[BarB]` cannot be resolved + * bar [BarB] bar //~ WARNING `BarB` * baz */ pub fn b() {} /** Foo -bar [BarC] bar //~ WARNING `[BarC]` cannot be resolved +bar [BarC] bar //~ WARNING `BarC` baz let bar_c_1 = 0; @@ -42,12 +42,12 @@ baz */ pub fn c() {} -#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `[BarD]` cannot be resolved +#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `BarD` pub fn d() {} macro_rules! f { ($f:expr) => { - #[doc = $f] //~ WARNING `[BarF]` cannot be resolved + #[doc = $f] //~ WARNING `BarF` pub fn f() {} } } @@ -55,30 +55,30 @@ f!("Foo\nbar [BarF] bar\nbaz"); /** # for example, * - * time to introduce a link [error]*/ //~ WARNING `[error]` cannot be resolved + * time to introduce a link [error]*/ //~ WARNING `error` pub struct A; /** * # for example, * - * time to introduce a link [error] //~ WARNING `[error]` cannot be resolved + * time to introduce a link [error] //~ WARNING `error` */ pub struct B; -#[doc = "single line [error]"] //~ WARNING `[error]` cannot be resolved +#[doc = "single line [error]"] //~ WARNING `error` pub struct C; -#[doc = "single line with \"escaping\" [error]"] //~ WARNING `[error]` cannot be resolved +#[doc = "single line with \"escaping\" [error]"] //~ WARNING `error` pub struct D; -/// Item docs. //~ WARNING `[error]` cannot be resolved +/// Item docs. //~ WARNING `error` #[doc="Hello there!"] /// [error] pub struct E; /// -/// docs [error1] //~ WARNING `[error1]` cannot be resolved +/// docs [error1] //~ WARNING `error1` -/// docs [error2] //~ WARNING `[error2]` cannot be resolved +/// docs [error2] //~ WARNING `error2` /// pub struct F; diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 914a19fc536c7..81931399c240a 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -1,77 +1,77 @@ -warning: `[Foo::baz]` cannot be resolved, ignoring it. +warning: unresolved link to `Foo::baz` --> $DIR/intra-links-warning.rs:3:23 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^ unresolved link | = note: `#[warn(intra_doc_link_resolution_failure)]` on by default - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Bar::foo]` cannot be resolved, ignoring it. +warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Uniooon::X]` cannot be resolved, ignoring it. +warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Qux::Z]` cannot be resolved, ignoring it. +warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Uniooon::X]` cannot be resolved, ignoring it. +warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ cannot be resolved, ignoring + | ^^^^^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Qux::Z]` cannot be resolved, ignoring it. +warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[Qux:Y]` cannot be resolved, ignoring it. +warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:68:1 | LL | #[doc = "single line [error]"] @@ -81,9 +81,9 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:71:1 | LL | #[doc = "single line with \"escaping\" [error]"] @@ -93,9 +93,9 @@ LL | #[doc = "single line with \"escaping\" [error]"] single line with "escaping" [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error]` cannot be resolved, ignoring it. +warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:74:1 | LL | / /// Item docs. @@ -107,49 +107,49 @@ LL | | /// [error] [error] ^^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error1]` cannot be resolved, ignoring it. +warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[error2]` cannot be resolved, ignoring it. +warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ cannot be resolved, ignoring + | ^^^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarA]` cannot be resolved, ignoring it. +warning: unresolved link to `BarA` --> $DIR/intra-links-warning.rs:21:10 | LL | /// bar [BarA] bar - | ^^^^ cannot be resolved, ignoring + | ^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarB]` cannot be resolved, ignoring it. +warning: unresolved link to `BarB` --> $DIR/intra-links-warning.rs:27:9 | LL | * bar [BarB] bar - | ^^^^ cannot be resolved, ignoring + | ^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarC]` cannot be resolved, ignoring it. +warning: unresolved link to `BarC` --> $DIR/intra-links-warning.rs:34:6 | LL | bar [BarC] bar - | ^^^^ cannot be resolved, ignoring + | ^^^^ unresolved link | - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarD]` cannot be resolved, ignoring it. +warning: unresolved link to `BarD` --> $DIR/intra-links-warning.rs:45:1 | LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] @@ -159,9 +159,9 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] bar [BarD] bar ^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -warning: `[BarF]` cannot be resolved, ignoring it. +warning: unresolved link to `BarF` --> $DIR/intra-links-warning.rs:50:9 | LL | #[doc = $f] @@ -174,7 +174,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); bar [BarF] bar ^^^^ - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: 19 warnings emitted diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr index 03f95f19d326e..3c41f7e63e637 100644 --- a/src/test/rustdoc-ui/issue-74134.public.stderr +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -1,4 +1,4 @@ -warning: `[PrivateType]` public documentation for `public_item` links to a private item +warning: public documentation for `public_item` links to private item `PrivateType` --> $DIR/issue-74134.rs:19:10 | LL | /// [`PrivateType`] diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs index d561c2dd89015..fe484b43fb6fc 100644 --- a/src/test/rustdoc-ui/issue-74134.rs +++ b/src/test/rustdoc-ui/issue-74134.rs @@ -17,7 +17,7 @@ pub struct PublicType; pub struct Public { /// [`PublicType`] /// [`PrivateType`] - //[public]~^ WARNING public documentation for `public_item` links to a private + //[public]~^ WARNING public documentation for `public_item` links to private item `PrivateType` pub public_item: u32, /// [`PublicType`] diff --git a/src/test/rustdoc-ui/lint-group.rs b/src/test/rustdoc-ui/lint-group.rs index 06766db5335a1..e58c8b12f68cb 100644 --- a/src/test/rustdoc-ui/lint-group.rs +++ b/src/test/rustdoc-ui/lint-group.rs @@ -11,7 +11,7 @@ /// ``` /// println!("sup"); /// ``` -pub fn link_error() {} //~^^^^^ ERROR cannot be resolved, ignoring it +pub fn link_error() {} //~^^^^^ ERROR unresolved link to `error` /// wait, this doesn't have a doctest? pub fn no_doctest() {} //~^ ERROR missing code example in this documentation diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 852c9120e0bf9..14d72e9aad3ba 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -15,11 +15,11 @@ LL | #![deny(rustdoc)] | ^^^^^^^ = note: `#[deny(private_doc_tests)]` implied by `#[deny(rustdoc)]` -error: `[error]` cannot be resolved, ignoring it. +error: unresolved link to `error` --> $DIR/lint-group.rs:9:29 | LL | /// what up, let's make an [error] - | ^^^^^ cannot be resolved, ignoring + | ^^^^^ unresolved link | note: the lint level is defined here --> $DIR/lint-group.rs:7:9 @@ -27,7 +27,7 @@ note: the lint level is defined here LL | #![deny(rustdoc)] | ^^^^^^^ = note: `#[deny(intra_doc_link_resolution_failure)]` implied by `#[deny(rustdoc)]` - = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: missing code example in this documentation --> $DIR/lint-group.rs:16:1 diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs index 8c6073e2f7a49..1eeb01ccc846e 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs @@ -35,7 +35,7 @@ fn baz<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) { #[cfg(transmute)] // one instantiations: BAD fn baz<'a,'b>(x: &'a u32) -> &'static u32 { - bar(foo, x) //[transmute]~ ERROR E0495 + bar(foo, x) //[transmute]~ ERROR E0759 } #[cfg(krisskross)] // two instantiations, mixing and matching: BAD diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index 5ea98dcd4a972..0be9b37263a48 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -1,26 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/project-fn-ret-contravariant.rs:38:8 | -LL | bar(foo, x) - | ^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 37:8... - --> $DIR/project-fn-ret-contravariant.rs:37:8 - | LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { - | ^^ -note: ...so that reference does not outlive borrowed content - --> $DIR/project-fn-ret-contravariant.rs:38:13 - | -LL | bar(foo, x) - | ^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that reference does not outlive borrowed content - --> $DIR/project-fn-ret-contravariant.rs:38:4 - | + | ------- this data with lifetime `'a`... LL | bar(foo, x) - | ^^^^^^^^^^^ + | ----^^^---- ...is captured and required to live as long as `'static` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs index 0034d796826de..08d864f7836d2 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs @@ -46,7 +46,7 @@ fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { // Cannot instantiate `foo` with any lifetime other than `'a`, // since it is provided as input. - bar(foo, x) //[transmute]~ ERROR E0495 + bar(foo, x) //[transmute]~ ERROR E0759 } #[cfg(krisskross)] // two instantiations, mixing and matching: BAD diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index ef57f9e0bc480..0a44864b24955 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -1,30 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/project-fn-ret-invariant.rs:49:9 | -LL | bar(foo, x) - | ^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8... - --> $DIR/project-fn-ret-invariant.rs:45:8 - | LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { - | ^^ -note: ...so that the expression is assignable - --> $DIR/project-fn-ret-invariant.rs:49:14 - | -LL | bar(foo, x) - | ^ - = note: expected `Type<'_>` - found `Type<'a>` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable - --> $DIR/project-fn-ret-invariant.rs:49:5 - | + | -------- this data with lifetime `'a`... +... LL | bar(foo, x) - | ^^^^^^^^^^^ - = note: expected `Type<'static>` - found `Type<'_>` + | ----^^^---- ...is captured and required to live as long as `'static` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/async-await/issues/issue-62097.rs b/src/test/ui/async-await/issues/issue-62097.rs index ea482d3667e2b..66ebbd83ffa9e 100644 --- a/src/test/ui/async-await/issues/issue-62097.rs +++ b/src/test/ui/async-await/issues/issue-62097.rs @@ -9,7 +9,7 @@ where struct Struct; impl Struct { - pub async fn run_dummy_fn(&self) { //~ ERROR cannot infer + pub async fn run_dummy_fn(&self) { //~ ERROR E0759 foo(|| self.bar()).await; } diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 0f58b158904db..56a28d904b91d 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/issue-62097.rs:12:31 | LL | pub async fn run_dummy_fn(&self) { diff --git a/src/test/ui/cfguard-run.rs b/src/test/ui/cfguard-run.rs index 21368fad3b058..3c4f9a1f5ee2c 100644 --- a/src/test/ui/cfguard-run.rs +++ b/src/test/ui/cfguard-run.rs @@ -1,5 +1,5 @@ // run-pass -// compile-flags: -Z control-flow-guard +// compile-flags: -C control-flow-guard pub fn main() { println!("hello, world"); diff --git a/src/test/ui/const-generics/const-argument-non-static-lifetime.rs b/src/test/ui/const-generics/const-argument-non-static-lifetime.rs new file mode 100644 index 0000000000000..bc09ba2ab553b --- /dev/null +++ b/src/test/ui/const-generics/const-argument-non-static-lifetime.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete +#![allow(dead_code)] + +fn test<const N: usize>() {} + +fn wow<'a>() -> &'a () { + test::<{ + let _: &'a (); + 3 + }>(); + &() +} + +fn main() {} diff --git a/src/test/ui/const-generics/const-argument-non-static-lifetime.stderr b/src/test/ui/const-generics/const-argument-non-static-lifetime.stderr new file mode 100644 index 0000000000000..53a7550090d44 --- /dev/null +++ b/src/test/ui/const-generics/const-argument-non-static-lifetime.stderr @@ -0,0 +1,11 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-argument-non-static-lifetime.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/consts/issue-73976-monomorphic.rs b/src/test/ui/consts/issue-73976-monomorphic.rs new file mode 100644 index 0000000000000..7706a97f23b48 --- /dev/null +++ b/src/test/ui/consts/issue-73976-monomorphic.rs @@ -0,0 +1,36 @@ +// check-pass +// +// This test is complement to the test in issue-73976-polymorphic.rs. +// In that test we ensure that polymorphic use of type_id and type_name in patterns +// will be properly rejected. This test will ensure that monomorphic use of these +// would not be wrongly rejected in patterns. + +#![feature(const_type_id)] +#![feature(const_type_name)] + +use std::any::{self, TypeId}; + +pub struct GetTypeId<T>(T); + +impl<T: 'static> GetTypeId<T> { + pub const VALUE: TypeId = TypeId::of::<T>(); +} + +const fn check_type_id<T: 'static>() -> bool { + matches!(GetTypeId::<T>::VALUE, GetTypeId::<usize>::VALUE) +} + +pub struct GetTypeNameLen<T>(T); + +impl<T: 'static> GetTypeNameLen<T> { + pub const VALUE: usize = any::type_name::<T>().len(); +} + +const fn check_type_name_len<T: 'static>() -> bool { + matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<usize>::VALUE) +} + +fn main() { + assert!(check_type_id::<usize>()); + assert!(check_type_name_len::<usize>()); +} diff --git a/src/test/ui/consts/issue-73976-polymorphic.rs b/src/test/ui/consts/issue-73976-polymorphic.rs new file mode 100644 index 0000000000000..28b84518719a1 --- /dev/null +++ b/src/test/ui/consts/issue-73976-polymorphic.rs @@ -0,0 +1,40 @@ +// This test is from #73976. We previously did not check if a type is monomorphized +// before calculating its type id, which leads to the bizzare behaviour below that +// TypeId of a generic type does not match itself. +// +// This test case should either run-pass or be rejected at compile time. +// Currently we just disallow this usage and require pattern is monomorphic. + +#![feature(const_type_id)] +#![feature(const_type_name)] + +use std::any::{self, TypeId}; + +pub struct GetTypeId<T>(T); + +impl<T: 'static> GetTypeId<T> { + pub const VALUE: TypeId = TypeId::of::<T>(); +} + +const fn check_type_id<T: 'static>() -> bool { + matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE) + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern +} + +pub struct GetTypeNameLen<T>(T); + +impl<T: 'static> GetTypeNameLen<T> { + pub const VALUE: usize = any::type_name::<T>().len(); +} + +const fn check_type_name_len<T: 'static>() -> bool { + matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE) + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern +} + +fn main() { + assert!(check_type_id::<usize>()); + assert!(check_type_name_len::<usize>()); +} diff --git a/src/test/ui/consts/issue-73976-polymorphic.stderr b/src/test/ui/consts/issue-73976-polymorphic.stderr new file mode 100644 index 0000000000000..c90ce2bd06a67 --- /dev/null +++ b/src/test/ui/consts/issue-73976-polymorphic.stderr @@ -0,0 +1,26 @@ +error: could not evaluate constant pattern + --> $DIR/issue-73976-polymorphic.rs:20:37 + | +LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-73976-polymorphic.rs:32:42 + | +LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-73976-polymorphic.rs:20:37 + | +LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-73976-polymorphic.rs:32:42 + | +LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/error-codes/E0771.rs b/src/test/ui/error-codes/E0771.rs new file mode 100644 index 0000000000000..ba3592719408c --- /dev/null +++ b/src/test/ui/error-codes/E0771.rs @@ -0,0 +1,8 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +fn function_with_str<'a, const STRING: &'a str>() {} //~ ERROR E0771 + +fn main() { + function_with_str::<"Hello, world!">() +} diff --git a/src/test/ui/error-codes/E0771.stderr b/src/test/ui/error-codes/E0771.stderr new file mode 100644 index 0000000000000..60220be6b57ba --- /dev/null +++ b/src/test/ui/error-codes/E0771.stderr @@ -0,0 +1,20 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/E0771.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + +error[E0771]: use of non-static lifetime `'a` in const generic + --> $DIR/E0771.rs:4:41 + | +LL | fn function_with_str<'a, const STRING: &'a str>() {} + | ^^ + | + = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052> + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0771`. diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs index d4ad706d01bc2..89210fdf137e0 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs @@ -17,7 +17,7 @@ fn static_val<T: StaticTrait>(_: T) { } fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) { - static_val(x); //~ ERROR cannot infer + static_val(x); //~ ERROR E0759 } fn not_static_val<T: NotStaticTrait>(_: T) { diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 268008c211129..b3bef677d19c1 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -1,30 +1,17 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/dyn-trait.rs:20:16 | -LL | static_val(x); - | ^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 19:26... - --> $DIR/dyn-trait.rs:19:26 - | LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) { - | ^^ -note: ...so that the expression is assignable - --> $DIR/dyn-trait.rs:20:16 - | + | ------------------- this data with lifetime `'a`... LL | static_val(x); - | ^ - = note: expected `std::boxed::Box<dyn std::fmt::Debug>` - found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the types are compatible + | ^ ...is captured here... + | +note: ...and is required to live as long as `'static` here --> $DIR/dyn-trait.rs:20:5 | LL | static_val(x); | ^^^^^^^^^^ - = note: expected `StaticTrait` - found `StaticTrait` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index 3b339c5c3d7fc..4372de245078f 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -12,7 +12,7 @@ LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:6:32 + --> $DIR/must_outlive_least_region_or_bound.rs:5:32 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | -- ^^^^^^^^^ opaque type requires that `'a` must outlive `'static` @@ -26,7 +26,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:9:46 + --> $DIR/must_outlive_least_region_or_bound.rs:7:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | - ^ returning this value requires that `'1` must outlive `'static` @@ -36,7 +36,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x } = help: consider replacing `'1` with `'static` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:12:55 + --> $DIR/must_outlive_least_region_or_bound.rs:9:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` @@ -45,7 +45,7 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } = help: consider replacing `'a` with `'static` error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/must_outlive_least_region_or_bound.rs:15:41 + --> $DIR/must_outlive_least_region_or_bound.rs:11:41 | LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | ---- ^ lifetime `'a` required @@ -53,7 +53,7 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:30:24 + --> $DIR/must_outlive_least_region_or_bound.rs:22:24 | LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` @@ -61,7 +61,7 @@ LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } | let's call the lifetime of this reference `'1` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:37:69 + --> $DIR/must_outlive_least_region_or_bound.rs:28:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` @@ -70,7 +70,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } = help: consider replacing `'a` with `'static` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:42:61 + --> $DIR/must_outlive_least_region_or_bound.rs:32:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a` @@ -80,7 +80,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 = help: consider adding the following bound: `'b: 'a` error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:47:51 + --> $DIR/must_outlive_least_region_or_bound.rs:37:51 | LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static { | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index 9bf86fa66cded..51f488e45a6f3 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -1,41 +1,31 @@ use std::fmt::Debug; -fn elided(x: &i32) -> impl Copy { x } -//~^ ERROR cannot infer an appropriate lifetime +fn elided(x: &i32) -> impl Copy { x } //~ ERROR E0759 -fn explicit<'a>(x: &'a i32) -> impl Copy { x } -//~^ ERROR cannot infer an appropriate lifetime +fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~ ERROR E0759 -fn elided2(x: &i32) -> impl Copy + 'static { x } -//~^ ERROR cannot infer an appropriate lifetime +fn elided2(x: &i32) -> impl Copy + 'static { x } //~ ERROR E0759 -fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } -//~^ ERROR cannot infer an appropriate lifetime +fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } //~ ERROR E0759 fn foo<'a>(x: &i32) -> impl Copy + 'a { x } //~^ ERROR explicit lifetime required in the type of `x` -fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } -//~^ ERROR cannot infer an appropriate lifetime +fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } //~ ERROR E0759 -fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } -//~^ ERROR cannot infer an appropriate lifetime +fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } //~ ERROR E0759 -fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } -//~^ ERROR cannot infer an appropriate lifetime +fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759 -fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } -//~^ ERROR cannot infer an appropriate lifetime +fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759 -fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } -//~^ ERROR cannot infer an appropriate lifetime -//~| ERROR cannot infer an appropriate lifetime +fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } //~ ERROR E0759 +//~^ ERROR E0759 trait LifetimeTrait<'a> {} impl<'a> LifetimeTrait<'a> for &'a i32 {} -fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } -//~^ ERROR cannot infer an appropriate lifetime +fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~ ERROR E0759 // Tests that a closure type containing 'b cannot be returned from a type where // only 'a was expected. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index ffadcaae08e05..b040889217e47 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } @@ -16,8 +16,8 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:6:44 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:5:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | ------- ^ ...is captured here... @@ -25,7 +25,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | this data with lifetime `'a`... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:6:32 + --> $DIR/must_outlive_least_region_or_bound.rs:5:32 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | ^^^^^^^^^ @@ -34,8 +34,8 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:9:46 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:7:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | ---- ^ ...is captured here... @@ -43,7 +43,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | this data with an anonymous lifetime `'_`... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:9:24 + --> $DIR/must_outlive_least_region_or_bound.rs:7:24 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^^^^^^^^ @@ -56,8 +56,8 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:12:55 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:9:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | ------- ^ ...is captured here... @@ -65,7 +65,7 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | this data with lifetime `'a`... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:12:33 + --> $DIR/must_outlive_least_region_or_bound.rs:9:33 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^^^^^^^^ @@ -79,15 +79,15 @@ LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x } | ^^^^^^^^^^^^ error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/must_outlive_least_region_or_bound.rs:15:24 + --> $DIR/must_outlive_least_region_or_bound.rs:11:24 | LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | ---- ^^^^^^^^^^^^^^ lifetime `'a` required | | | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:30:65 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:22:65 | LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static` @@ -101,14 +101,14 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:30:69 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:22:69 | LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:30:41 + --> $DIR/must_outlive_least_region_or_bound.rs:22:41 | LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } | ^^^^^^^^^^ @@ -121,14 +121,14 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:37:69 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:28:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ------- this data with lifetime `'a`... ^ ...is captured here... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:37:34 + --> $DIR/must_outlive_least_region_or_bound.rs:28:34 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x | ^^^^^^^^^^^^ error[E0623]: lifetime mismatch - --> $DIR/must_outlive_least_region_or_bound.rs:42:61 + --> $DIR/must_outlive_least_region_or_bound.rs:32:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | ------- ^^^^^^^^^^^^^^^^ @@ -151,15 +151,15 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 | this parameter and the return type are declared with different lifetimes... error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:47:51 + --> $DIR/must_outlive_least_region_or_bound.rs:37:51 | LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static { | -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `T: 'static +` -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:18:50 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:14:50 | LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } | ---- ^ ...is captured here, requiring it to live as long as `'static` @@ -171,8 +171,8 @@ help: to declare that the trait object captures data from argument `x`, you can LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:21:59 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:16:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } | ------- ^ ...is captured here, requiring it to live as long as `'static` @@ -184,8 +184,8 @@ help: to declare that the trait object captures data from argument `x`, you can LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) } | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:24:60 +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:18:60 | LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } | ---- ^ ...is captured here, requiring it to live as long as `'static` @@ -201,8 +201,8 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn elided4(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) } | ^^^^^^^^^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:27:69 +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/must_outlive_least_region_or_bound.rs:20:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static` diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr index 123ea6af6b019..65178cc9d24c2 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr @@ -12,7 +12,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/static-return-lifetime-infered.rs:10:37 + --> $DIR/static-return-lifetime-infered.rs:9:37 | LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { | -- ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static` diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.rs b/src/test/ui/impl-trait/static-return-lifetime-infered.rs index 96f3652c226ea..518c52f5de4d7 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.rs +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.rs @@ -4,13 +4,11 @@ struct A { impl A { fn iter_values_anon(&self) -> impl Iterator<Item=u32> { - self.x.iter().map(|a| a.0) + self.x.iter().map(|a| a.0) //~ ERROR E0759 } - //~^^ ERROR cannot infer an appropriate lifetime fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { - self.x.iter().map(|a| a.0) + self.x.iter().map(|a| a.0) //~ ERROR E0759 } - //~^^ ERROR cannot infer an appropriate lifetime } fn main() {} diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index df0db6e4fc6df..7c289b388223a 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { @@ -18,8 +18,8 @@ help: to declare that the `impl Trait` captures data from argument `self`, you c LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime - --> $DIR/static-return-lifetime-infered.rs:11:16 +error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/static-return-lifetime-infered.rs:10:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { | -------- this data with lifetime `'a`... @@ -29,7 +29,7 @@ LL | self.x.iter().map(|a| a.0) | ...is captured here... | note: ...and is required to live as long as `'static` here - --> $DIR/static-return-lifetime-infered.rs:10:37 + --> $DIR/static-return-lifetime-infered.rs:9:37 | LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-16922.rs b/src/test/ui/issues/issue-16922.rs index 827163ef83cf7..f048ccd2427cb 100644 --- a/src/test/ui/issues/issue-16922.rs +++ b/src/test/ui/issues/issue-16922.rs @@ -1,8 +1,7 @@ use std::any::Any; fn foo<T: Any>(value: &T) -> Box<dyn Any> { - Box::new(value) as Box<dyn Any> - //~^ ERROR cannot infer an appropriate lifetime + Box::new(value) as Box<dyn Any> //~ ERROR E0759 } fn main() { diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 919594fc9af4b..6decc751321f9 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/issue-16922.rs:4:14 | LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> { diff --git a/src/test/ui/issues/issue-74539.rs b/src/test/ui/issues/issue-74539.rs new file mode 100644 index 0000000000000..75632d11c1df0 --- /dev/null +++ b/src/test/ui/issues/issue-74539.rs @@ -0,0 +1,12 @@ +enum E { + A(u8, u8), +} + +fn main() { + let e = E::A(2, 3); + match e { + E::A(x @ ..) => { //~ ERROR `x @` is not allowed in a tuple + x //~ ERROR cannot find value `x` in this scope + } + }; +} diff --git a/src/test/ui/issues/issue-74539.stderr b/src/test/ui/issues/issue-74539.stderr new file mode 100644 index 0000000000000..94526dcd7cb39 --- /dev/null +++ b/src/test/ui/issues/issue-74539.stderr @@ -0,0 +1,21 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/issue-74539.rs:9:13 + | +LL | x + | ^ help: a local variable with a similar name exists: `e` + +error: `x @` is not allowed in a tuple struct + --> $DIR/issue-74539.rs:8:14 + | +LL | E::A(x @ ..) => { + | ^^^^^^ this is only allowed in slice patterns + | + = help: remove this and bind each tuple field independently +help: if you don't need to use the contents of x, discard the tuple's remaining fields + | +LL | E::A(..) => { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/lint/lint-ctypes.rs b/src/test/ui/lint/lint-ctypes.rs index bdf95350c7045..f485766bcd34e 100644 --- a/src/test/ui/lint/lint-ctypes.rs +++ b/src/test/ui/lint/lint-ctypes.rs @@ -7,6 +7,7 @@ extern crate libc; use std::marker::PhantomData; +trait Bar { } trait Mirror { type It: ?Sized; } impl<T: ?Sized> Mirror for T { type It = Self; } #[repr(C)] @@ -53,7 +54,7 @@ extern { pub fn char_type(p: char); //~ ERROR uses type `char` pub fn i128_type(p: i128); //~ ERROR uses type `i128` pub fn u128_type(p: u128); //~ ERROR uses type `u128` - pub fn trait_type(p: &dyn Clone); //~ ERROR uses type `dyn std::clone::Clone` + pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar` pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)` pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)` pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize` diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr index 13b9adca3f9f5..a54226a7fc4a2 100644 --- a/src/test/ui/lint/lint-ctypes.stderr +++ b/src/test/ui/lint/lint-ctypes.stderr @@ -1,5 +1,5 @@ error: `extern` block uses type `Foo`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:46:28 + --> $DIR/lint-ctypes.rs:47:28 | LL | pub fn ptr_type1(size: *const Foo); | ^^^^^^^^^^ not FFI-safe @@ -12,13 +12,13 @@ LL | #![deny(improper_ctypes)] = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes.rs:24:1 + --> $DIR/lint-ctypes.rs:25:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^^ error: `extern` block uses type `Foo`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:47:28 + --> $DIR/lint-ctypes.rs:48:28 | LL | pub fn ptr_type2(size: *const Foo); | ^^^^^^^^^^ not FFI-safe @@ -26,13 +26,13 @@ LL | pub fn ptr_type2(size: *const Foo); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes.rs:24:1 + --> $DIR/lint-ctypes.rs:25:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^^ error: `extern` block uses type `[u32]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:48:26 + --> $DIR/lint-ctypes.rs:49:26 | LL | pub fn slice_type(p: &[u32]); | ^^^^^^ not FFI-safe @@ -41,7 +41,7 @@ LL | pub fn slice_type(p: &[u32]); = note: slices have no C equivalent error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:49:24 + --> $DIR/lint-ctypes.rs:50:24 | LL | pub fn str_type(p: &str); | ^^^^ not FFI-safe @@ -50,7 +50,7 @@ LL | pub fn str_type(p: &str); = note: string slices have no C equivalent error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:50:24 + --> $DIR/lint-ctypes.rs:51:24 | LL | pub fn box_type(p: Box<u32>); | ^^^^^^^^ not FFI-safe @@ -59,7 +59,7 @@ LL | pub fn box_type(p: Box<u32>); = note: this struct has unspecified layout error: `extern` block uses type `std::option::Option<std::boxed::Box<u32>>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:51:28 + --> $DIR/lint-ctypes.rs:52:28 | LL | pub fn opt_box_type(p: Option<Box<u32>>); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -68,7 +68,7 @@ LL | pub fn opt_box_type(p: Option<Box<u32>>); = note: enum has no representation hint error: `extern` block uses type `char`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:53:25 + --> $DIR/lint-ctypes.rs:54:25 | LL | pub fn char_type(p: char); | ^^^^ not FFI-safe @@ -77,7 +77,7 @@ LL | pub fn char_type(p: char); = note: the `char` type has no C equivalent error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:54:25 + --> $DIR/lint-ctypes.rs:55:25 | LL | pub fn i128_type(p: i128); | ^^^^ not FFI-safe @@ -85,23 +85,23 @@ LL | pub fn i128_type(p: i128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:55:25 + --> $DIR/lint-ctypes.rs:56:25 | LL | pub fn u128_type(p: u128); | ^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:56:26 +error: `extern` block uses type `dyn Bar`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:57:26 | -LL | pub fn trait_type(p: &dyn Clone); - | ^^^^^^^^^^ not FFI-safe +LL | pub fn trait_type(p: &dyn Bar); + | ^^^^^^^^ not FFI-safe | = note: trait objects have no C equivalent error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:57:26 + --> $DIR/lint-ctypes.rs:58:26 | LL | pub fn tuple_type(p: (i32, i32)); | ^^^^^^^^^^ not FFI-safe @@ -110,7 +110,7 @@ LL | pub fn tuple_type(p: (i32, i32)); = note: tuples have unspecified layout error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:58:27 + --> $DIR/lint-ctypes.rs:59:27 | LL | pub fn tuple_type2(p: I32Pair); | ^^^^^^^ not FFI-safe @@ -119,7 +119,7 @@ LL | pub fn tuple_type2(p: I32Pair); = note: tuples have unspecified layout error: `extern` block uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:59:25 + --> $DIR/lint-ctypes.rs:60:25 | LL | pub fn zero_size(p: ZeroSize); | ^^^^^^^^ not FFI-safe @@ -127,26 +127,26 @@ LL | pub fn zero_size(p: ZeroSize); = help: consider adding a member to this struct = note: this struct has no fields note: the type is defined here - --> $DIR/lint-ctypes.rs:20:1 + --> $DIR/lint-ctypes.rs:21:1 | LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:60:33 + --> $DIR/lint-ctypes.rs:61:33 | LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: composed only of `PhantomData` note: the type is defined here - --> $DIR/lint-ctypes.rs:43:1 + --> $DIR/lint-ctypes.rs:44:1 | LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `std::marker::PhantomData<bool>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:63:12 + --> $DIR/lint-ctypes.rs:64:12 | LL | -> ::std::marker::PhantomData<bool>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -154,7 +154,7 @@ LL | -> ::std::marker::PhantomData<bool>; = note: composed only of `PhantomData` error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:64:23 + --> $DIR/lint-ctypes.rs:65:23 | LL | pub fn fn_type(p: RustFn); | ^^^^^^ not FFI-safe @@ -163,7 +163,7 @@ LL | pub fn fn_type(p: RustFn); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:65:24 + --> $DIR/lint-ctypes.rs:66:24 | LL | pub fn fn_type2(p: fn()); | ^^^^ not FFI-safe @@ -172,7 +172,7 @@ LL | pub fn fn_type2(p: fn()); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:66:28 + --> $DIR/lint-ctypes.rs:67:28 | LL | pub fn fn_contained(p: RustBadRet); | ^^^^^^^^^^ not FFI-safe @@ -181,7 +181,7 @@ LL | pub fn fn_contained(p: RustBadRet); = note: this struct has unspecified layout error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:67:32 + --> $DIR/lint-ctypes.rs:68:32 | LL | pub fn transparent_i128(p: TransparentI128); | ^^^^^^^^^^^^^^^ not FFI-safe @@ -189,7 +189,7 @@ LL | pub fn transparent_i128(p: TransparentI128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:68:31 + --> $DIR/lint-ctypes.rs:69:31 | LL | pub fn transparent_str(p: TransparentStr); | ^^^^^^^^^^^^^^ not FFI-safe @@ -198,7 +198,7 @@ LL | pub fn transparent_str(p: TransparentStr); = note: string slices have no C equivalent error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:69:30 + --> $DIR/lint-ctypes.rs:70:30 | LL | pub fn transparent_fn(p: TransparentBadFn); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -207,7 +207,7 @@ LL | pub fn transparent_fn(p: TransparentBadFn); = note: this struct has unspecified layout error: `extern` block uses type `[u8; 8]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:70:27 + --> $DIR/lint-ctypes.rs:71:27 | LL | pub fn raw_array(arr: [u8; 8]); | ^^^^^^^ not FFI-safe @@ -216,7 +216,7 @@ LL | pub fn raw_array(arr: [u8; 8]); = note: passing raw arrays by value is not FFI-safe error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:72:34 + --> $DIR/lint-ctypes.rs:73:34 | LL | pub static static_u128_type: u128; | ^^^^ not FFI-safe @@ -224,7 +224,7 @@ LL | pub static static_u128_type: u128; = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:73:40 + --> $DIR/lint-ctypes.rs:74:40 | LL | pub static static_u128_array_type: [u128; 16]; | ^^^^^^^^^^ not FFI-safe diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index 8421dc1d0c130..1931934a2112a 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -1,28 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements +error[E0759]: `fn` parameter has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/constant-in-expr-inherent-1.rs:8:5 | -LL | <Foo<'a>>::C - | ^^^^^^^^^^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 7:8... - --> $DIR/constant-in-expr-inherent-1.rs:7:8 - | LL | fn foo<'a>(_: &'a u32) -> &'static u32 { - | ^^ -note: ...so that the types are compatible - --> $DIR/constant-in-expr-inherent-1.rs:8:5 - | -LL | <Foo<'a>>::C - | ^^^^^^^^^^^^ - = note: expected `Foo<'_>` - found `Foo<'a>` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that reference does not outlive borrowed content - --> $DIR/constant-in-expr-inherent-1.rs:8:5 - | + | ------- this data with lifetime `'a`... LL | <Foo<'a>>::C - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs index 708ab1cf38297..4a2665d8e1694 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs @@ -15,7 +15,7 @@ fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> { // `Box<SomeTrait>` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR cannot infer an appropriate lifetime + ss.r //~ ERROR E0759 } fn store(ss: &mut SomeStruct, b: Box<dyn SomeTrait>) { diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 1b1e0d9610724..70b99ef7869ca 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `ss` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> { diff --git a/src/test/ui/polymorphization/const_parameters/closures.rs b/src/test/ui/polymorphization/const_parameters/closures.rs new file mode 100644 index 0000000000000..7bbcaebea0125 --- /dev/null +++ b/src/test/ui/polymorphization/const_parameters/closures.rs @@ -0,0 +1,66 @@ +// build-fail +#![feature(const_generics, rustc_attrs)] +//~^ WARN the feature `const_generics` is incomplete + +// This test checks that the polymorphization analysis correctly detects unused const +// parameters in closures. + +// Function doesn't have any generic parameters to be unused. +#[rustc_polymorphize_error] +pub fn no_parameters() { + let _ = || {}; +} + +// Function has an unused generic parameter in parent and closure. +#[rustc_polymorphize_error] +pub fn unused<const T: usize>() -> usize { + //~^ ERROR item has unused generic parameters + let add_one = |x: usize| x + 1; + //~^ ERROR item has unused generic parameters + add_one(3) +} + +// Function has an unused generic parameter in closure, but not in parent. +#[rustc_polymorphize_error] +pub fn used_parent<const T: usize>() -> usize { + let x: usize = T; + let add_one = |x: usize| x + 1; + //~^ ERROR item has unused generic parameters + x + add_one(3) +} + +// Function uses generic parameter in value of a binding in closure. +#[rustc_polymorphize_error] +pub fn used_binding<const T: usize>() -> usize { + let x = || { + let y: usize = T; + y + }; + + x() +} + +// Closure uses a value as an upvar, which used the generic parameter. +#[rustc_polymorphize_error] +pub fn unused_upvar<const T: usize>() -> usize { + let x: usize = T; + let y = || x; + //~^ ERROR item has unused generic parameters + y() +} + +// Closure uses generic parameter in substitutions to another function. +#[rustc_polymorphize_error] +pub fn used_substs<const T: usize>() -> usize { + let x = || unused::<T>(); + x() +} + +fn main() { + no_parameters(); + let _ = unused::<1>(); + let _ = used_parent::<1>(); + let _ = used_binding::<1>(); + let _ = unused_upvar::<1>(); + let _ = used_substs::<1>(); +} diff --git a/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr new file mode 100644 index 0000000000000..eb872eac74c91 --- /dev/null +++ b/src/test/ui/polymorphization/const_parameters/closures.stderr @@ -0,0 +1,44 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closures.rs:2:12 + | +LL | #![feature(const_generics, rustc_attrs)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + +error: item has unused generic parameters + --> $DIR/closures.rs:18:19 + | +LL | pub fn unused<const T: usize>() -> usize { + | - generic parameter `T` is unused +LL | +LL | let add_one = |x: usize| x + 1; + | ^^^^^^^^^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/closures.rs:16:8 + | +LL | pub fn unused<const T: usize>() -> usize { + | ^^^^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/closures.rs:27:19 + | +LL | pub fn used_parent<const T: usize>() -> usize { + | - generic parameter `T` is unused +LL | let x: usize = T; +LL | let add_one = |x: usize| x + 1; + | ^^^^^^^^^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/closures.rs:47:13 + | +LL | pub fn unused_upvar<const T: usize>() -> usize { + | - generic parameter `T` is unused +LL | let x: usize = T; +LL | let y = || x; + | ^^^^ + +error: aborting due to 4 previous errors; 1 warning emitted + diff --git a/src/test/ui/polymorphization/const_parameters/functions.rs b/src/test/ui/polymorphization/const_parameters/functions.rs new file mode 100644 index 0000000000000..77539b94e489a --- /dev/null +++ b/src/test/ui/polymorphization/const_parameters/functions.rs @@ -0,0 +1,36 @@ +// build-fail +#![feature(const_generics, rustc_attrs)] +//~^ WARN the feature `const_generics` is incomplete + +// This test checks that the polymorphization analysis correctly detects unused const +// parameters in functions. + +// Function doesn't have any generic parameters to be unused. +#[rustc_polymorphize_error] +pub fn no_parameters() {} + +// Function has an unused generic parameter. +#[rustc_polymorphize_error] +pub fn unused<const T: usize>() { + //~^ ERROR item has unused generic parameters +} + +// Function uses generic parameter in value of a binding. +#[rustc_polymorphize_error] +pub fn used_binding<const T: usize>() -> usize { + let x: usize = T; + x +} + +// Function uses generic parameter in substitutions to another function. +#[rustc_polymorphize_error] +pub fn used_substs<const T: usize>() { + unused::<T>() +} + +fn main() { + no_parameters(); + unused::<1>(); + used_binding::<1>(); + used_substs::<1>(); +} diff --git a/src/test/ui/polymorphization/const_parameters/functions.stderr b/src/test/ui/polymorphization/const_parameters/functions.stderr new file mode 100644 index 0000000000000..c99a9b788ebc5 --- /dev/null +++ b/src/test/ui/polymorphization/const_parameters/functions.stderr @@ -0,0 +1,17 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/functions.rs:2:12 + | +LL | #![feature(const_generics, rustc_attrs)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + +error: item has unused generic parameters + --> $DIR/functions.rs:14:8 + | +LL | pub fn unused<const T: usize>() { + | ^^^^^^ - generic parameter `T` is unused + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/polymorphization/drop_shims/simple.rs b/src/test/ui/polymorphization/drop_shims/simple.rs new file mode 100644 index 0000000000000..ce56b7a358861 --- /dev/null +++ b/src/test/ui/polymorphization/drop_shims/simple.rs @@ -0,0 +1,21 @@ +// check-pass + +pub struct OnDrop<F: Fn()>(pub F); + +impl<F: Fn()> Drop for OnDrop<F> { + fn drop(&mut self) { } +} + +fn foo<R, S: FnOnce()>( + _: R, + _: S, +) { + let bar = || { + let _ = OnDrop(|| ()); + }; + let _ = bar(); +} + +fn main() { + foo(3u32, || {}); +} diff --git a/src/test/ui/polymorphization/drop_shims/transitive.rs b/src/test/ui/polymorphization/drop_shims/transitive.rs new file mode 100644 index 0000000000000..b7ea07b6bc653 --- /dev/null +++ b/src/test/ui/polymorphization/drop_shims/transitive.rs @@ -0,0 +1,26 @@ +// check-pass + +pub struct OnDrop<F: Fn()>(pub F); + +impl<F: Fn()> Drop for OnDrop<F> { + fn drop(&mut self) { } +} + +fn bar<F: FnOnce()>(f: F) { + let _ = OnDrop(|| ()); + f() +} + +fn foo<R, S: FnOnce()>( + _: R, + _: S, +) { + let bar = || { + bar(|| {}) + }; + let _ = bar(); +} + +fn main() { + foo(3u32, || {}); +} diff --git a/src/test/ui/polymorphization/generators.rs b/src/test/ui/polymorphization/generators.rs new file mode 100644 index 0000000000000..1acba7c8bf14c --- /dev/null +++ b/src/test/ui/polymorphization/generators.rs @@ -0,0 +1,93 @@ +// build-fail +#![feature(const_generics, generators, generator_trait, rustc_attrs)] +//~^ WARN the feature `const_generics` is incomplete + +use std::marker::Unpin; +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +enum YieldOrReturn<Y, R> { + Yield(Y), + Return(R), +} + +fn finish<T, Y, R>(mut t: T) -> Vec<YieldOrReturn<Y, R>> +where + T: Generator<(), Yield = Y, Return = R> + Unpin, +{ + let mut results = Vec::new(); + loop { + match Pin::new(&mut t).resume(()) { + GeneratorState::Yielded(yielded) => results.push(YieldOrReturn::Yield(yielded)), + GeneratorState::Complete(returned) => { + results.push(YieldOrReturn::Return(returned)); + return results; + } + } + } +} + +// This test checks that the polymorphization analysis functions on generators. + +#[rustc_polymorphize_error] +pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { + //~^ ERROR item has unused generic parameters + || { + //~^ ERROR item has unused generic parameters + yield 1; + 2 + } +} + +#[rustc_polymorphize_error] +pub fn used_type_in_yield<Y: Default>() -> impl Generator<(), Yield = Y, Return = u32> + Unpin { + || { + yield Y::default(); + 2 + } +} + +#[rustc_polymorphize_error] +pub fn used_type_in_return<R: Default>() -> impl Generator<(), Yield = u32, Return = R> + Unpin { + || { + yield 3; + R::default() + } +} + +#[rustc_polymorphize_error] +pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { + //~^ ERROR item has unused generic parameters + || { + //~^ ERROR item has unused generic parameters + yield 1; + 2 + } +} + +#[rustc_polymorphize_error] +pub fn used_const_in_yield<const Y: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin +{ + || { + yield Y; + 2 + } +} + +#[rustc_polymorphize_error] +pub fn used_const_in_return<const R: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin +{ + || { + yield 4; + R + } +} + +fn main() { + finish(unused_type::<u32>()); + finish(used_type_in_yield::<u32>()); + finish(used_type_in_return::<u32>()); + finish(unused_const::<1u32>()); + finish(used_const_in_yield::<1u32>()); + finish(used_const_in_return::<1u32>()); +} diff --git a/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr new file mode 100644 index 0000000000000..b3e5a2de0270a --- /dev/null +++ b/src/test/ui/polymorphization/generators.stderr @@ -0,0 +1,49 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/generators.rs:2:12 + | +LL | #![feature(const_generics, generators, generator_trait, rustc_attrs)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + +error: item has unused generic parameters + --> $DIR/generators.rs:35:5 + | +LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { + | - generic parameter `T` is unused +LL | +LL | / || { +LL | | +LL | | yield 1; +LL | | 2 +LL | | } + | |_____^ + +error: item has unused generic parameters + --> $DIR/generators.rs:33:8 + | +LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { + | ^^^^^^^^^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/generators.rs:61:5 + | +LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { + | - generic parameter `T` is unused +LL | +LL | / || { +LL | | +LL | | yield 1; +LL | | 2 +LL | | } + | |_____^ + +error: item has unused generic parameters + --> $DIR/generators.rs:59:8 + | +LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { + | ^^^^^^^^^^^^ - generic parameter `T` is unused + +error: aborting due to 4 previous errors; 1 warning emitted + diff --git a/src/test/ui/polymorphization/lifetimes.rs b/src/test/ui/polymorphization/lifetimes.rs new file mode 100644 index 0000000000000..4bde349a336ea --- /dev/null +++ b/src/test/ui/polymorphization/lifetimes.rs @@ -0,0 +1,24 @@ +// build-fail +#![feature(rustc_attrs)] + +// This test checks that the polymorphization analysis doesn't break when the +// function/closure doesn't just have generic parameters. + +// Function has an unused generic parameter. +#[rustc_polymorphize_error] +pub fn unused<'a, T>(_: &'a u32) { + //~^ ERROR item has unused generic parameters +} + +#[rustc_polymorphize_error] +pub fn used<'a, T: Default>(_: &'a u32) -> u32 { + let _: T = Default::default(); + let add_one = |x: u32| x + 1; + //~^ ERROR item has unused generic parameters + add_one(3) +} + +fn main() { + unused::<u32>(&3); + used::<u32>(&3); +} diff --git a/src/test/ui/polymorphization/lifetimes.stderr b/src/test/ui/polymorphization/lifetimes.stderr new file mode 100644 index 0000000000000..6c85e4f291611 --- /dev/null +++ b/src/test/ui/polymorphization/lifetimes.stderr @@ -0,0 +1,17 @@ +error: item has unused generic parameters + --> $DIR/lifetimes.rs:9:8 + | +LL | pub fn unused<'a, T>(_: &'a u32) { + | ^^^^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/lifetimes.rs:16:19 + | +LL | pub fn used<'a, T: Default>(_: &'a u32) -> u32 { + | - generic parameter `T` is unused +LL | let _: T = Default::default(); +LL | let add_one = |x: u32| x + 1; + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/polymorphization/normalized_sig_types.rs b/src/test/ui/polymorphization/normalized_sig_types.rs new file mode 100644 index 0000000000000..fa76b7201e8c3 --- /dev/null +++ b/src/test/ui/polymorphization/normalized_sig_types.rs @@ -0,0 +1,25 @@ +// build-pass + +pub trait ParallelIterator: Sized { + fn drive<C: Consumer<()>>(_: C) { + C::into_folder(); + } +} + +pub trait Consumer<T>: Sized { + type Result; + fn into_folder() -> Self::Result; +} + +impl ParallelIterator for () {} + +impl<F: Fn(), T> Consumer<T> for F { + type Result = (); + fn into_folder() -> Self::Result { + unimplemented!() + } +} + +fn main() { + <()>::drive(|| ()); +} diff --git a/src/test/ui/polymorphization/predicates.rs b/src/test/ui/polymorphization/predicates.rs new file mode 100644 index 0000000000000..390ac983aa007 --- /dev/null +++ b/src/test/ui/polymorphization/predicates.rs @@ -0,0 +1,23 @@ +// build-fail +#![feature(rustc_attrs)] + +// This test checks that `T` is considered used in `foo`, because it is used in a predicate for +// `I`, which is used. + +#[rustc_polymorphize_error] +fn bar<I>() { + //~^ ERROR item has unused generic parameters +} + +#[rustc_polymorphize_error] +fn foo<I, T>(_: I) +where + I: Iterator<Item = T>, +{ + bar::<I>() +} + +fn main() { + let x = &[2u32]; + foo(x.iter()); +} diff --git a/src/test/ui/polymorphization/predicates.stderr b/src/test/ui/polymorphization/predicates.stderr new file mode 100644 index 0000000000000..1b266083463a2 --- /dev/null +++ b/src/test/ui/polymorphization/predicates.stderr @@ -0,0 +1,8 @@ +error: item has unused generic parameters + --> $DIR/predicates.rs:8:4 + | +LL | fn bar<I>() { + | ^^^ - generic parameter `I` is unused + +error: aborting due to previous error + diff --git a/src/test/ui/polymorphization/too-many-generic-params.rs b/src/test/ui/polymorphization/too-many-generic-params.rs new file mode 100644 index 0000000000000..ec6244630fd1f --- /dev/null +++ b/src/test/ui/polymorphization/too-many-generic-params.rs @@ -0,0 +1,85 @@ +// build-pass +#![feature(rustc_attrs)] + +// This test checks that the analysis doesn't panic when there are >64 generic parameters, but +// instead considers those parameters used. + +#[rustc_polymorphize_error] +fn bar<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, + AB, AC, AD, AE, AF, AG, AH, AI, AJ, AK, AL, AM, AN, AO, AP, AQ, AR, AS, AT, AU, AV, AW, + AX, AY, AZ, BA, BB, BC, BD, BE, BF, BG, BH, BI, BJ, BK, BL, BM>() +{ + let _: Option<A> = None; + let _: Option<B> = None; + let _: Option<C> = None; + let _: Option<D> = None; + let _: Option<E> = None; + let _: Option<F> = None; + let _: Option<G> = None; + let _: Option<H> = None; + let _: Option<I> = None; + let _: Option<J> = None; + let _: Option<K> = None; + let _: Option<L> = None; + let _: Option<M> = None; + let _: Option<N> = None; + let _: Option<O> = None; + let _: Option<P> = None; + let _: Option<Q> = None; + let _: Option<R> = None; + let _: Option<S> = None; + let _: Option<T> = None; + let _: Option<U> = None; + let _: Option<V> = None; + let _: Option<W> = None; + let _: Option<X> = None; + let _: Option<Y> = None; + let _: Option<Z> = None; + let _: Option<AA> = None; + let _: Option<AB> = None; + let _: Option<AC> = None; + let _: Option<AD> = None; + let _: Option<AE> = None; + let _: Option<AF> = None; + let _: Option<AG> = None; + let _: Option<AH> = None; + let _: Option<AI> = None; + let _: Option<AJ> = None; + let _: Option<AK> = None; + let _: Option<AL> = None; + let _: Option<AM> = None; + let _: Option<AN> = None; + let _: Option<AO> = None; + let _: Option<AP> = None; + let _: Option<AQ> = None; + let _: Option<AR> = None; + let _: Option<AS> = None; + let _: Option<AT> = None; + let _: Option<AU> = None; + let _: Option<AV> = None; + let _: Option<AW> = None; + let _: Option<AX> = None; + let _: Option<AY> = None; + let _: Option<AZ> = None; + let _: Option<BA> = None; + let _: Option<BB> = None; + let _: Option<BC> = None; + let _: Option<BD> = None; + let _: Option<BE> = None; + let _: Option<BF> = None; + let _: Option<BG> = None; + let _: Option<BH> = None; + let _: Option<BI> = None; + let _: Option<BJ> = None; + let _: Option<BK> = None; + let _: Option<BL> = None; + let _: Option<BM> = None; +} + +fn main() { + bar::<u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, + u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, + u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, + u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, + u32>(); +} diff --git a/src/test/ui/polymorphization/type_parameters/closures.rs b/src/test/ui/polymorphization/type_parameters/closures.rs new file mode 100644 index 0000000000000..1fbe13380b5b9 --- /dev/null +++ b/src/test/ui/polymorphization/type_parameters/closures.rs @@ -0,0 +1,160 @@ +// build-fail +#![feature(stmt_expr_attributes, rustc_attrs)] + +// This test checks that the polymorphization analysis correctly detects unused type +// parameters in closures. + +// Function doesn't have any generic parameters to be unused. +#[rustc_polymorphize_error] +pub fn no_parameters() { + let _ = || {}; +} + +// Function has an unused generic parameter in parent and closure. +#[rustc_polymorphize_error] +pub fn unused<T>() -> u32 { + //~^ ERROR item has unused generic parameters + + let add_one = |x: u32| x + 1; + //~^ ERROR item has unused generic parameters + add_one(3) +} + +// Function has an unused generic parameter in closure, but not in parent. +#[rustc_polymorphize_error] +pub fn used_parent<T: Default>() -> u32 { + let _: T = Default::default(); + let add_one = |x: u32| x + 1; + //~^ ERROR item has unused generic parameters + add_one(3) +} + +// Function uses generic parameter in value of a binding in closure. +#[rustc_polymorphize_error] +pub fn used_binding_value<T: Default>() -> T { + let x = || { + let y: T = Default::default(); + y + }; + + x() +} + +// Function uses generic parameter in generic of a binding in closure. +#[rustc_polymorphize_error] +pub fn used_binding_generic<T>() -> Option<T> { + let x = || { + let y: Option<T> = None; + y + }; + + x() +} + +// Function and closure uses generic parameter in argument. +#[rustc_polymorphize_error] +pub fn used_argument<T>(t: T) -> u32 { + let x = |_: T| 3; + x(t) +} + +// Closure uses generic parameter in argument. +#[rustc_polymorphize_error] +pub fn used_argument_closure<T: Default>() -> u32 { + let t: T = Default::default(); + + let x = |_: T| 3; + x(t) +} + +// Closure uses generic parameter as upvar. +#[rustc_polymorphize_error] +pub fn used_upvar<T: Default>() -> T { + let x: T = Default::default(); + + let y = || x; + y() +} + +// Closure uses generic parameter in substitutions to another function. +#[rustc_polymorphize_error] +pub fn used_substs<T>() -> u32 { + let x = || unused::<T>(); + x() +} + +struct Foo<F>(F); + +impl<F: Default> Foo<F> { + // Function has an unused generic parameter from impl and fn. + #[rustc_polymorphize_error] + pub fn unused_all<G: Default>() -> u32 { + //~^ ERROR item has unused generic parameters + let add_one = |x: u32| x + 1; + //~^ ERROR item has unused generic parameters + add_one(3) + } + + // Function uses generic parameter from impl and fn in closure. + #[rustc_polymorphize_error] + pub fn used_both<G: Default>() -> u32 { + let add_one = |x: u32| { + let _: F = Default::default(); + let _: G = Default::default(); + x + 1 + }; + + add_one(3) + } + + // Function uses generic parameter from fn in closure. + #[rustc_polymorphize_error] + pub fn used_fn<G: Default>() -> u32 { + //~^ ERROR item has unused generic parameters + let add_one = |x: u32| { + //~^ ERROR item has unused generic parameters + let _: G = Default::default(); + x + 1 + }; + + add_one(3) + } + + // Function uses generic parameter from impl in closure. + #[rustc_polymorphize_error] + pub fn used_impl<G: Default>() -> u32 { + //~^ ERROR item has unused generic parameters + let add_one = |x: u32| { + //~^ ERROR item has unused generic parameters + let _: F = Default::default(); + x + 1 + }; + + add_one(3) + } + + // Closure uses generic parameter in substitutions to another function. + #[rustc_polymorphize_error] + pub fn used_substs() -> u32 { + let x = || unused::<F>(); + x() + } +} + +fn main() { + no_parameters(); + let _ = unused::<u32>(); + let _ = used_parent::<u32>(); + let _ = used_binding_value::<u32>(); + let _ = used_binding_generic::<u32>(); + let _ = used_argument(3u32); + let _ = used_argument_closure::<u32>(); + let _ = used_upvar::<u32>(); + let _ = used_substs::<u32>(); + + let _ = Foo::<u32>::unused_all::<u32>(); + let _ = Foo::<u32>::used_both::<u32>(); + let _ = Foo::<u32>::used_impl::<u32>(); + let _ = Foo::<u32>::used_fn::<u32>(); + let _ = Foo::<u32>::used_substs(); +} diff --git a/src/test/ui/polymorphization/type_parameters/closures.stderr b/src/test/ui/polymorphization/type_parameters/closures.stderr new file mode 100644 index 0000000000000..d68e6e25a1eb9 --- /dev/null +++ b/src/test/ui/polymorphization/type_parameters/closures.stderr @@ -0,0 +1,90 @@ +error: item has unused generic parameters + --> $DIR/closures.rs:18:19 + | +LL | pub fn unused<T>() -> u32 { + | - generic parameter `T` is unused +... +LL | let add_one = |x: u32| x + 1; + | ^^^^^^^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/closures.rs:15:8 + | +LL | pub fn unused<T>() -> u32 { + | ^^^^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/closures.rs:27:19 + | +LL | pub fn used_parent<T: Default>() -> u32 { + | - generic parameter `T` is unused +LL | let _: T = Default::default(); +LL | let add_one = |x: u32| x + 1; + | ^^^^^^^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/closures.rs:93:23 + | +LL | impl<F: Default> Foo<F> { + | - generic parameter `F` is unused +... +LL | pub fn unused_all<G: Default>() -> u32 { + | - generic parameter `G` is unused +LL | +LL | let add_one = |x: u32| x + 1; + | ^^^^^^^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/closures.rs:91:12 + | +LL | impl<F: Default> Foo<F> { + | - generic parameter `F` is unused +... +LL | pub fn unused_all<G: Default>() -> u32 { + | ^^^^^^^^^^ - generic parameter `G` is unused + +error: item has unused generic parameters + --> $DIR/closures.rs:127:23 + | +LL | pub fn used_impl<G: Default>() -> u32 { + | - generic parameter `G` is unused +LL | +LL | let add_one = |x: u32| { + | _______________________^ +LL | | +LL | | let _: F = Default::default(); +LL | | x + 1 +LL | | }; + | |_________^ + +error: item has unused generic parameters + --> $DIR/closures.rs:125:12 + | +LL | pub fn used_impl<G: Default>() -> u32 { + | ^^^^^^^^^ - generic parameter `G` is unused + +error: item has unused generic parameters + --> $DIR/closures.rs:114:23 + | +LL | impl<F: Default> Foo<F> { + | - generic parameter `F` is unused +... +LL | let add_one = |x: u32| { + | _______________________^ +LL | | +LL | | let _: G = Default::default(); +LL | | x + 1 +LL | | }; + | |_________^ + +error: item has unused generic parameters + --> $DIR/closures.rs:112:12 + | +LL | impl<F: Default> Foo<F> { + | - generic parameter `F` is unused +... +LL | pub fn used_fn<G: Default>() -> u32 { + | ^^^^^^^ + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/polymorphization/type_parameters/functions.rs b/src/test/ui/polymorphization/type_parameters/functions.rs new file mode 100644 index 0000000000000..38f10148c2c52 --- /dev/null +++ b/src/test/ui/polymorphization/type_parameters/functions.rs @@ -0,0 +1,95 @@ +// build-fail +#![feature(rustc_attrs)] + +// This test checks that the polymorphization analysis correctly detects unused type +// parameters in functions. + +// Function doesn't have any generic parameters to be unused. +#[rustc_polymorphize_error] +pub fn no_parameters() {} + +// Function has an unused generic parameter. +#[rustc_polymorphize_error] +pub fn unused<T>() { + //~^ ERROR item has unused generic parameters +} + +// Function uses generic parameter in value of a binding. +#[rustc_polymorphize_error] +pub fn used_binding_value<T: Default>() { + let _: T = Default::default(); +} + +// Function uses generic parameter in generic of a binding. +#[rustc_polymorphize_error] +pub fn used_binding_generic<T>() { + let _: Option<T> = None; +} + +// Function uses generic parameter in argument. +#[rustc_polymorphize_error] +pub fn used_argument<T>(_: T) {} + +// Function uses generic parameter in substitutions to another function. +#[rustc_polymorphize_error] +pub fn used_substs<T>() { + unused::<T>() +} + +struct Foo<F>(F); + +impl<F: Default> Foo<F> { + // Function has an unused generic parameter from impl. + #[rustc_polymorphize_error] + pub fn unused_impl() { + //~^ ERROR item has unused generic parameters + } + + // Function has an unused generic parameter from impl and fn. + #[rustc_polymorphize_error] + pub fn unused_both<G: Default>() { + //~^ ERROR item has unused generic parameters + } + + // Function uses generic parameter from impl. + #[rustc_polymorphize_error] + pub fn used_impl() { + let _: F = Default::default(); + } + + // Function uses generic parameter from impl. + #[rustc_polymorphize_error] + pub fn used_fn<G: Default>() { + //~^ ERROR item has unused generic parameters + let _: G = Default::default(); + } + + // Function uses generic parameter from impl. + #[rustc_polymorphize_error] + pub fn used_both<G: Default>() { + let _: F = Default::default(); + let _: G = Default::default(); + } + + // Function uses generic parameter in substitutions to another function. + #[rustc_polymorphize_error] + pub fn used_substs() { + unused::<F>() + } +} + +fn main() { + no_parameters(); + unused::<u32>(); + used_binding_value::<u32>(); + used_binding_generic::<u32>(); + used_argument(3u32); + used_substs::<u32>(); + + Foo::<u32>::unused_impl(); + Foo::<u32>::unused_both::<u32>(); + Foo::<u32>::used_impl(); + Foo::<u32>::used_fn::<u32>(); + Foo::<u32>::used_both::<u32>(); + Foo::<u32>::used_substs(); +} diff --git a/src/test/ui/polymorphization/type_parameters/functions.stderr b/src/test/ui/polymorphization/type_parameters/functions.stderr new file mode 100644 index 0000000000000..be4c6576e9645 --- /dev/null +++ b/src/test/ui/polymorphization/type_parameters/functions.stderr @@ -0,0 +1,35 @@ +error: item has unused generic parameters + --> $DIR/functions.rs:13:8 + | +LL | pub fn unused<T>() { + | ^^^^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/functions.rs:44:12 + | +LL | impl<F: Default> Foo<F> { + | - generic parameter `F` is unused +... +LL | pub fn unused_impl() { + | ^^^^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/functions.rs:50:12 + | +LL | impl<F: Default> Foo<F> { + | - generic parameter `F` is unused +... +LL | pub fn unused_both<G: Default>() { + | ^^^^^^^^^^^ - generic parameter `G` is unused + +error: item has unused generic parameters + --> $DIR/functions.rs:62:12 + | +LL | impl<F: Default> Foo<F> { + | - generic parameter `F` is unused +... +LL | pub fn used_fn<G: Default>() { + | ^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/polymorphization/unsized_cast.rs b/src/test/ui/polymorphization/unsized_cast.rs new file mode 100644 index 0000000000000..d2f3d4f13cdcc --- /dev/null +++ b/src/test/ui/polymorphization/unsized_cast.rs @@ -0,0 +1,28 @@ +// build-fail +#![feature(fn_traits, rustc_attrs, unboxed_closures)] + +// This test checks that the polymorphization analysis considers a closure +// as using all generic parameters if it does an unsizing cast. + +#[rustc_polymorphize_error] +fn foo<T: Default>() { + let _: T = Default::default(); + (|| Box::new(|| {}) as Box<dyn Fn()>)(); + //~^ ERROR item has unused generic parameters + //~^^ ERROR item has unused generic parameters +} + +#[rustc_polymorphize_error] +fn foo2<T: Default>() { + let _: T = Default::default(); + (|| { + let call: extern "rust-call" fn(_, _) = Fn::call; + call(&|| {}, ()); + //~^ ERROR item has unused generic parameters + })(); +} + +fn main() { + foo::<u32>(); + foo2::<u32>(); +} diff --git a/src/test/ui/polymorphization/unsized_cast.stderr b/src/test/ui/polymorphization/unsized_cast.stderr new file mode 100644 index 0000000000000..b8b96bbdf15a6 --- /dev/null +++ b/src/test/ui/polymorphization/unsized_cast.stderr @@ -0,0 +1,29 @@ +error: item has unused generic parameters + --> $DIR/unsized_cast.rs:10:18 + | +LL | fn foo<T: Default>() { + | - generic parameter `T` is unused +LL | let _: T = Default::default(); +LL | (|| Box::new(|| {}) as Box<dyn Fn()>)(); + | ^^^^^ + +error: item has unused generic parameters + --> $DIR/unsized_cast.rs:10:5 + | +LL | fn foo<T: Default>() { + | - generic parameter `T` is unused +LL | let _: T = Default::default(); +LL | (|| Box::new(|| {}) as Box<dyn Fn()>)(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/unsized_cast.rs:20:15 + | +LL | fn foo2<T: Default>() { + | - generic parameter `T` is unused +... +LL | call(&|| {}, ()); + | ^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.rs b/src/test/ui/regions/region-object-lifetime-in-coercion.rs index 5d199149c39b8..9d3f485e31438 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.rs +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.rs @@ -5,18 +5,18 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} fn a(v: &[u8]) -> Box<dyn Foo + 'static> { - let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR cannot infer an appropriate lifetime + let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR E0759 x } fn b(v: &[u8]) -> Box<dyn Foo + 'static> { - Box::new(v) //~ ERROR cannot infer an appropriate lifetime + Box::new(v) //~ ERROR E0759 } fn c(v: &[u8]) -> Box<dyn Foo> { // same as previous case due to RFC 599 - Box::new(v) //~ ERROR cannot infer an appropriate lifetime + Box::new(v) //~ ERROR E0759 } fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 7f5a3a47976c7..63fea1f41626d 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/region-object-lifetime-in-coercion.rs:8:46 | LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> { @@ -15,7 +15,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> { | ^^^^^^^^^^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/region-object-lifetime-in-coercion.rs:13:14 | LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> { @@ -32,7 +32,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> { | ^^^^^^^^^^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/region-object-lifetime-in-coercion.rs:19:14 | LL | fn c(v: &[u8]) -> Box<dyn Foo> { diff --git a/src/test/ui/regions/regions-addr-of-self.rs b/src/test/ui/regions/regions-addr-of-self.rs index 647212407fc8a..4eb1b275f163e 100644 --- a/src/test/ui/regions/regions-addr-of-self.rs +++ b/src/test/ui/regions/regions-addr-of-self.rs @@ -4,7 +4,7 @@ struct Dog { impl Dog { pub fn chase_cat(&mut self) { - let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer + let p: &'static mut usize = &mut self.cats_chased; //~ ERROR E0759 *p += 1; } diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr index a0b8b6b51e5a1..738691fd695eb 100644 --- a/src/test/ui/regions/regions-addr-of-self.stderr +++ b/src/test/ui/regions/regions-addr-of-self.stderr @@ -1,29 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/regions-addr-of-self.rs:7:37 | +LL | pub fn chase_cat(&mut self) { + | --------- this data with an anonymous lifetime `'_`... LL | let p: &'static mut usize = &mut self.cats_chased; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5... - --> $DIR/regions-addr-of-self.rs:6:5 - | -LL | / pub fn chase_cat(&mut self) { -LL | | let p: &'static mut usize = &mut self.cats_chased; -LL | | *p += 1; -LL | | } - | |_____^ -note: ...so that reference does not outlive borrowed content - --> $DIR/regions-addr-of-self.rs:7:37 - | -LL | let p: &'static mut usize = &mut self.cats_chased; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that reference does not outlive borrowed content - --> $DIR/regions-addr-of-self.rs:7:37 - | -LL | let p: &'static mut usize = &mut self.cats_chased; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.rs b/src/test/ui/regions/regions-close-object-into-object-2.rs index 2364ba2728600..7144ab5a24c51 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.rs +++ b/src/test/ui/regions/regions-close-object-into-object-2.rs @@ -7,7 +7,7 @@ trait X { } impl<'a, T> X for B<'a, T> {} fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> { - box B(&*v) as Box<dyn X> //~ ERROR cannot infer + box B(&*v) as Box<dyn X> //~ ERROR E0759 } fn main() { } diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 114e4052aae09..aab7ce993aa3c 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/regions-close-object-into-object-2.rs:10:11 | LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> { diff --git a/src/test/ui/regions/regions-close-object-into-object-4.rs b/src/test/ui/regions/regions-close-object-into-object-4.rs index d531077043686..4c087f264f92b 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.rs +++ b/src/test/ui/regions/regions-close-object-into-object-4.rs @@ -7,7 +7,7 @@ trait X { } impl<'a, T> X for B<'a, T> {} fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { - box B(&*v) as Box<dyn X> //~ ERROR cannot infer + box B(&*v) as Box<dyn X> //~ ERROR E0759 } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 850d81940791f..90f807a41c562 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/regions-close-object-into-object-4.rs:10:11 | LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { diff --git a/src/test/ui/regions/regions-proc-bound-capture.rs b/src/test/ui/regions/regions-proc-bound-capture.rs index 8617c0e9da8f7..55d964ac53405 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.rs +++ b/src/test/ui/regions/regions-proc-bound-capture.rs @@ -6,7 +6,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<dyn FnMut()->(isize) + 'a> { fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime + Box::new(move || { *x }) //~ ERROR E0759 } fn main() { } diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 67eee3bb6e281..e76073f4f6b13 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/regions-proc-bound-capture.rs:9:14 | LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> { diff --git a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs index 64d6ccf340916..9439df266d59b 100644 --- a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs +++ b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs @@ -2,7 +2,7 @@ // being run when compiling with new LLVM pass manager and ThinLTO. // Note: The issue occurred only on non-zero opt-level. // -// min-llvm-version 9.0 +// min-llvm-version: 9.0 // needs-sanitizer-support // needs-sanitizer-address // diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs index 0afe631f1e3fc..43998ca8c5784 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs @@ -6,7 +6,7 @@ struct Foo; impl Foo { async fn f(self: Pin<&Self>) -> impl Clone { self } - //~^ ERROR cannot infer an appropriate lifetime + //~^ ERROR E0759 } fn main() { diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index f2fbb0ba7d755..9cd0fd328ffa0 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs index 5054568b18970..04935fc52ab9e 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs @@ -3,7 +3,7 @@ use std::pin::Pin; struct Foo; impl Foo { - fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime + fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR E0759 } fn main() { diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 2e10ab3d3f9b8..cb9d5b56dbc5c 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr new file mode 100644 index 0000000000000..6921926590a69 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr @@ -0,0 +1,37 @@ +error[E0597]: `val` does not live long enough + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:22:9 + | +LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> { + | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` +LL | val.use_self() + | ^^^ borrowed value does not live long enough +LL | } + | - `val` dropped here while still borrowed + | +help: you can add a bound to the opaque type to make it last less than `'static` and match `'a` + | +LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a { + | ^^^^ + +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:44:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:110:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0515, E0597. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs new file mode 100644 index 0000000000000..b2dc16a27e310 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs @@ -0,0 +1,113 @@ +// FIXME: the following cases need to suggest more things to make users reach a working end state. + +mod bav { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Bar {} + + impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> { + fn use_self(&self) -> &() { panic!() } + } + impl Bar for i32 {} + + fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> { + val.use_self() //~ ERROR E0597 + } +} + +mod bap { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Bar {} + + impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> { + fn use_self(&self) -> &() { panic!() } + } + impl Bar for i32 {} + + fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR E0515 + } +} + +// This case in particular requires the user to write all of the bounds we have in `mod bax`. +mod bay { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Bar {} + + impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> { + fn use_self(&self) -> &() { panic!() } + } + impl Bar for i32 {} + + fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () { + val.use_self() //~ ERROR E0772 + } +} + +mod bax { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait<'a> { + fn use_self(&'a self) -> &'a () { panic!() } + } + trait Bar {} + + impl<'a> MyTrait<'a> for Box<dyn ObjectTrait<Assoc = i32> + 'a> { + fn use_self(&'a self) -> &'a () { panic!() } + } + impl Bar for i32 {} + + fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () { + val.use_self() + } +} + +mod baw { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait { + type Assoc: Bar; + } + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Bar {} + + impl<'a> MyTrait for Box<dyn ObjectTrait<Assoc = Box<dyn Bar>>> { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = Box<dyn Bar>>>) -> impl OtherTrait<'a> + 'a{ + val.use_self() //~ ERROR E0515 + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr new file mode 100644 index 0000000000000..00971b41c7ce6 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -0,0 +1,57 @@ +error[E0597]: `val` does not live long enough + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9 + | +LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> { + | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` +LL | val.use_self() + | ^^^ borrowed value does not live long enough +LL | } + | - `val` dropped here while still borrowed + | +help: you can add a bound to the opaque type to make it last less than `'static` and match `'a` + | +LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a { + | ^^^^ + +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + +error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:13 + | +LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () { + | -------------------------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:60:30 + | +LL | impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> { + | ^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0515, E0597. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed new file mode 100644 index 0000000000000..3c10f85d9423a --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.fixed @@ -0,0 +1,112 @@ +// run-rustfix +#![allow(dead_code)] + +mod foo { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait<T> {} + trait MyTrait<T> { + fn use_self<K>(&self) -> &(); + } + trait Irrelevant {} + + impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ { + fn use_self<K>(&self) -> &() { panic!() } + } + impl<T> Irrelevant for dyn ObjectTrait<T> {} + + fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a { + val.use_self::<T>() //~ ERROR E0759 + } +} + +mod bar { + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + trait Irrelevant {} + + impl MyTrait for dyn ObjectTrait + '_ { + fn use_self(&self) -> &() { panic!() } + } + impl Irrelevant for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { + val.use_self() //~ ERROR E0772 + } +} + +mod baz { + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + trait Irrelevant {} + + impl MyTrait for Box<dyn ObjectTrait + '_> { + fn use_self(&self) -> &() { panic!() } + } + impl Irrelevant for Box<dyn ObjectTrait> {} + + fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () { + val.use_self() //~ ERROR E0772 + } +} + +mod bat { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + + impl dyn ObjectTrait + '_ { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR E0772 + } +} + +mod ban { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait + '_ {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR E0759 + } +} + +mod bal { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait + '_ {} + impl Irrelevant for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + MyTrait::use_self(val) //~ ERROR E0759 + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr new file mode 100644 index 0000000000000..697467dc3a630 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr @@ -0,0 +1,42 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9 + | +LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a { + | --- `val` is a reference that is only valid in the function body +LL | val.use_self::<T>() + | ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here + | + = help: consider replacing `'a` with `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | --- `val` is a reference that is only valid in the function body +LL | val.use_self() + | ^^^^^^^^^^^^^^ `val` escapes the function body here + | + = help: consider replacing `'a` with `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { + | --- `val` is a reference that is only valid in the function body +LL | val.use_self() + | ^^^^^^^^^^^^^^ `val` escapes the function body here + | + = help: consider replacing `'a` with `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | --- `val` is a reference that is only valid in the function body +LL | MyTrait::use_self(val) + | ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here + | + = help: consider replacing `'a` with `'static` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs new file mode 100644 index 0000000000000..88ab03dfc1ef1 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.rs @@ -0,0 +1,112 @@ +// run-rustfix +#![allow(dead_code)] + +mod foo { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait<T> {} + trait MyTrait<T> { + fn use_self<K>(&self) -> &(); + } + trait Irrelevant {} + + impl<T> MyTrait<T> for dyn ObjectTrait<T> { + fn use_self<K>(&self) -> &() { panic!() } + } + impl<T> Irrelevant for dyn ObjectTrait<T> {} + + fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a { + val.use_self::<T>() //~ ERROR E0759 + } +} + +mod bar { + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + trait Irrelevant {} + + impl MyTrait for dyn ObjectTrait { + fn use_self(&self) -> &() { panic!() } + } + impl Irrelevant for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { + val.use_self() //~ ERROR E0772 + } +} + +mod baz { + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &(); + } + trait Irrelevant {} + + impl MyTrait for Box<dyn ObjectTrait> { + fn use_self(&self) -> &() { panic!() } + } + impl Irrelevant for Box<dyn ObjectTrait> {} + + fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () { + val.use_self() //~ ERROR E0772 + } +} + +mod bat { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + + impl dyn ObjectTrait { + fn use_self(&self) -> &() { panic!() } + } + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR E0772 + } +} + +mod ban { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { + val.use_self() //~ ERROR E0759 + } +} + +mod bal { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &() { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait {} + impl Irrelevant for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + MyTrait::use_self(val) //~ ERROR E0759 + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr new file mode 100644 index 0000000000000..2fb6c25fd1702 --- /dev/null +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -0,0 +1,134 @@ +error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:13 + | +LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a { + | ---------------------- this data with lifetime `'a`... +LL | val.use_self::<T>() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32 + | +LL | impl<T> MyTrait<T> for dyn ObjectTrait<T> { + | ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +LL | fn use_self<K>(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ { + | ^^^^ + +error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:13 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl` + | +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14 + | +LL | impl dyn ObjectTrait { + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl dyn ObjectTrait + '_ { + | ^^^^ + +error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:13 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { + | ------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:85:26 + | +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +... +LL | impl MyTrait for dyn ObjectTrait {} + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl MyTrait for dyn ObjectTrait + '_ {} + | ^^^^ +help: to declare that the `impl Trait` captures data from argument `val`, you can add an explicit `'a` lifetime bound + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ^^^^ + +error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:27 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | ------------------- this data with lifetime `'a`... +LL | MyTrait::use_self(val) + | ^^^ ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 + | +LL | MyTrait::use_self(val) + | ^^^^^^^^^^^^^^^^^ +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:104:26 + | +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +... +LL | impl MyTrait for dyn ObjectTrait {} + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl MyTrait for dyn ObjectTrait + '_ {} + | ^^^^ + +error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:37:13 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { + | ------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26 + | +LL | impl MyTrait for dyn ObjectTrait { + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl MyTrait for dyn ObjectTrait + '_ { + | ^^^^ + +error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:54:13 + | +LL | fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () { + | ----------------------------- this data with lifetime `'a`... +LL | val.use_self() + | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | +note: the used `impl` has a `'static` requirement + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30 + | +LL | impl MyTrait for Box<dyn ObjectTrait> { + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +LL | fn use_self(&self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s 'static` requirement +help: consider relaxing the implicit `'static` requirement + | +LL | impl MyTrait for Box<dyn ObjectTrait + '_> { + | ^^^^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index d3853445dfdfe..94dd826a15cae 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -16,7 +16,7 @@ fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() where G: Get<T> { - move || { //~ ERROR cannot infer an appropriate lifetime + move || { //~ ERROR `dest` *dest = g.get(); } } diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 9ab060328537b..d7051515f1102 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -6,7 +6,7 @@ LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | | | help: consider introducing lifetime `'a` here: `'a,` -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `dest` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs index f78edb1c83a4c..d8446e58dbb63 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs @@ -27,7 +27,7 @@ impl Bar { fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> { Iter { current: None, - remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + remaining: self.0.iter(), //~ ERROR E0759 } } } @@ -38,7 +38,7 @@ impl Baz { fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ { Iter { current: None, - remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + remaining: self.0.iter(), //~ ERROR E0759 } } } @@ -49,7 +49,7 @@ impl Bat { fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a { Iter { current: None, - remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + remaining: self.0.iter(), //~ ERROR E0759 } } } @@ -60,7 +60,7 @@ impl Ban { fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> { Iter { current: None, - remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + remaining: self.0.iter(), //~ ERROR E0759 } } } diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr index 1257e9b172cf7..9f30787f07cc6 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/trait-object-nested-in-impl-trait.rs:30:31 | LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> { @@ -23,7 +23,7 @@ help: to declare that the trait object captures data from argument `self`, you c LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/trait-object-nested-in-impl-trait.rs:41:31 | LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ { @@ -44,7 +44,7 @@ help: to declare that the trait object captures data from argument `self`, you c LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/trait-object-nested-in-impl-trait.rs:52:31 | LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a { @@ -65,7 +65,7 @@ help: to declare that the trait object captures data from argument `self`, you c LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a { | ^^^^ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement --> $DIR/trait-object-nested-in-impl-trait.rs:63:31 | LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> { diff --git a/src/test/ui/traits/issue-72410.rs b/src/test/ui/traits/issue-72410.rs new file mode 100644 index 0000000000000..c95f1dfdca53a --- /dev/null +++ b/src/test/ui/traits/issue-72410.rs @@ -0,0 +1,18 @@ +// Regression test for #72410, this should be used with debug assertion enabled. + +// should be fine +pub trait Foo { + fn map() + where + Self: Sized, + for<'a> &'a mut [u8]: ; +} + +// should fail +pub trait Bar { + fn map() + where for<'a> &'a mut [dyn Bar]: ; + //~^ ERROR: the trait `Bar` cannot be made into an object +} + +fn main() {} diff --git a/src/test/ui/traits/issue-72410.stderr b/src/test/ui/traits/issue-72410.stderr new file mode 100644 index 0000000000000..1db2320841ff7 --- /dev/null +++ b/src/test/ui/traits/issue-72410.stderr @@ -0,0 +1,18 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/issue-72410.rs:14:19 + | +LL | pub trait Bar { + | --- this trait cannot be made into an object... +LL | fn map() + | --- ...because associated function `map` has no `self` parameter +LL | where for<'a> &'a mut [dyn Bar]: ; + | ^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object + | +help: consider turning `map` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects + | +LL | where for<'a> &'a mut [dyn Bar]:, Self: Sized ; + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs index d5aa18eb0f4e7..e951adf030f5c 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs @@ -5,7 +5,7 @@ fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` - Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime + Box::new(items.iter()) //~ ERROR E0759 } fn b<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index dda5de431d309..dd804864dab4f 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,4 +1,4 @@ -error[E0759]: cannot infer an appropriate lifetime +error[E0759]: `items` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/dyn-trait-underscore.rs:8:20 | LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.rs b/src/test/ui/wf/wf-foreign-fn-decl-ret.rs new file mode 100644 index 0000000000000..b9d956c056869 --- /dev/null +++ b/src/test/ui/wf/wf-foreign-fn-decl-ret.rs @@ -0,0 +1,18 @@ +pub trait Unsatisfied {} + +#[repr(transparent)] +pub struct Bar<T: Unsatisfied>(T); + +pub trait Foo { + type Assoc; +} + +extern "C" { + pub fn lint_me() -> <() as Foo>::Assoc; + //~^ ERROR: the trait bound `(): Foo` is not satisfied [E0277] + + pub fn lint_me_aswell() -> Bar<u32>; + //~^ ERROR: the trait bound `u32: Unsatisfied` is not satisfied [E0277] +} + +fn main() {} diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr new file mode 100644 index 0000000000000..9081b7929d935 --- /dev/null +++ b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/wf-foreign-fn-decl-ret.rs:11:5 + | +LL | pub fn lint_me() -> <() as Foo>::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` + +error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied + --> $DIR/wf-foreign-fn-decl-ret.rs:14:32 + | +LL | pub struct Bar<T: Unsatisfied>(T); + | ----------- required by this bound in `Bar` +... +LL | pub fn lint_me_aswell() -> Bar<u32>; + | ^^^^^^^^ the trait `Unsatisfied` is not implemented for `u32` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 4b163fba52890..a4bee1c278059 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1346,7 +1346,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { .predicates .iter() .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); - !traits::normalize_and_test_predicates( + traits::impossible_predicates( cx.tcx, traits::elaborate_predicates(cx.tcx, predicates) .map(|o| o.predicate) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5f7373be65946..9269a63b41aab 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -271,13 +271,13 @@ pub struct Config { pub gdb_native_rust: bool, /// Version of LLDB - pub lldb_version: Option<String>, + pub lldb_version: Option<u32>, /// Whether LLDB has native rust support pub lldb_native_rust: bool, /// Version of LLVM - pub llvm_version: Option<String>, + pub llvm_version: Option<u32>, /// Is LLVM a system LLVM pub system_llvm: bool, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index d6e28e93c9667..2ab764eb9207c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -132,72 +132,46 @@ impl EarlyProps { fn ignore_gdb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.gdb_version { - if line.starts_with("min-gdb-version") { - let (start_ver, end_ver) = extract_gdb_version_range(line); + if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { + let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version) + .unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", rest); + }); if start_ver != end_ver { panic!("Expected single GDB version") } // Ignore if actual version is smaller the minimum required // version - actual_version < start_ver - } else if line.starts_with("ignore-gdb-version") { - let (min_version, max_version) = extract_gdb_version_range(line); + return actual_version < start_ver; + } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { + let (min_version, max_version) = + extract_version_range(rest, extract_gdb_version).unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", rest); + }); if max_version < min_version { panic!("Malformed GDB version range: max < min") } - actual_version >= min_version && actual_version <= max_version - } else { - false - } - } else { - false - } - } - - // Takes a directive of the form "ignore-gdb-version <version1> [- <version2>]", - // returns the numeric representation of <version1> and <version2> as - // tuple: (<version1> as u32, <version2> as u32) - // If the <version2> part is omitted, the second component of the tuple - // is the same as <version1>. - fn extract_gdb_version_range(line: &str) -> (u32, u32) { - const ERROR_MESSAGE: &'static str = "Malformed GDB version directive"; - - let range_components = line - .split(&[' ', '-'][..]) - .filter(|word| !word.is_empty()) - .map(extract_gdb_version) - .skip_while(Option::is_none) - .take(3) // 3 or more = invalid, so take at most 3. - .collect::<Vec<Option<u32>>>(); - - match range_components.len() { - 1 => { - let v = range_components[0].unwrap(); - (v, v) - } - 2 => { - let v_min = range_components[0].unwrap(); - let v_max = range_components[1].expect(ERROR_MESSAGE); - (v_min, v_max) + return actual_version >= min_version && actual_version <= max_version; } - _ => panic!(ERROR_MESSAGE), } + false } fn ignore_lldb(config: &Config, line: &str) -> bool { - if let Some(ref actual_version) = config.lldb_version { - if line.starts_with("min-lldb-version") { - let min_version = line - .trim_end() - .rsplit(' ') - .next() - .expect("Malformed lldb version directive"); + if let Some(actual_version) = config.lldb_version { + if let Some(min_version) = line.strip_prefix("min-lldb-version:").map(str::trim) { + let min_version = min_version.parse().unwrap_or_else(|e| { + panic!( + "Unexpected format of LLDB version string: {}\n{:?}", + min_version, e + ); + }); // Ignore if actual version is smaller the minimum required // version - lldb_version_to_int(actual_version) < lldb_version_to_int(min_version) + actual_version < min_version } else if line.starts_with("rust-lldb") && !config.lldb_native_rust { true } else { @@ -212,48 +186,31 @@ impl EarlyProps { if config.system_llvm && line.starts_with("no-system-llvm") { return true; } - if let Some(ref actual_version) = config.llvm_version { - let actual_version = version_to_int(actual_version); - if line.starts_with("min-llvm-version") { - let min_version = line - .trim_end() - .rsplit(' ') - .next() - .expect("Malformed llvm version directive"); + if let Some(actual_version) = config.llvm_version { + if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) { + let min_version = extract_llvm_version(rest).unwrap(); // Ignore if actual version is smaller the minimum required // version - actual_version < version_to_int(min_version) - } else if line.starts_with("min-system-llvm-version") { - let min_version = line - .trim_end() - .rsplit(' ') - .next() - .expect("Malformed llvm version directive"); + actual_version < min_version + } else if let Some(rest) = + line.strip_prefix("min-system-llvm-version:").map(str::trim) + { + let min_version = extract_llvm_version(rest).unwrap(); // Ignore if using system LLVM and actual version // is smaller the minimum required version - config.system_llvm && actual_version < version_to_int(min_version) - } else if line.starts_with("ignore-llvm-version") { - // Syntax is: "ignore-llvm-version <version1> [- <version2>]" - let range_components = line - .split(' ') - .skip(1) // Skip the directive. - .map(|s| s.trim()) - .filter(|word| !word.is_empty() && word != &"-") - .take(3) // 3 or more = invalid, so take at most 3. - .collect::<Vec<&str>>(); - match range_components.len() { - 1 => actual_version == version_to_int(range_components[0]), - 2 => { - let v_min = version_to_int(range_components[0]); - let v_max = version_to_int(range_components[1]); - if v_max < v_min { - panic!("Malformed LLVM version range: max < min") - } - // Ignore if version lies inside of range. - actual_version >= v_min && actual_version <= v_max - } - _ => panic!("Malformed LLVM version directive"), + config.system_llvm && actual_version < min_version + } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim) + { + // Syntax is: "ignore-llvm-version: <version1> [- <version2>]" + let (v_min, v_max) = extract_version_range(rest, extract_llvm_version) + .unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", rest); + }); + if v_max < v_min { + panic!("Malformed LLVM version range: max < min") } + // Ignore if version lies inside of range. + actual_version >= v_min && actual_version <= v_max } else { false } @@ -261,20 +218,6 @@ impl EarlyProps { false } } - - fn version_to_int(version: &str) -> u32 { - let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap(); - let components: Vec<u32> = version_without_suffix - .split('.') - .map(|s| s.parse().expect("Malformed version component")) - .collect(); - match components.len() { - 1 => components[0] * 10000, - 2 => components[0] * 10000 + components[1] * 100, - 3 => components[0] * 10000 + components[1] * 100 + components[2], - _ => panic!("Malformed version"), - } - } } } @@ -944,12 +887,6 @@ impl Config { } } -pub fn lldb_version_to_int(version_string: &str) -> isize { - let error_string = - format!("Encountered LLDB version string with unexpected format: {}", version_string); - version_string.parse().expect(&error_string) -} - fn expand_variables(mut value: String, config: &Config) -> String { const CWD: &'static str = "{{cwd}}"; const SRC_BASE: &'static str = "{{src-base}}"; @@ -990,3 +927,49 @@ fn parse_normalization_string(line: &mut &str) -> Option<String> { *line = &line[end + 1..]; Some(result) } + +pub fn extract_llvm_version(version: &str) -> Option<u32> { + let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap(); + let components: Vec<u32> = version_without_suffix + .split('.') + .map(|s| s.parse().expect("Malformed version component")) + .collect(); + let version = match *components { + [a] => a * 10_000, + [a, b] => a * 10_000 + b * 100, + [a, b, c] => a * 10_000 + b * 100 + c, + _ => panic!("Malformed version"), + }; + Some(version) +} + +// Takes a directive of the form "<version1> [- <version2>]", +// returns the numeric representation of <version1> and <version2> as +// tuple: (<version1> as u32, <version2> as u32) +// If the <version2> part is omitted, the second component of the tuple +// is the same as <version1>. +fn extract_version_range<F>(line: &str, parse: F) -> Option<(u32, u32)> +where + F: Fn(&str) -> Option<u32>, +{ + let mut splits = line.splitn(2, "- ").map(str::trim); + let min = splits.next().unwrap(); + if min.ends_with('-') { + return None; + } + + let max = splits.next(); + + if min.is_empty() { + return None; + } + + let min = parse(min)?; + let max = match max { + Some(max) if max.is_empty() => return None, + Some(max) => parse(max)?, + _ => min, + }; + + Some((min, max)) +} diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 72af34d78260b..1f82b137ee6cf 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -119,17 +119,17 @@ fn no_system_llvm() { fn llvm_version() { let mut config = config(); - config.llvm_version = Some("8.1.2-rust".to_owned()); - assert!(parse_rs(&config, "// min-llvm-version 9.0").ignore); + config.llvm_version = Some(80102); + assert!(parse_rs(&config, "// min-llvm-version: 9.0").ignore); - config.llvm_version = Some("9.0.1-rust-1.43.0-dev".to_owned()); - assert!(parse_rs(&config, "// min-llvm-version 9.2").ignore); + config.llvm_version = Some(90001); + assert!(parse_rs(&config, "// min-llvm-version: 9.2").ignore); - config.llvm_version = Some("9.3.1-rust-1.43.0-dev".to_owned()); - assert!(!parse_rs(&config, "// min-llvm-version 9.2").ignore); + config.llvm_version = Some(90301); + assert!(!parse_rs(&config, "// min-llvm-version: 9.2").ignore); - config.llvm_version = Some("10.0.0-rust".to_owned()); - assert!(!parse_rs(&config, "// min-llvm-version 9.0").ignore); + config.llvm_version = Some(100000); + assert!(!parse_rs(&config, "// min-llvm-version: 9.0").ignore); } #[test] @@ -220,3 +220,18 @@ fn sanitizers() { assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore); assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore); } + +#[test] +fn test_extract_version_range() { + use super::{extract_llvm_version, extract_version_range}; + + assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506))); + assert_eq!(extract_version_range("0 - 4.5.6", extract_llvm_version), Some((0, 40506))); + assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None); + assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None); + assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None); + assert_eq!(extract_version_range("-", extract_llvm_version), None); + assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); + assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); + assert_eq!(extract_version_range("0 -", extract_llvm_version), None); +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 07eba22c6eeb3..bf3510ea0894b 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -166,14 +166,20 @@ pub fn parse_config(args: Vec<String>) -> Config { let cdb = analyze_cdb(matches.opt_str("cdb"), &target); let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); - let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version")); - - let color = match matches.opt_str("color").as_ref().map(|x| &**x) { + let (lldb_version, lldb_native_rust) = matches + .opt_str("lldb-version") + .as_deref() + .and_then(extract_lldb_version) + .map(|(v, b)| (Some(v), b)) + .unwrap_or((None, false)); + let color = match matches.opt_str("color").as_deref() { Some("auto") | None => ColorConfig::AutoColor, Some("always") => ColorConfig::AlwaysColor, Some("never") => ColorConfig::NeverColor, Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; + let llvm_version = + matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version); let src_base = opt_path(matches, "src-base"); let run_ignored = matches.opt_present("ignored"); @@ -215,7 +221,7 @@ pub fn parse_config(args: Vec<String>) -> Config { gdb_native_rust, lldb_version, lldb_native_rust, - llvm_version: matches.opt_str("llvm-version"), + llvm_version, system_llvm: matches.opt_present("system-llvm"), android_cross_path, adb_path: opt_str2(matches.opt_str("adb-path")), @@ -254,7 +260,7 @@ pub fn log_config(config: &Config) { logv(c, format!("stage_id: {}", config.stage_id)); logv(c, format!("mode: {}", config.mode)); logv(c, format!("run_ignored: {}", config.run_ignored)); - logv(c, format!("filter: {}", opt_str(&config.filter.as_ref().map(|re| re.to_owned())))); + logv(c, format!("filter: {}", opt_str(&config.filter))); logv(c, format!("filter_exact: {}", config.filter_exact)); logv( c, @@ -403,17 +409,14 @@ fn configure_lldb(config: &Config) -> Option<Config> { return None; } - if let Some(lldb_version) = config.lldb_version.as_ref() { - if lldb_version == "350" { - println!( - "WARNING: The used version of LLDB ({}) has a \ - known issue that breaks debuginfo tests. See \ - issue #32520 for more information. Skipping all \ - LLDB-based tests!", - lldb_version - ); - return None; - } + if let Some(350) = config.lldb_version { + println!( + "WARNING: The used version of LLDB (350) has a \ + known issue that breaks debuginfo tests. See \ + issue #32520 for more information. Skipping all \ + LLDB-based tests!", + ); + return None; } // Some older versions of LLDB seem to have problems with multiple @@ -727,9 +730,7 @@ fn make_test_closure( let config = config.clone(); let testpaths = testpaths.clone(); let revision = revision.cloned(); - test::DynTestFn(Box::new(move || { - runtest::run(config, &testpaths, revision.as_ref().map(|s| s.as_str())) - })) + test::DynTestFn(Box::new(move || runtest::run(config, &testpaths, revision.as_deref()))) } /// Returns `true` if the given target is an Android target for the @@ -845,75 +846,40 @@ fn extract_gdb_version(full_version_line: &str) -> Option<u32> { // This particular form is documented in the GNU coding standards: // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion - // don't start parsing in the middle of a number - let mut prev_was_digit = false; - let mut in_parens = false; - for (pos, c) in full_version_line.char_indices() { - if in_parens { - if c == ')' { - in_parens = false; - } - continue; - } else if c == '(' { - in_parens = true; - continue; - } - - if prev_was_digit || !c.is_digit(10) { - prev_was_digit = c.is_digit(10); - continue; + let mut splits = full_version_line.rsplit(' '); + let version_string = splits.next().unwrap(); + + let mut splits = version_string.split('.'); + let major = splits.next().unwrap(); + let minor = splits.next().unwrap(); + let patch = splits.next(); + + let major: u32 = major.parse().unwrap(); + let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { + None => { + let minor = minor.parse().unwrap(); + let patch: u32 = match patch { + Some(patch) => match patch.find(not_a_digit) { + None => patch.parse().unwrap(), + Some(idx) if idx > 3 => 0, + Some(idx) => patch[..idx].parse().unwrap(), + }, + None => 0, + }; + (minor, patch) } - - prev_was_digit = true; - - let line = &full_version_line[pos..]; - - let next_split = match line.find(|c: char| !c.is_digit(10)) { - Some(idx) => idx, - None => continue, // no minor version - }; - - if line.as_bytes()[next_split] != b'.' { - continue; // no minor version + // There is no patch version after minor-date (e.g. "4-2012"). + Some(idx) => { + let minor = minor[..idx].parse().unwrap(); + (minor, 0) } + }; - let major = &line[..next_split]; - let line = &line[next_split + 1..]; - - let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) { - Some(idx) => { - if line.as_bytes()[idx] == b'.' { - let patch = &line[idx + 1..]; - - let patch_len = - patch.find(|c: char| !c.is_digit(10)).unwrap_or_else(|| patch.len()); - let patch = &patch[..patch_len]; - let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) }; - - (&line[..idx], patch) - } else { - (&line[..idx], None) - } - } - None => (line, None), - }; - - if minor.is_empty() { - continue; - } - - let major: u32 = major.parse().unwrap(); - let minor: u32 = minor.parse().unwrap(); - let patch: u32 = patch.unwrap_or("0").parse().unwrap(); - - return Some(((major * 1000) + minor) * 1000 + patch); - } - - None + Some(((major * 1000) + minor) * 1000 + patch) } /// Returns (LLDB version, LLDB is rust-enabled) -fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, bool) { +fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { // Extract the major LLDB version from the given version string. // LLDB version strings are different for Apple and non-Apple platforms. // The Apple variant looks like this: @@ -922,7 +888,7 @@ fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, b // lldb-300.2.51 (new versions) // // We are only interested in the major version number, so this function - // will return `Some("179")` and `Some("300")` respectively. + // will return `Some(179)` and `Some(300)` respectively. // // Upstream versions look like: // lldb version 6.0.1 @@ -934,53 +900,24 @@ fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, b // normally fine because the only non-Apple version we test is // rust-enabled. - if let Some(ref full_version_line) = full_version_line { - if !full_version_line.trim().is_empty() { - let full_version_line = full_version_line.trim(); - - for (pos, l) in full_version_line.char_indices() { - if l != 'l' && l != 'L' { - continue; - } - if pos + 5 >= full_version_line.len() { - continue; - } - let l = full_version_line[pos + 1..].chars().next().unwrap(); - if l != 'l' && l != 'L' { - continue; - } - let d = full_version_line[pos + 2..].chars().next().unwrap(); - if d != 'd' && d != 'D' { - continue; - } - let b = full_version_line[pos + 3..].chars().next().unwrap(); - if b != 'b' && b != 'B' { - continue; - } - let dash = full_version_line[pos + 4..].chars().next().unwrap(); - if dash != '-' { - continue; - } - - let vers = full_version_line[pos + 5..] - .chars() - .take_while(|c| c.is_digit(10)) - .collect::<String>(); - if !vers.is_empty() { - return (Some(vers), full_version_line.contains("rust-enabled")); - } - } + let full_version_line = full_version_line.trim(); - if full_version_line.starts_with("lldb version ") { - let vers = full_version_line[13..] - .chars() - .take_while(|c| c.is_digit(10)) - .collect::<String>(); - if !vers.is_empty() { - return (Some(vers + "00"), full_version_line.contains("rust-enabled")); - } - } + if let Some(apple_ver) = + full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) + { + if let Some(idx) = apple_ver.find(not_a_digit) { + let version: u32 = apple_ver[..idx].parse().unwrap(); + return Some((version, full_version_line.contains("rust-enabled"))); + } + } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { + if let Some(idx) = lldb_ver.find(not_a_digit) { + let version: u32 = lldb_ver[..idx].parse().unwrap(); + return Some((version * 100, full_version_line.contains("rust-enabled"))); } } - (None, false) + None +} + +fn not_a_digit(c: char) -> bool { + !c.is_digit(10) } diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 31c151d29e916..ea9bc1c1a5b7f 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,8 +1,9 @@ +use super::header::extract_llvm_version; use super::*; #[test] fn test_extract_gdb_version() { - macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$( + macro_rules! test { ($($expectation:literal: $input:literal,)*) => {{$( assert_eq!(extract_gdb_version($input), Some($expectation)); )*}}} @@ -41,6 +42,17 @@ fn test_extract_gdb_version() { } } +#[test] +fn test_extract_lldb_version() { + // Apple variants + assert_eq!(extract_lldb_version("LLDB-179.5"), Some((179, false))); + assert_eq!(extract_lldb_version("lldb-300.2.51"), Some((300, false))); + + // Upstream versions + assert_eq!(extract_lldb_version("lldb version 6.0.1"), Some((600, false))); + assert_eq!(extract_lldb_version("lldb version 9.0.0"), Some((900, false))); +} + #[test] fn is_test_test() { assert_eq!(true, is_test(&OsString::from("a_test.rs"))); @@ -49,3 +61,11 @@ fn is_test_test() { assert_eq!(false, is_test(&OsString::from("#a_dog_gif"))); assert_eq!(false, is_test(&OsString::from("~a_temp_file"))); } + +#[test] +fn test_extract_llvm_version() { + assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102)); + assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001)); + assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301)); + assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000)); +} diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 8b0983e89ad9a..c9c518e5e9761 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 8b0983e89ad9a28b142eccf3755a8c9aaeb37852 +Subproject commit c9c518e5e9761bf35d466c47c57c3a1358b56b3c diff --git a/triagebot.toml b/triagebot.toml index 51a29553fdb3d..ce4ea895400ac 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -81,7 +81,7 @@ topic = "I-prioritize #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* issue #{number} has been requested for prioritization. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#Unprioritized-I-prioritize) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#assign-priority-to-unprioritized-issues-with-i-prioritize-label) - Priority? - Regression? - Notify people/groups? @@ -96,7 +96,7 @@ topic = "I-nominated #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#I-nominated) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-i-nominated-issues) - Already discussed? - Worth the meeting time? - Add agenda entry: @@ -113,7 +113,7 @@ topic = "Backport #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* PR #{number} has been requested for beta backport. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations) Prepare agenda entry: - Why nominated? - Author, assignee? @@ -127,7 +127,7 @@ topic = "Backport #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* PR #{number} has been requested for stable backport. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations) Prepare agenda entry: - Why nominated? - Author, assignee? @@ -142,7 +142,7 @@ topic = "S-waiting-on-team #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#PR%E2%80%99s-waiting-on-team) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-prs-waiting-on-team) - Prepare agenda entry: - What is it waiting for? - Important details? @@ -156,7 +156,7 @@ topic = "P-critical #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions) - Notify people/groups? - Assign if possible? - Add to agenda: @@ -172,7 +172,7 @@ topic = "P-high regression #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression. -# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions) +# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions) Is issue assigned? If not: - Try to find an assignee? - Otherwise add to agenda: