diff --git a/.editorconfig b/.editorconfig index eadd72e499373..ef8ed24c52a50 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,6 +9,8 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true + +[!src/llvm-project] indent_style = space indent_size = 4 diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 8612a40923a8d..af071c706856e 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -29,3 +29,7 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8 99cb0c6bc399fb94a0ddde7e9b38e9c00d523bad # reformat with rustfmt edition 2024 c682aa162b0d41e21cc6748f4fecfe01efb69d1f +# reformat with updated edition 2024 +1fcae03369abb4c2cc180cd5a49e1f4440a81300 +# Breaking up of compiletest runtest.rs +60600a6fa403216bfd66e04f948b1822f6450af7 diff --git a/.gitattributes b/.gitattributes index d29c15fe712f3..8700d5d6dcff1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,6 +5,7 @@ *.h rust *.rs rust diff=rust *.fixed linguist-language=Rust +*.pp linguist-language=Rust *.mir linguist-language=Rust src/etc/installer/gfx/* binary src/vendor/** -text diff --git a/.github/ISSUE_TEMPLATE/bootstrap.md b/.github/ISSUE_TEMPLATE/bootstrap.md new file mode 100644 index 0000000000000..344ea30e1fc0b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bootstrap.md @@ -0,0 +1,70 @@ +--- +name: Bootstrap (Rust Build System) Report +about: Issues encountered on bootstrap build system +labels: C-bug, T-bootstrap +--- + +<!-- +Thank you for submitting a bootstrap report! Please provide detailed information to help us reproduce and diagnose the issue. +--> + +### Summary + +<!-- +Provide a brief description of the problem you are experiencing. +--> + +### Command used + +```sh +<command> +``` + +### Expected behaviour + +<!-- +Describe what you expected to happen. +--> + +### Actual behaviour + +<!-- +Describe what actually happened. +--> + +### Bootstrap configuration (bootstrap.toml) +```toml +<config> +``` + +### Operating system + +<!-- +e.g., Ubuntu 22.04, macOS 12, Windows 10 +--> + +### HEAD + +<!-- +Output of `git rev-parse HEAD` command, or content of the `git-commit-hash` file if using a tarball source. +--> + +### Additional context +<!-- +Include any other relevant information (e.g., if you have custom patches or modifications on the project). +--> + + +<!-- +Include the complete build log in the section below. +Enable backtrace and verbose mode if possible for more detailed information e.g., with `RUST_BACKTRACE=1 ./x build -v`. +--> +<details><summary>Build Log</summary> +<p> + +```txt +<log> +``` + +</p> +</details> diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md index 934312662beb6..d56da9d5d025a 100644 --- a/.github/ISSUE_TEMPLATE/library_tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md @@ -2,7 +2,7 @@ name: Library Tracking Issue about: A tracking issue for an unstable library feature. title: Tracking Issue for XXX -labels: C-tracking-issue, T-libs-api +labels: C-tracking-issue, T-libs-api, S-tracking-unimplemented --- <!-- Thank you for creating a tracking issue! @@ -49,6 +49,8 @@ For larger features, more steps might be involved. If the feature is changed later, please add those PRs here as well. --> +(Remember to update the `S-tracking-*` label when checking boxes.) + - [ ] Implementation: #... - [ ] Final comment period (FCP)[^1] - [ ] Stabilization PR diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md index 598628936112e..aedc15a54c274 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -41,12 +41,15 @@ for larger features an implementation could be broken up into multiple PRs. - [ ] Implement the RFC (cc @rust-lang/XXX -- can anyone write up mentoring instructions?) - [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide]) -- [ ] Formatting for new syntax has been added to the [Style Guide] ([nightly-style-procedure]) +- [ ] Style updates for any new syntax ([nightly-style-procedure]) + - [ ] Style team decision on new formatting + - [ ] Formatting for new syntax has been added to the [Style Guide] + - [ ] (non-blocking) Formatting has been implemented in `rustfmt` - [ ] Stabilization PR ([see instructions on rustc-dev-guide][stabilization-guide]) [stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr [doc-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#documentation-prs -[nightly-style-procedure]: https://github.com/rust-lang/style-team/blob/master/nightly-style-procedure.md +[nightly-style-procedure]: https://github.com/rust-lang/style-team/blob/main/nightly-style-procedure.md [Style Guide]: https://github.com/rust-lang/rust/tree/master/src/doc/style-guide ### Unresolved Questions diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ecf8f993f90b0..93388ddd24075 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -7,6 +7,6 @@ tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using - r\? <reviewer name> (with the `\` removed) + r? <reviewer name> --> <!-- homu-ignore:end --> diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 0000000000000..87f5f103ddfca --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,14 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + // Let Renovatebot keep an opened issue that tracks our dependencies + "dependencyDashboard": true, + // Disable "normal" package updates + "enabledManagers": [], + // Update lockfiles once per week + "lockFileMaintenance": { + "enabled": true, + "schedule": [ + "before 5am on Tuesday" + ] + } +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 003c1e5d7ebbe..2e83bbf643fee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,8 @@ # This file defines our primary CI workflow that runs on pull requests # and also on pushes to special branches (auto, try). # -# The actual definition of the executed jobs is calculated by a Python -# script located at src/ci/github-actions/calculate-job-matrix.py, which +# The actual definition of the executed jobs is calculated by the +# `src/ci/citool` crate, which # uses job definition data from src/ci/github-actions/jobs.yml. # You should primarily modify the `jobs.yml` file if you want to modify # what jobs are executed in CI. @@ -46,33 +46,44 @@ jobs: # If you want to modify CI jobs, take a look at src/ci/github-actions/jobs.yml. calculate_matrix: name: Calculate job matrix - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: jobs: ${{ steps.jobs.outputs.jobs }} run_type: ${{ steps.jobs.outputs.run_type }} steps: - name: Checkout the source code uses: actions/checkout@v4 + # Cache citool to make its build faster, as it's in the critical path. + # The rust-cache doesn't bleed into the main `job`, so it should not affect any other + # Rust compilation. + - name: Cache citool + uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 + with: + workspaces: src/ci/citool - name: Calculate the CI job matrix env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - run: python3 src/ci/github-actions/calculate-job-matrix.py >> $GITHUB_OUTPUT + run: | + cd src/ci/citool + CARGO_INCREMENTAL=0 cargo test + CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT id: jobs job: - name: ${{ matrix.name }} + name: ${{ matrix.full_name }} needs: [ calculate_matrix ] runs-on: "${{ matrix.os }}" - defaults: - run: - shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }} - timeout-minutes: 240 + timeout-minutes: 360 env: - CI_JOB_NAME: ${{ matrix.image }} + CI_JOB_NAME: ${{ matrix.name }} + CI_JOB_DOC_URL: ${{ matrix.doc_url }} + GITHUB_WORKFLOW_RUN_ID: ${{ github.run_id }} + GITHUB_REPOSITORY: ${{ github.repository }} CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs. HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} DOCKER_TOKEN: ${{ secrets.GITHUB_TOKEN }} SCCACHE_BUCKET: rust-lang-ci-sccache2 + SCCACHE_REGION: us-west-1 CACHE_DOMAIN: ci-caches.rust-lang.org continue-on-error: ${{ matrix.continue_on_error || false }} strategy: @@ -80,22 +91,6 @@ jobs: # Check the `calculate_matrix` job to see how is the matrix defined. include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }} steps: - - if: contains(matrix.os, 'windows') - uses: msys2/setup-msys2@v2.22.0 - with: - # i686 jobs use mingw32. x86_64 and cross-compile jobs use mingw64. - msystem: ${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }} - # don't try to download updates for already installed packages - update: false - # don't try to use the msys that comes built-in to the github runner, - # so we can control what is installed (i.e. not python) - release: true - # Inherit the full path from the Windows environment, with MSYS2's */bin/ - # dirs placed in front. This lets us run Windows-native Python etc. - path-type: inherit - install: > - make - - name: disable git crlf conversion run: git config --global core.autocrlf false @@ -104,6 +99,14 @@ jobs: with: fetch-depth: 2 + # Free up disk space on Linux by removing preinstalled components that + # we do not need. We do this to enable some of the less resource + # intensive jobs to run on free runners, which however also have + # less disk space. + - name: free up disk space + run: src/ci/scripts/free-disk-space.sh + if: matrix.free_disk + # 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. @@ -184,9 +187,33 @@ jobs: - name: ensure the stable version number is correct run: src/ci/scripts/verify-stable-version-number.sh + # Show the environment just before we run the build + # This makes it easier to diagnose problems with the above install scripts. + - name: show the current environment + run: src/ci/scripts/dump-environment.sh + + # Pre-build citool before the following step uninstalls rustup + # Build it into the build directory, to avoid modifying sources + - name: build citool + run: | + cd src/ci/citool + CARGO_INCREMENTAL=0 CARGO_TARGET_DIR=../../../build/citool cargo build + - name: run the build - # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. - run: src/ci/scripts/run-build-from-ci.sh 2>&1 + run: | + set +e + # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. + src/ci/scripts/run-build-from-ci.sh 2>&1 + STATUS=$? + set -e + + if [[ "$STATUS" -ne 0 && -n "$CI_JOB_DOC_URL" ]]; then + echo "****************************************************************************" + echo "To find more information about this job, visit the following URL:" + echo "$CI_JOB_DOC_URL" + echo "****************************************************************************" + fi + exit ${STATUS} env: AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} @@ -194,6 +221,11 @@ jobs: - name: create github artifacts run: src/ci/scripts/create-doc-artifacts.sh + - name: print disk usage + run: | + echo "disk usage:" + df -h + - name: upload artifacts to github uses: actions/upload-artifact@v4 with: @@ -215,21 +247,43 @@ jobs: # erroring about invalid credentials instead. if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1' + - name: postprocess metrics into the summary + # This step is not critical, and if some I/O problem happens, we don't want + # to cancel the build. + continue-on-error: true + run: | + if [ -f build/metrics.json ]; then + METRICS=build/metrics.json + elif [ -f obj/build/metrics.json ]; then + METRICS=obj/build/metrics.json + else + echo "No metrics.json found" + exit 0 + fi + + # Get closest bors merge commit + PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1` + + ./build/citool/debug/citool postprocess-metrics \ + --job-name ${CI_JOB_NAME} \ + --parent ${PARENT_COMMIT} \ + ${METRICS} >> ${GITHUB_STEP_SUMMARY} + - name: upload job metrics to DataDog + # This step is not critical, and if some I/O problem happens, we don't want + # to cancel the build. + continue-on-error: true if: needs.calculate_matrix.outputs.run_type != 'pr' env: - DATADOG_SITE: datadoghq.com DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }} - DD_GITHUB_JOB_NAME: ${{ matrix.name }} - run: | - npm install -g @datadog/datadog-ci@^2.x.x - python3 src/ci/scripts/upload-build-metrics.py build/cpu-usage.csv + DD_GITHUB_JOB_NAME: ${{ matrix.full_name }} + run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv # This job isused to tell bors the final status of the build, as there is no practical way to detect # when a workflow is successful listening to webhooks only in our current bors implementation (homu). outcome: name: bors build finished - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [ calculate_matrix, job ] # !cancelled() executes the job regardless of whether the previous jobs passed or failed if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }} diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index b7b5a03bd41f3..98d8c14f7d185 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -27,7 +27,7 @@ jobs: not-waiting-on-bors: if: github.repository_owner == 'rust-lang' name: skip if S-waiting-on-bors - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -47,7 +47,7 @@ jobs: if: github.repository_owner == 'rust-lang' name: update dependencies needs: not-waiting-on-bors - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: checkout the source code uses: actions/checkout@v4 @@ -94,7 +94,7 @@ jobs: if: github.repository_owner == 'rust-lang' name: amend PR needs: update - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: write pull-requests: write diff --git a/.github/workflows/ghcr.yml b/.github/workflows/ghcr.yml new file mode 100644 index 0000000000000..c2c0c11f0083d --- /dev/null +++ b/.github/workflows/ghcr.yml @@ -0,0 +1,75 @@ +# Mirror DockerHub images used by the Rust project to ghcr.io. +# Images are available at https://github.com/orgs/rust-lang/packages. +# +# In some CI jobs, we pull images from ghcr.io instead of Docker Hub because +# Docker Hub has a rate limit, while ghcr.io doesn't. +# Those images are pushed to ghcr.io by this job. +# +# While Docker Hub rate limit *shouldn't* be an issue on GitHub Actions, +# it certainly is for AWS codebuild. +# +# Note that authenticating to DockerHub or other registries isn't possible +# for PR jobs, because forks can't access secrets. +# That's why we use ghcr.io: it has no rate limit and it doesn't require authentication. + +name: GHCR image mirroring + +on: + workflow_dispatch: + schedule: + # Run daily at midnight UTC + - cron: '0 0 * * *' + +jobs: + mirror: + name: DockerHub mirror + runs-on: ubuntu-24.04 + if: github.repository == 'rust-lang/rust' + permissions: + # Needed to write to the ghcr.io registry + packages: write + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Log in to registry + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin + + # Download crane in the current directory. + # We use crane because it copies the docker image for all the architectures available in + # DockerHub for the image. + # Learn more about crane at + # https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md + - name: Download crane + run: | + curl -sL "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_${OS}_${ARCH}.tar.gz" | tar -xzf - + env: + VERSION: v0.20.2 + OS: Linux + ARCH: x86_64 + + - name: Mirror DockerHub + run: | + # List of DockerHub images to mirror to ghcr.io + images=( + # Mirrored because used by the mingw-check-tidy, which doesn't cache Docker images + "ubuntu:22.04" + # Mirrored because used by all linux CI jobs, including mingw-check-tidy + "moby/buildkit:buildx-stable-1" + # Mirrored because used when CI is running inside a Docker container + "alpine:3.4" + # Mirrored because used by dist-x86_64-linux + "centos:7" + ) + + # Mirror each image from DockerHub to ghcr.io + for img in "${images[@]}"; do + echo "Mirroring ${img}..." + # Remove namespace from the image if any. + # E.g. "moby/buildkit:buildx-stable-1" becomes "buildkit:buildx-stable-1" + dest_image=$(echo "${img}" | cut -d'/' -f2-) + ./crane copy \ + "docker.io/${img}" \ + "ghcr.io/${{ github.repository_owner }}/${dest_image}" + done diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml new file mode 100644 index 0000000000000..94553608a2f48 --- /dev/null +++ b/.github/workflows/post-merge.yml @@ -0,0 +1,46 @@ +# Workflow that runs after a merge to master, analyses changes in test executions +# and posts the result to the merged PR. + +name: Post merge analysis + +on: + push: + branches: + - master + +jobs: + analysis: + runs-on: ubuntu-24.04 + if: github.repository == 'rust-lang/rust' + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + # Make sure that we have enough commits to find the parent merge commit. + # Since all merges should be through merge commits, fetching two commits + # should be enough to get the parent bors merge commit. + fetch-depth: 2 + - name: Perform analysis and send PR + env: + GH_TOKEN: ${{ github.token }} + run: | + # Get closest bors merge commit + PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1` + echo "Parent: ${PARENT_COMMIT}" + + # Find PR for the current commit + HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'` + echo "HEAD: ${{ github.sha }} (#${HEAD_PR})" + + cd src/ci/citool + + printf "<details>\n<summary>What is this?</summary>\n" >> output.log + printf "This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.\n" >> output.log + printf "</details>\n\n" >> output.log + + cargo run --release post-merge-report ${PARENT_COMMIT} ${{ github.sha }} >> output.log + + cat output.log + + gh pr comment ${HEAD_PR} -F output.log diff --git a/.gitignore b/.gitignore index b170dca88fa95..a549b6e6e56c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # This file should only ignore things that are generated during a `x.py` build, # generated by common IDEs, and optional files controlled by the user that -# affect the build (such as config.toml). +# affect the build (such as bootstrap.toml). # In particular, things like `mir_dump` should not be listed here; they are only # created during manual debugging and many people like to clean up instead of # having git ignore such leftovers. You can use `.git/info/exclude` to @@ -34,6 +34,7 @@ Session.vim !/tests/run-make/thumb-none-qemu/example/.cargo ## Configuration +/bootstrap.toml /config.toml /Makefile config.mk @@ -46,17 +47,21 @@ no_llvm_build /inst/ /llvm/ /mingw-build/ -build/ -!/compiler/rustc_mir_build/src/build/ +/build /build-rust-analyzer/ /dist/ /unicode-downloads /target /library/target /src/bootstrap/target +/src/ci/citool/target /src/tools/x/target +# Created by `x vendor` +/vendor # Created by default with `src/ci/docker/run.sh` /obj/ +# Created by nix dev shell / .envrc +src/tools/nix-dev-shell/flake.lock ## ICE reports rustc-ice-*.txt @@ -82,17 +87,18 @@ __pycache__/ node_modules package-lock.json package.json +/src/doc/rustc-dev-guide/mermaid.min.js ## Rustdoc GUI tests tests/rustdoc-gui/src/**.lock ## direnv -.envrc -.direnv/ +/.envrc +/.direnv/ ## nix -flake.nix +/flake.nix flake.lock -default.nix +/default.nix # Before adding new lines, see the comment at the top. diff --git a/.gitmodules b/.gitmodules index 33ea0f53cf132..d09d81ccadcb0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,10 +22,6 @@ path = library/stdarch url = https://github.com/rust-lang/stdarch.git shallow = true -[submodule "src/doc/rustc-dev-guide"] - path = src/doc/rustc-dev-guide - url = https://github.com/rust-lang/rustc-dev-guide.git - shallow = true [submodule "src/doc/edition-guide"] path = src/doc/edition-guide url = https://github.com/rust-lang/edition-guide.git @@ -33,7 +29,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/19.1-2024-09-17 + branch = rustc/20.1-2025-02-13 shallow = true [submodule "src/doc/embedded-book"] path = src/doc/embedded-book @@ -49,7 +45,7 @@ shallow = true [submodule "src/tools/enzyme"] path = src/tools/enzyme - url = https://github.com/EnzymeAD/Enzyme.git + url = https://github.com/rust-lang/Enzyme.git shallow = true [submodule "src/gcc"] path = src/gcc diff --git a/.ignore b/.ignore index 40d1513978fc6..b0c640fee3dac 100644 --- a/.ignore +++ b/.ignore @@ -1,2 +1,3 @@ -# Make vscode *not* count `config.toml` as ignored, so it is included in search +# Make vscode *not* count `bootstrap.toml` and `config.toml` as ignored, so it is included in search +!/bootstrap.toml !/config.toml diff --git a/.mailmap b/.mailmap index bdc34c52aa768..c3ce111bfe3b4 100644 --- a/.mailmap +++ b/.mailmap @@ -31,6 +31,7 @@ Alexis Beingessner <a.beingessner@gmail.com> Alfie John <alfie@alfie.wtf> Alfie John <alfiej@fastmail.fm> Alona Enraght-Moony <code@alona.page> <nixon.emoony@gmail.com> Alona Enraght-Moony <code@alona.page> <nixon@caminus.local> +Alona Enraght-Moony <code@alona.page> <contact@alona.page> Amanda Stjerna <mail@amandastjerna.se> <albin.stjerna@gmail.com> Amanda Stjerna <mail@amandastjerna.se> <amanda.stjerna@it.uu.se> Amos Onn <amosonn@gmail.com> @@ -47,6 +48,7 @@ Andrew Poelstra <asp11@sfu.ca> <apoelstra@wpsoftware.net> Anhad Singh <andypythonappdeveloper@gmail.com> Antoine Plaskowski <antoine.plaskowski@epitech.eu> Anton Löfgren <anton.lofgren@gmail.com> <alofgren@op5.com> +apiraino <apiraino@users.noreply.github.com> <apiraino@protonmail.com> Araam Borhanian <avborhanian@gmail.com> Araam Borhanian <avborhanian@gmail.com> <dobbybabee@gmail.com> Areski Belaid <areski@gmail.com> areski <areski@gmail.com> @@ -61,7 +63,10 @@ Austin Seipp <mad.one@gmail.com> <as@hacks.yi.org> Ayaz Hafiz <ayaz.hafiz.1@gmail.com> Aydin Kim <ladinjin@hanmail.net> aydin.kim <aydin.kim@samsung.com> Ayush Mishra <ayushmishra2005@gmail.com> +Ashley Mannix <kodraus@hey.com> <ashleymannix@live.com.au> asrar <aszenz@gmail.com> +b-naber <bn263@gmx.de> +b-naber <bn263@gmx.de> <b_naber@gmx.de> BaoshanPang <pangbw@gmail.com> Barosl Lee <vcs@barosl.com> Barosl LEE <github@barosl.com> Bastian Kersting <bastian@cmbt.de> @@ -75,6 +80,7 @@ Benjamin Jackman <ben@jackman.biz> Benoît Cortier <benoit.cortier@fried-world.eu> Bheesham Persaud <bheesham123@hotmail.com> Bheesham Persaud <bheesham.persaud@live.ca> bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3@users.noreply.github.com> +bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3_gh@protonmail.com> Björn Steinbrink <bsteinbr@gmail.com> <B.Steinbrink@gmx.de> blake2-ppc <ulrik.sverdrup@gmail.com> <blake2-ppc> blyxyas <blyxyas@gmail.com> Alejandra González <blyxyas@gmail.com> @@ -82,7 +88,8 @@ boolean_coercion <booleancoercion@gmail.com> Boris Egorov <jightuse@gmail.com> <egorov@linux.com> bors <bors@rust-lang.org> bors[bot] <26634292+bors[bot]@users.noreply.github.com> bors <bors@rust-lang.org> bors[bot] <bors[bot]@users.noreply.github.com> -Boxy <rust@boxyuwu.dev> <supbscripter@gmail.com> +BoxyUwU <rust@boxyuwu.dev> +BoxyUwU <rust@boxyuwu.dev> <supbscripter@gmail.com> Braden Nelson <moonheart08@users.noreply.github.com> Brandon Sanderson <singingboyo@gmail.com> Brandon Sanderson <singingboyo@hotmail.com> Brett Cannon <brett@python.org> Brett Cannon <brettcannon@users.noreply.github.com> @@ -96,6 +103,8 @@ Caleb Cartwright <caleb.cartwright@outlook.com> Caleb Jones <code@calebjones.net> Noah Lev <camelidcamel@gmail.com> Noah Lev <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com> +Catherine <catherine3.flores@gmail.com> +Catherine <catherine3.flores@gmail.com> <catherine.3.flores@gmail.com> cameron1024 <cameron.studdstreet@gmail.com> Camille Gillot <gillot.camille@gmail.com> Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com> @@ -131,11 +140,13 @@ Clement Miao <clementmiao@gmail.com> Clément Renault <renault.cle@gmail.com> Cliff Dyer <jcd@sdf.org> Clinton Ryan <clint.ryan3@gmail.com> +Taylor Cramer <cramertaylorj@gmail.com> <cramertj@google.com> ember arlynx <ember@lunar.town> <corey@octayn.net> Crazycolorz5 <Crazycolorz5@gmail.com> csmoe <35686186+csmoe@users.noreply.github.com> Cyryl Płotnicki <cyplo@cyplo.net> Damien Schoof <damien.schoof@gmail.com> +Dan Gohman <dev@sunfishcode.online> <sunfish@mozilla.com> Dan Robertson <danlrobertson89@gmail.com> Daniel Campoverde <alx741@riseup.net> Daniel J Rollins <drollins@financialforce.com> @@ -172,20 +183,29 @@ Dzmitry Malyshau <kvarkus@gmail.com> E. Dunham <edunham@mozilla.com> edunham <edunham@mozilla.com> Ed Barnard <eabarnard@gmail.com> Eduard-Mihai Burtescu <edy.burt@gmail.com> +Eduard-Mihai Burtescu <edy.burt@gmail.com> <eddyb@lyken.rs> Eduardo Bautista <me@eduardobautista.com> <=> Eduardo Bautista <me@eduardobautista.com> <mail@eduardobautista.com> Eduardo Broto <ebroto@tutanota.com> Edward Shen <code@eddie.sh> <xes@meta.com> +Jacob Finkelman <eh2406@wayne.edu> +Jacob Finkelman <eh2406@wayne.edu> <YeomanYaacov@gmail.com> +Jacob Finkelman <eh2406@wayne.edu> <jfinkelm@amazon.com> +Jacob Finkelman <eh2406@wayne.edu> <finkelman@semcog.org> +Jacob Finkelman <eh2406@wayne.edu> <Eh2406@users.noreply.github.com> Elliott Slaughter <elliottslaughter@gmail.com> <eslaughter@mozilla.com> Elly Fong-Jones <elly@leptoquark.net> Eric Holk <eric.holk@gmail.com> <eholk@cs.indiana.edu> Eric Holk <eric.holk@gmail.com> <eholk@mozilla.com> +Eric Holk <eric.holk@gmail.com> <eric@theincredibleholk.org> +Eric Holk <eric.holk@gmail.com> <ericholk@microsoft.com> Eric Holmes <eric@ejholmes.net> Eric Reed <ecreed@cs.washington.edu> <ereed@mozilla.com> Erick Tryzelaar <erick.tryzelaar@gmail.com> <etryzelaar@iqt.org> Erik Desjardins <erikdesjardins@users.noreply.github.com> Erik Jensen <erikjensen@rkjnsn.net> Erin Power <xampprocky@gmail.com> +Erin Power <xampprocky@gmail.com> <xampprocky@icloud.com> Erin Power <xampprocky@gmail.com> <theaaronepower@gmail.com> Erin Power <xampprocky@gmail.com> <Aaronepower@users.noreply.github.com> Esteban Küber <esteban@kuber.com.ar> @@ -198,9 +218,11 @@ F001 <changchun.fan@qq.com> Fabian Kössel <fkjogu@users.noreply.github.com> Falco Hirschenberger <falco.hirschenberger@gmail.com> <hirschen@itwm.fhg.de> Felix S. Klock II <pnkfelix@pnkfx.org> Felix S Klock II <pnkfelix@pnkfx.org> +Felix S. Klock II <pnkfelix@pnkfx.org> <pnkfelix@mozilla.com> Félix Saparelli <felix@passcod.name> Flaper Fesp <flaper87@gmail.com> Florian Berger <fbergr@gmail.com> +Florian Gilcher <florian.gilcher@asquera.de> <flo@andersground.net> Florian Wilkens <mrfloya_github@outlook.com> Florian Wilkens <floya@live.de> François Mockers <mockersf@gmail.com> Frank Steffahn <fdsteffahn@gmail.com> <frank.steffahn@stu.uni-kiel.de> @@ -235,6 +257,8 @@ Herman J. Radtke III <herman@hermanradtke.com> Herman J. Radtke III <hermanradtk Hirochika Matsumoto <git@hkmatsumoto.com> <matsujika@gmail.com> Hrvoje Nikšić <hniksic@gmail.com> Hsiang-Cheng Yang <rick68@users.noreply.github.com> +Huon Wilson <dbau.pp@gmail.com> +Huon Wilson <dbau.pp@gmail.com> <wilson.huon@gmail.com> Ian Jackson <ijackson@chiark.greenend.org.uk> <ian.jackson@citrix.com> Ian Jackson <ijackson@chiark.greenend.org.uk> <ijackson+github@slimy.greenend.org.uk> Ian Jackson <ijackson@chiark.greenend.org.uk> <iwj@xenproject.org> @@ -245,10 +269,15 @@ Irina Popa <irinagpopa@gmail.com> Ivan Ivaschenko <defuz.net@gmail.com> ivan tkachenko <me@ratijas.tk> J. J. Weber <jjweber@gmail.com> -Jack Huey <jack.huey@umassmed.edu> +Jack Huey <jack.huey@umassmed.edu> <jackh726@gmail.com> Jacob <jacob.macritchie@gmail.com> +Jacob Hoffman-Andrews <rust@hoffman-andrews.com> <github@hoffman-andrews.com> Jacob Greenfield <xales@naveria.com> Jacob Pratt <jacob@jhpratt.dev> <the.z.cuber@gmail.com> +Jacob Pratt <jacob@jhpratt.dev> <jacopratt@tesla.com> +Jake Goulding <jake.goulding@integer32.com> +Jake Goulding <jake.goulding@integer32.com> <jake.goulding@gmail.com> +Jake Goulding <jake.goulding@integer32.com> <shepmaster@mac.com> Jake Vossen <jake@vossen.dev> Jakob Degen <jakob.e.degen@gmail.com> <jakob@degen.com> Jakob Lautrup Nysom <jako3047@gmail.com> @@ -256,12 +285,17 @@ Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakub.bukaj@yahoo.com> Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakub@jakub.cc> Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakubw@jakubw.net> +Jakub Beránek <berykubik@gmail.com> <jakub.beranek@vsb.cz> James [Undefined] <tpzker@thepuzzlemaker.info> James Deng <cnjamesdeng@gmail.com> <cnJamesDeng@gmail.com> James Hinshelwood <jameshinshelwood1@gmail.com> <james.hinshelwood@bigpayme.com> James Miller <bladeon@gmail.com> <james@aatch.net> James Perry <james.austin.perry@gmail.com> James Sanderson <zofrex@gmail.com> +Jamie Hill-Daniel <jamie@hill-daniel.co.uk> <clubby789@gmail.com> +Jana Dönszelmann <jana@donsz.nl> +Jana Dönszelmann <jana@donsz.nl> <jonathan@donsz.nl> +Jana Dönszelmann <jana@donsz.nl> <jonabent@gmail.com> Jan-Erik Rediger <janerik@fnordig.de> <badboy@archlinux.us> Jaro Fietz <jaro.fietz@gmx.de> Jason Fager <jfager@gmail.com> @@ -280,6 +314,7 @@ Jerry Hardee <hardeejj9@gmail.com> Jesús Rubio <jesusprubio@gmail.com> Jethro Beekman <github@jbeekman.nl> Jian Zeng <knight42@mail.ustc.edu.cn> +Jieyou Xu <jieyouxu@outlook.com> Jieyou Xu <jieyouxu@outlook.com> <39484203+jieyouxu@users.noreply.github.com> Jihyun Yu <j.yu@navercorp.com> <yjh0502@gmail.com> Jihyun Yu <j.yu@navercorp.com> jihyun <jihyun@nablecomm.com> @@ -291,6 +326,7 @@ John Clements <clements@racket-lang.org> <clements@brinckerhoff.org> John Hodge <acessdev@gmail.com> John Hodge <tpg@mutabah.net> John Hörnvall <trolledwoods@gmail.com> John Kåre Alsaker <john.kare.alsaker@gmail.com> +John Kåre Alsaker <john.kare.alsaker@gmail.com> <zoxc32@gmail.com> John Talling <inrustwetrust@users.noreply.github.com> John Van Enk <vanenkj@gmail.com> Jonas Tepe <jonasprogrammer@gmail.com> @@ -314,9 +350,12 @@ Josh Holmer <jholmer.in@gmail.com> Josh Stone <cuviper@gmail.com> <jistone@redhat.com> Josh Stone <cuviper@gmail.com> <jistone@fedoraproject.org> Julia Ryan <juliaryan3.14@gmail.com> <josephryan3.14@gmail.com> +Jubilee Young <workingjubilee@gmail.com> <46493976+workingjubilee@users.noreply.github.com> +Jubilee Young <workingjubilee@gmail.com> Julian Knodt <julianknodt@gmail.com> jumbatm <jumbatm@gmail.com> <30644300+jumbatm@users.noreply.github.com> Junyoung Cho <june0.cho@samsung.com> +Jynn Nelson <github@jyn.dev> <rust@jyn.dev> Jynn Nelson <github@jyn.dev> <jyn514@gmail.com> Jynn Nelson <github@jyn.dev> <joshua@yottadb.com> Jynn Nelson <github@jyn.dev> <jyn.nelson@redjack.com> @@ -367,21 +406,27 @@ Lukas Lueg <lukas.lueg@gmail.com> Luke Metz <luke.metz@students.olin.edu> Luqman Aden <me@luqman.ca> <laden@csclub.uwaterloo.ca> Luqman Aden <me@luqman.ca> <laden@mozilla.com> +Luqman Aden <me@luqman.ca> <rust@luqman.ca> Lzu Tao <taolzu@gmail.com> Maik Klein <maikklein@googlemail.com> +Maja Kądziołka <maya@compilercrim.es> <github@compilercrim.es> +Maja Kądziołka <maya@compilercrim.es> <kuba@kadziolka.net> Malo Jaffré <jaffre.malo@gmail.com> Manish Goregaokar <manishsmail@gmail.com> Mara Bos <m-ou.se@m-ou.se> Marcell Pardavi <marcell.pardavi@gmail.com> +Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Marcus Klaas de Vries <mail@marcusklaas.nl> Margaret Meyerhofer <mmeyerho@andrew.cmu.edu> <mmeyerho@andrew> Mark Mansi <markm@cs.wisc.edu> +Mark Mansi <markm@cs.wisc.edu> <m.mim95@gmail.com> Mark Rousskov <mark.simulacrum@gmail.com> Mark Sinclair <mark.edward.x@gmail.com> Mark Sinclair <mark.edward.x@gmail.com> =Mark Sinclair <=125axel125@gmail.com> Markus Legner <markus@legner.ch> Markus Westerlind <marwes91@gmail.com> Markus <marwes91@gmail.com> Martin Carton <cartonmartin+git@gmail.com> +Martin Carton <cartonmartin+git@gmail.com> <cartonmartin@gmail.com> Martin Habovštiak <martin.habovstiak@gmail.com> Martin Hafskjold Thoresen <martinhath@gmail.com> Martin Nordholts <martin.nordholts@codetale.se> <enselic@gmail.com> @@ -406,8 +451,10 @@ Melody Horn <melody@boringcactus.com> <mathphreak@gmail.com> Mendes <pedro.mendes.26@gmail.com> mental <m3nta1@yahoo.com> mibac138 <5672750+mibac138@users.noreply.github.com> +Michael Howell <michael@notriddle.com> <notriddle+rust-mod@protonmail.com> Michael Williams <m.t.williams@live.com> Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail> +Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail.com> Michael Woerister <michaelwoerister@posteo> <michaelwoerister@users.noreply.github.com> Michael Woerister <michaelwoerister@posteo> <michaelwoerister@posteo.net> Michael Zhang <hmperson1@gmail.com> @@ -421,6 +468,8 @@ Ms2ger <ms2ger@gmail.com> <Ms2ger@gmail.com> msizanoen1 <qtmlabs@protonmail.com> Mukilan Thiagarajan <mukilanthiagarajan@gmail.com> Nadrieril Feneanar <Nadrieril@users.noreply.github.com> +Nadrieril Feneanar <Nadrieril@users.noreply.github.com> <nadrieril+rust@gmail.com> +Nadrieril Feneanar <Nadrieril@users.noreply.github.com> <nadrieril+git@gmail.com> NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm@gmail.com> NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm+github@gmail.com> Nathan Ringo <remexre@gmail.com> @@ -436,13 +485,23 @@ Nicholas Bishop <nbishop@nbishop.net> <nicholasbishop@gmail.com> Nicholas Bishop <nbishop@nbishop.net> <nicholasbishop@google.com> Nicholas Nethercote <n.nethercote@gmail.com> <nnethercote@apple.com> Nicholas Nethercote <n.nethercote@gmail.com> <nnethercote@mozilla.com> +Nick Cameron <nrc@ncameron.org> <ncameron@mozilla.com> +Nick Fitzgerald <fitzgen@gmail.com> <nfitzgerald@mozilla.com> Nick Platt <platt.nicholas@gmail.com> Niclas Schwarzlose <15schnic@gmail.com> Nicolas Abram <abramlujan@gmail.com> Nicole Mazzuca <npmazzuca@gmail.com> +Niko Matsakis <rust@nikomatsakis.com> +Niko Matsakis <rust@nikomatsakis.com> <niko@alum.mit.edu> +Noratrieb <48135649+Noratrieb@users.noreply.github.com> Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com> +Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nilstrieb@gmail.com> +Noratrieb <48135649+Noratrieb@users.noreply.github.com> <rust@noratrieb.dev> +Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nora@noratrieb.dev> Nif Ward <nif.ward@gmail.com> Nika Layzell <nika@thelayzells.com> <michael@thelayzells.com> +Nikita Popov <nikita.ppv@gmail.com> +Nikita Popov <nikita.ppv@gmail.com> <npopov@redhat.com> NODA Kai <nodakai@gmail.com> Oğuz Ağcayazı <oguz.agcayazi@gmail.com> <oguz.agcayazi@gmail.com> Oğuz Ağcayazı <oguz.agcayazi@gmail.com> <ouz.agz@gmail.com> @@ -459,6 +518,7 @@ Oliver Scherer <oli-obk@users.noreply.github.com> <github6541940@oli-obk.de> Oliver Scherer <oli-obk@users.noreply.github.com> <public.oliver.schneider@kit.edu> Oliver Scherer <oli-obk@users.noreply.github.com> <oliver.schneider@kit.edu> Oliver Scherer <oli-obk@users.noreply.github.com> <obk8176014uqher834@olio-obk.de> +Oliver Scherer <oli-obk@users.noreply.github.com> <rustc-contact@oli-obk.de> Oliver Scherer <oli-obk@users.noreply.github.com> Onur Özkan <onurozkan.dev@outlook.com> <work@onurozkan.dev> Onur Özkan <onurozkan.dev@outlook.com> @@ -495,18 +555,23 @@ Raphaël Huchet <rap2hpoutre@users.noreply.github.com> rChaser53 <tayoshizawa29@gmail.com> Rémy Rakic <remy.rakic@gmail.com> Rémy Rakic <remy.rakic@gmail.com> <remy.rakic+github@gmail.com> +Rémy Rakic <remy.rakic@gmail.com> <remy.rakic+rust@gmail.com> Renato Riccieri Santos Zannon <renato@rrsz.com.br> Richard Diamond <wichard@vitalitystudios.com> <wichard@hahbee.co> Ricky Hosfelt <ricky@hosfelt.io> Ritiek Malhotra <ritiekmalhotra123@gmail.com> Rob Arnold <robarnold@cs.cmu.edu> Rob Arnold <robarnold@cs.cmu.edu> Rob Arnold <robarnold@68-26-94-7.pools.spcsdns.net> +Robert Collins <robertc@robertcollins.net> <robertc+rust@robertcollins.net> Robert Foss <dev@robertfoss.se> robertfoss <dev@robertfoss.se> Robert Gawdzik <rgawdzik@hotmail.com> Robert Gawdzik ☢ <rgawdzik@hotmail.com> Robert Habermeier <rphmeier@gmail.com> Robert Millar <robert.millar@cantab.net> Roc Yu <rocyu@protonmail.com> Rohit Joshi <rohitjoshi@users.noreply.github.com> Rohit Joshi <rohit.joshi@capitalone.com> +Ross Smyth <18294397+RossSmyth@users.noreply.github.com> +Ross Smyth <18294397+RossSmyth@users.noreply.github.com> <crs2017@gmail.com> +Ross Smyth <18294397+RossSmyth@users.noreply.github.com> <rsmyth@electrocraft.com> Roxane Fruytier <roxane.fruytier@hotmail.com> Rui <xiongmao86dev@sina.com> Russell Johnston <rpjohnst@gmail.com> @@ -524,6 +589,7 @@ Samuel Tardieu <sam@rfc1149.net> Santiago Pastorino <spastorino@gmail.com> Santiago Pastorino <spastorino@gmail.com> <santiago@wyeworks.com> Scott McMurray <scottmcm@users.noreply.github.com> +Scott McMurray <scottmcm@users.noreply.github.com> <smcmurray@acm.org> Scott Olson <scott@solson.me> Scott Olson <scott@scott-olson.org> Sean Gillespie <sean.william.g@gmail.com> swgillespie <sean.william.g@gmail.com> Seiichi Uchida <seuchida@gmail.com> @@ -535,8 +601,17 @@ Shyam Sundar B <shyambaskaran@outlook.com> Simon Barber-Dueck <sbarberdueck@gmail.com> Simon BD <simon@server> Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org> Simonas Kazlauskas <git@kazlauskas.me> Simonas Kazlauskas <github@kazlauskas.me> +Simonas Kazlauskas <git@kazlauskas.me> <simonas+t-compiler@kazlauskas.me> Siva Prasad <sivaauturic@gmail.com> +Skgland <3877590+Skgland@users.noreply.github.com> +Skgland <3877590+Skgland@users.noreply.github.com> <bb-github@t-online.de> +Skgland <3877590+Skgland@users.noreply.github.com> <bennet.blessmann+github@googlemail.com> Smittyvb <me@smitop.com> +Sophia June Turner <547158+sophiajt@users.noreply.github.com> +Sophia June Turner <547158+sophiajt@users.noreply.github.com> <547158+jntrnr@users.noreply.github.com> +Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jonathandturner@users.noreply.github.com> +Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jturner@mozilla.com> +Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jonathan.d.turner@gmail.com> Srinivas Reddy Thatiparthy <thatiparthysreenivas@gmail.com> Stanislav Tkach <stanislav.tkach@gmail.com> startling <tdixon51793@gmail.com> @@ -555,6 +630,8 @@ Tatsuyuki Ishi <ishitatsuyuki@gmail.com> Tau Gärtli <git@tau.garden> <ruben.schmidmeister@icloud.com> Tero Hänninen <lgvz@users.noreply.github.com> Tero Hänninen <tejohann@kapsi.fi> The8472 <git@infinite-source.de> +The8472 <git@infinite-source.de> <the8472.rs@infinite-source.de> +The8472 <git@infinite-source.de> <the8472@users.noreply.github.com> Theo Belaire <theo.belaire@gmail.com> Theo Belaire <tyr.god.of.war.42@gmail.com> Theodore Luo Wang <wangtheo662@gmail.com> Thiago Pontes <email@thiago.me> thiagopnts <thiagopnts@gmail.com> @@ -567,8 +644,10 @@ Tim Diekmann <t.diekmann.3dv@gmail.com> Tim Hutt <tdhutt@gmail.com> Tim JIANG <p90eri@gmail.com> Tim Joseph Dumol <tim@timdumol.com> +Tim Neumann <mail@timnn.me> <timnn@google.com> Timothy Maloney <tmaloney@pdx.edu> Tomas Koutsky <tomas@stepnivlk.net> +Tomasz Miąsko <tomasz.miasko@gmail.com> Torsten Weber <TorstenWeber12@gmail.com> Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com> Trevor Gross <tmgross@umich.edu> <t.gross35@gmail.com> @@ -588,11 +667,14 @@ Valerii Lashmanov <vflashm@gmail.com> Vitali Haravy <HumaneProgrammer@gmail.com> Vitali Haravy <humaneprogrammer@gmail.com> Vitaly Shukela <vi0oss@gmail.com> Waffle Lapkin <waffle.lapkin@gmail.com> -Waffle Lapkin <waffle.lapkin@tasking.com> +Waffle Lapkin <waffle.lapkin@gmail.com> <waffle.lapkin@tasking.com> +Weihang Lo <me@weihanglo.tw> +Weihang Lo <me@weihanglo.tw> <weihanglo@users.noreply.github.com> Wesley Wiser <wwiser@gmail.com> <wesleywiser@microsoft.com> whitequark <whitequark@whitequark.org> William Ting <io@williamting.com> <william.h.ting@gmail.com> -Wim Looman <wim@nemo157.com> +Wim Looman <wim@nemo157.com> <rust-lang@nemo157.com> +Wim Looman <wim@nemo157.com> <git@nemo157.com> Without Boats <woboats@gmail.com> Without Boats <woboats@gmail.com> <boats@mozilla.com> Xinye Tao <xy.tao@outlook.com> diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eeff563d8ecdf..e155e253784aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,15 @@ Documentation for contributing to the compiler or tooling is located in the [Gui Development][rustc-dev-guide], commonly known as the [rustc-dev-guide]. Documentation for the standard library in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide]. +## Making changes to subtrees and submodules + +For submodules, changes need to be made against the repository corresponding the +submodule, and not the main `rust-lang/rust` repository. + +For subtrees, prefer sending a PR against the subtree's repository if it does +not need to be made against the main `rust-lang/rust` repository (e.g. a +rustc-dev-guide change that does not accompany a compiler change). + ## About the [rustc-dev-guide] The [rustc-dev-guide] is meant to help document how rustc –the Rust compiler– works, diff --git a/COPYRIGHT b/COPYRIGHT index 05993830a0fb4..4dad74f234eaa 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -3,6 +3,7 @@ Short version for non-lawyers: The Rust Project is dual-licensed under Apache 2.0 and MIT terms. +It is Copyright (c) The Rust Project Contributors. Longer version: @@ -11,381 +12,23 @@ copyright assignment is required to contribute to the Rust project. Some files include explicit copyright notices and/or license notices. For full authorship information, see the version control history or -https://thanks.rust-lang.org - -Except as otherwise noted (below and/or in individual files), Rust is -licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or -<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. - - -The Rust Project includes packages written by third parties. -The following third party packages are included, and carry -their own copyright notices and license terms: - -* LLVM, located in src/llvm-project, is licensed under the following - terms. - - ============================================================================== - The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: - ============================================================================== - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - ---- LLVM Exceptions to the Apache 2.0 License ---- - - As an exception, if, as a result of your compiling your source code, portions - of this Software are embedded into an Object form of such source code, you - may redistribute such embedded portions in such Object form without complying - with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - - In addition, if you combine or link compiled forms of this Software with - software that is licensed under the GPLv2 ("Combined Software") and if a - court of competent jurisdiction determines that the patent provision (Section - 3), the indemnity provision (Section 9) or other Section of the License - conflicts with the conditions of the GPLv2, you may retroactively and - prospectively choose to deem waived or otherwise exclude such Section(s) of - the License, but only in their entirety and only with respect to the Combined - Software. - - ============================================================================== - Software from third parties included in the LLVM Project: - ============================================================================== - The LLVM Project contains third party software which is under different license - terms. All such code will be identified clearly using at least one of two - mechanisms: - 1) It will be in a separate directory tree with its own `LICENSE.txt` or - `LICENSE` file at the top containing the specific license and restrictions - which apply to that software, or - 2) It will contain specific license and restriction terms at the top of every - file. - - ============================================================================== - Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): - ============================================================================== - University of Illinois/NCSA - Open Source License - - Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. - All rights reserved. - - Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal with - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE - SOFTWARE. - -* Portions of the FFI code for interacting with the native ABI - is derived from the Clay programming language, which carries - the following license. - - Copyright (C) 2008-2010 Tachyon Technologies. - All rights reserved. - - Redistribution and use in source and binary forms, with - or without modification, are permitted provided that the - following conditions are met: - - 1. Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - - 2. Redistributions in binary form must reproduce the - above copyright notice, this list of conditions and - the following disclaimer in the documentation and/or - other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - OF SUCH DAMAGE. - -* Portions of internationalization code use code or data from Unicode, which - carry the following license: - - UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE - - See Terms of Use <https://www.unicode.org/copyright.html> - for definitions of Unicode Inc.’s Data Files and Software. - - NOTICE TO USER: Carefully read the following legal agreement. - BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S - DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), - YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE - TERMS AND CONDITIONS OF THIS AGREEMENT. - IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE - THE DATA FILES OR SOFTWARE. - - COPYRIGHT AND PERMISSION NOTICE - - Copyright © 1991-2022 Unicode, Inc. All rights reserved. - Distributed under the Terms of Use in https://www.unicode.org/copyright.html. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of the Unicode data files and any associated documentation - (the "Data Files") or Unicode software and any associated documentation - (the "Software") to deal in the Data Files or Software - without restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, and/or sell copies of - the Data Files or Software, and to permit persons to whom the Data Files - or Software are furnished to do so, provided that either - (a) this copyright and permission notice appear with all copies - of the Data Files or Software, or - (b) this copyright and permission notice appear in associated - Documentation. - - THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF - ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS - NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL - DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THE DATA FILES OR SOFTWARE. - - Except as contained in this notice, the name of a copyright holder - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in these Data Files or Software without prior - written authorization of the copyright holder. +<https://thanks.rust-lang.org> + +Except as otherwise noted, Rust is licensed under the Apache License, Version +2.0 <LICENSE-APACHE> or <http://www.apache.org/licenses/LICENSE-2.0> or the MIT +license <LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +We track licenses for third-party materials in two ways: + +* We use [REUSE](https://reuse.software) to track license information for + in-tree source files - both those authored by the Rust project and those + authored by third parties. See `REUSE.toml`, and our cached output of the + `reuse` tool which is committed to `license-metadata.json`. +* We use `cargo` to track license information for out-of-tree dependencies. + +These two sources of information are collected by the tool `generate-copyright` +into a file called `COPYRIGHT.html`, which is shipped with each binary release +of Rust. Please refer to that file for detailed information as to the components of +any given Rust release. We also produce a `COPYRIGHT-library.html` file which only +covers the subset of source code used in the Rust Standard Library, as opposed +to the toolchain as a whole. diff --git a/Cargo.lock b/Cargo.lock index 5f81a5a84966a..49c1eb5b45f77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,19 +34,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -58,22 +45,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" - -[[package]] -name = "ammonia" -version = "4.0.0" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" -dependencies = [ - "html5ever", - "maplit", - "once_cell", - "tendril", - "url", -] +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-tzdata" @@ -102,19 +76,19 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" +checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" dependencies = [ "anstyle", - "unicode-width 0.1.14", + "unicode-width 0.2.0", ] [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -127,65 +101,66 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-lossy" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f45c79b3b9413932fc255f2c19ca0d48eaab72c4ea1913bafaebf289cbc099f2" +checksum = "934ff8719effd2023a48cf63e69536c1c3ced9d3895068f6f5cc9a4ff845e59b" dependencies = [ "anstyle", ] [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-svg" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962f6d5681926dbe5503b71057202d6723a33abe464c983b1d160bca3095a3bb" +checksum = "d3607949e9f6de49ea4bafe12f5e4fd73613ebf24795e48587302a8cc0e4bb35" dependencies = [ "anstream", "anstyle", "anstyle-lossy", "html-escape", - "unicode-width 0.1.14", + "unicode-width 0.2.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" dependencies = [ "backtrace", ] @@ -196,14 +171,14 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" dependencies = [ - "object 0.36.4", + "object 0.36.7", ] [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -211,6 +186,48 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "askama" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash 2.1.1", + "serde", + "serde_derive", + "syn 2.0.100", +] + +[[package]] +name = "askama_parser" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow 0.7.6", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -240,9 +257,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "basic-toml" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" dependencies = [ "serde", ] @@ -258,21 +275,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "blake3" -version = "1.5.2" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d08263faac5cde2a4d52b513dadb80846023aade56fcd8fc99ba73ba8050e92" +checksum = "389a099b34312839e16420d499a9cad9650541715937ffbdd40d36f49e77eeb3" dependencies = [ "arrayref", "arrayvec", @@ -292,12 +303,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.9", "serde", ] @@ -339,9 +350,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytecount" @@ -349,17 +360,11 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" -version = "1.7.2" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "camino" @@ -374,10 +379,10 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata", + "cargo_metadata 0.19.2", "directories", "rustc-build-sysroot", - "rustc_tools_util 0.4.0", + "rustc_tools_util 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version", "serde", "serde_json", @@ -385,9 +390,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -403,7 +408,21 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.12", ] [[package]] @@ -412,9 +431,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.1.23" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bbb537bb4a30b90362caddba8f360c0a56bc13d3a5570028e7197204cb54a17" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "shlex", ] @@ -433,22 +452,22 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "chrono-tz" -version = "0.10.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3" dependencies = [ "chrono", "chrono-tz-build", @@ -457,9 +476,9 @@ dependencies = [ [[package]] name = "chrono-tz-build" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402" dependencies = [ "parse-zoneinfo", "phf_codegen", @@ -477,9 +496,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" dependencies = [ "clap_builder", "clap_derive", @@ -497,50 +516,40 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", - "terminal_size", -] - -[[package]] -name = "clap_complete" -version = "4.5.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" -dependencies = [ - "clap", ] [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clippy" -version = "0.1.83" +version = "0.1.87" dependencies = [ "anstream", - "cargo_metadata", + "cargo_metadata 0.18.1", "clippy_config", "clippy_lints", "clippy_utils", @@ -550,12 +559,14 @@ dependencies = [ "if_chain", "itertools", "parking_lot", + "pulldown-cmark 0.11.3", "quote", "regex", - "rustc_tools_util 0.3.0", + "rinja", + "rustc_tools_util 0.4.2", "serde", "serde_json", - "syn 2.0.79", + "syn 2.0.100", "tempfile", "termize", "tokio", @@ -566,8 +577,9 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.83" +version = "0.1.87" dependencies = [ + "clippy_utils", "itertools", "serde", "toml 0.7.8", @@ -579,27 +591,27 @@ name = "clippy_dev" version = "0.0.1" dependencies = [ "aho-corasick", + "chrono", "clap", "indoc", "itertools", - "opener 0.6.1", + "opener", "shell-escape", "walkdir", ] [[package]] name = "clippy_lints" -version = "0.1.83" +version = "0.1.87" dependencies = [ "arrayvec", - "cargo_metadata", + "cargo_metadata 0.18.1", "clippy_config", "clippy_utils", - "declare_clippy_lint", "itertools", "quine-mc_cluskey", "regex", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "semver", "serde", "serde_json", @@ -613,12 +625,12 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.83" +version = "0.1.87" dependencies = [ "arrayvec", - "clippy_config", "itertools", "rustc_apfloat", + "serde", ] [[package]] @@ -648,23 +660,23 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" +checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" +checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] @@ -681,18 +693,18 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -706,8 +718,8 @@ name = "compiletest" version = "0.0.0" dependencies = [ "anstyle-svg", - "anyhow", "build_helper", + "camino", "colored", "diff", "getopts", @@ -719,33 +731,34 @@ dependencies = [ "miropt-test-tools", "regex", "rustfix", + "semver", "serde", "serde_json", "tracing", "tracing-subscriber", "unified-diff", "walkdir", - "windows", + "windows 0.59.0", ] [[package]] name = "console" -version = "0.15.8" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "unicode-width 0.1.14", - "windows-sys 0.52.0", + "once_cell", + "unicode-width 0.2.0", + "windows-sys 0.59.0", ] [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "core-foundation-sys" @@ -767,9 +780,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -785,18 +798,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -813,9 +826,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" @@ -829,9 +842,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.5" +version = "3.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c" dependencies = [ "nix", "windows-sys 0.59.0", @@ -839,9 +852,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.46" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" +checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" dependencies = [ "curl-sys", "libc", @@ -854,9 +867,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.76+curl-8.10.1" +version = "0.4.80+curl-8.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00462dbe9cbb9344e1b2be34d9094d74e3b8aac59a883495b335eafd02e25120" +checksum = "55f7df2eac63200c3ab25bde3b2268ef2ee56af3d238e76d61f01c3c49bff734" dependencies = [ "cc", "libc", @@ -869,9 +882,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", @@ -879,27 +892,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] @@ -919,24 +932,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "declare_clippy_lint" -version = "0.1.83" -dependencies = [ - "itertools", - "quote", - "syn 2.0.79", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - [[package]] name = "derive-where" version = "1.2.7" @@ -945,38 +940,38 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "derive_builder" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "derive_builder_macro" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] @@ -988,7 +983,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] @@ -1009,11 +1004,11 @@ dependencies = [ [[package]] name = "directories" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ - "dirs-sys", + "dirs-sys 0.5.0", ] [[package]] @@ -1022,7 +1017,7 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys", + "dirs-sys 0.4.1", ] [[package]] @@ -1043,10 +1038,22 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", - "redox_users", + "redox_users 0.4.6", "windows-sys 0.48.0", ] +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.0", + "windows-sys 0.59.0", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1054,7 +1061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.6", "winapi", ] @@ -1066,38 +1073,26 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "dissimilar" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" +checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921" [[package]] name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "elasticlunr-rs" -version = "3.0.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e83863a500656dfa214fee6682de9c5b9f03de6860fec531235ed2ae9f6571" -dependencies = [ - "regex", - "serde", - "serde_derive", - "serde_json", -] +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elsa" -version = "1.7.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848fe615fbb0a74d9ae68dcaa510106d32e37d9416207bbea4bd008bd89c47ed" +checksum = "9abf33c656a7256451ebb7d0082c5a471820c31269e49d807c538c252352186e" dependencies = [ "stable_deref_trait", ] @@ -1113,15 +1108,15 @@ dependencies = [ [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -1129,45 +1124,38 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "error_index_generator" -version = "0.0.0" -dependencies = [ - "mdbook", + "windows-sys 0.59.0", ] [[package]] name = "expect-test" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0" +checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0" dependencies = [ "dissimilar", "once_cell", @@ -1191,18 +1179,19 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +name = "features-status-dump" +version = "0.1.0" dependencies = [ - "memoffset", - "rustc_version", + "anyhow", + "clap", + "serde", + "serde_json", + "tidy", ] [[package]] @@ -1219,12 +1208,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.34" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide 0.8.8", ] [[package]] @@ -1258,7 +1247,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" dependencies = [ - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1267,6 +1256,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1303,9 +1298,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1318,9 +1313,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1328,15 +1323,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1345,38 +1340,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1395,11 +1390,11 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", - "cargo_metadata", - "rinja", + "askama", + "cargo_metadata 0.18.1", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1436,31 +1431,32 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] -name = "gimli" -version = "0.28.1" +name = "getrandom" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] [[package]] name = "gimli" -version = "0.30.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" -dependencies = [ - "fallible-iterator", - "indexmap", - "stable_deref_trait", -] +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "fallible-iterator", "indexmap", @@ -1469,21 +1465,21 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "globset" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -1495,28 +1491,15 @@ dependencies = [ "serde", ] -[[package]] -name = "handlebars" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" -dependencies = [ - "log", - "pest", - "pest_derive", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "ahash", "allocator-api2", + "equivalent", + "foldhash", "serde", ] @@ -1546,11 +1529,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1572,16 +1555,14 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.27.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 2.0.79", + "match_token", ] [[package]] @@ -1595,22 +1576,23 @@ dependencies = [ [[package]] name = "humantime" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core 0.61.0", ] [[package]] @@ -1622,6 +1604,18 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + [[package]] name = "icu_list" version = "1.5.0" @@ -1638,9 +1632,9 @@ dependencies = [ [[package]] name = "icu_list_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1825170d2c6679cb20dbd96a589d034e49f698aed9a2ef4fafc9a0101ed298f" +checksum = "52b1a7fbdbf3958f1be8354cb59ac73f165b7b7082d447ff2090355c9a069120" [[package]] name = "icu_locid" @@ -1671,15 +1665,60 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] -name = "icu_provider" +name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", @@ -1713,7 +1752,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] @@ -1730,12 +1769,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1754,7 +1804,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.9", "same-file", "walkdir", "winapi-util", @@ -1768,27 +1818,26 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.5.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", - "rustc-rayon", "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width 0.1.14", + "unicode-width 0.2.0", + "web-time", ] [[package]] @@ -1799,9 +1848,9 @@ checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] @@ -1819,15 +1868,6 @@ dependencies = [ "xz2", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "intl-memoizer" version = "0.5.2" @@ -1864,35 +1904,51 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] -name = "jemalloc-sys" -version = "0.5.4+5.3.0-patched" +name = "jiff" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c1946e1cea1788cbfde01c993b52a10e2da07f4bac608228d1bed20bfebf2" +checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" dependencies = [ - "cc", - "libc", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.2", "libc", ] [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1902,7 +1958,7 @@ version = "0.1.0" dependencies = [ "fs-err", "getopts", - "jsonpath_lib", + "jsonpath-rust", "regex", "serde_json", "shlex", @@ -1915,21 +1971,23 @@ dependencies = [ "anyhow", "clap", "fs-err", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "rustdoc-json-types", "serde", "serde_json", ] [[package]] -name = "jsonpath_lib" -version = "0.3.0" +name = "jsonpath-rust" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" +checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9" dependencies = [ - "log", - "serde", + "pest", + "pest_derive", + "regex", "serde_json", + "thiserror 2.0.12", ] [[package]] @@ -1944,6 +2002,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "levenshtein" version = "1.0.5" @@ -1952,15 +2016,15 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "lexopt" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" +checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libdbus-sys" @@ -1974,9 +2038,9 @@ dependencies = [ [[package]] name = "libffi" -version = "3.2.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" +checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074" dependencies = [ "libc", "libffi-sys", @@ -1984,18 +2048,18 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "2.3.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" +checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84" dependencies = [ "cc", ] [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2003,9 +2067,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" @@ -2013,16 +2077,16 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", "redox_syscall", ] [[package]] name = "libz-sys" -version = "1.1.20" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "libc", @@ -2049,15 +2113,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "lld-wrapper" @@ -2069,7 +2133,7 @@ version = "0.0.1" dependencies = [ "anyhow", "clap", - "thiserror", + "thiserror 1.0.69", "tracing", "tracing-subscriber", ] @@ -2086,9 +2150,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lzma-sys" @@ -2107,17 +2171,11 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "markup5ever" -version = "0.12.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" dependencies = [ "log", "phf", @@ -2127,6 +2185,17 @@ dependencies = [ "tendril", ] +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "matchers" version = "0.1.0" @@ -2146,39 +2215,11 @@ dependencies = [ "digest", ] -[[package]] -name = "mdbook" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" -dependencies = [ - "ammonia", - "anyhow", - "chrono", - "clap", - "clap_complete", - "elasticlunr-rs", - "env_logger", - "handlebars", - "log", - "memchr", - "once_cell", - "opener 0.7.2", - "pulldown-cmark 0.10.3", - "regex", - "serde", - "serde_json", - "shlex", - "tempfile", - "toml 0.5.11", - "topological-sort", -] - [[package]] name = "measureme" -version = "11.0.1" +version = "12.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d" +checksum = "570a507d8948a66a97f42cbbaf8a6bb9516a51017d4ee949502ad7a10a864395" dependencies = [ "log", "memmap2", @@ -2203,15 +2244,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.17" @@ -2230,12 +2262,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.3.1" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437" -dependencies = [ - "clap", -] +checksum = "9bfdc64e2f805f3d12965f10522000bae36e88d2cfea44112331f467d4f4bf68" [[package]] name = "minimal-lexical" @@ -2254,9 +2283,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -2275,24 +2304,24 @@ name = "miri" version = "0.1.0" dependencies = [ "aes", + "bitflags", "chrono", "chrono-tz", "colored", - "ctrlc", "directories", - "getrandom", - "jemalloc-sys", + "getrandom 0.3.2", "libc", "libffi", "libloading", "measureme", - "rand", + "rand 0.9.0", "regex", "rustc_version", "smallvec", "tempfile", + "tikv-jemalloc-sys", "ui_test", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2311,7 +2340,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -2388,12 +2417,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-integer" version = "0.1.46" @@ -2461,9 +2484,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "flate2", @@ -2471,7 +2494,7 @@ dependencies = [ "indexmap", "memchr", "ruzstd", - "wasmparser 0.216.0", + "wasmparser 0.222.1", ] [[package]] @@ -2485,32 +2508,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "once_map" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c7f82d6d446dd295845094f3a76bcdc5e6183b66667334e169f019cd05e5a0" -dependencies = [ - "ahash", - "hashbrown", - "parking_lot", - "stable_deref_trait", -] - -[[package]] -name = "opener" -version = "0.6.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788" -dependencies = [ - "bstr", - "normpath", - "winapi", -] +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "opener" @@ -2526,15 +2526,15 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" dependencies = [ "cc", "libc", @@ -2638,9 +2638,9 @@ dependencies = [ [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -2659,20 +2659,20 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.13" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.12", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.13" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" dependencies = [ "pest", "pest_generator", @@ -2680,22 +2680,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.13" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "pest_meta" -version = "2.7.13" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" dependencies = [ "once_cell", "pest", @@ -2704,66 +2704,47 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_shared 0.11.2", + "phf_shared", ] [[package]] name = "phf_codegen" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_shared 0.10.0", - "rand", + "phf_generator", + "phf_shared", ] [[package]] name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "siphasher", + "phf_shared", + "rand 0.8.5", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2773,9 +2754,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polonius-engine" @@ -2790,21 +2771,24 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] -name = "powerfmt" -version = "0.2.0" +name = "portable-atomic-util" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] @@ -2833,18 +2817,18 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" +checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88" dependencies = [ "cc", ] @@ -2855,20 +2839,8 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.6.0", - "memchr", - "unicase", -] - -[[package]] -name = "pulldown-cmark" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" -dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", - "pulldown-cmark-escape 0.10.1", "unicase", ] @@ -2878,18 +2850,12 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", - "pulldown-cmark-escape 0.11.0", + "pulldown-cmark-escape", "unicase", ] -[[package]] -name = "pulldown-cmark-escape" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" - [[package]] name = "pulldown-cmark-escape" version = "0.11.0" @@ -2910,13 +2876,19 @@ checksum = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -2924,8 +2896,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy", ] [[package]] @@ -2935,7 +2918,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -2944,16 +2937,25 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.2", ] [[package]] name = "rand_xoshiro" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" dependencies = [ - "rand_core", + "rand_core 0.9.3", ] [[package]] @@ -2978,11 +2980,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.6" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -2991,21 +2993,32 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 2.0.12", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -3028,13 +3041,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -3051,9 +3064,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "remote-test-client" @@ -3073,67 +3086,56 @@ dependencies = [ [[package]] name = "rinja" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28580fecce391f3c0e65a692e5f2b5db258ba2346ee04f355ae56473ab973dc" +checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5" dependencies = [ - "humansize", "itoa", - "num-traits", - "percent-encoding", "rinja_derive", ] [[package]] name = "rinja_derive" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f1ae91455a4c82892d9513fcfa1ac8faff6c523602d0041536341882714aede" +checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b" dependencies = [ "basic-toml", "memchr", "mime", "mime_guess", - "once_map", "proc-macro2", "quote", "rinja_parser", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "serde", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "rinja_parser" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea17639e1f35032e1c67539856e498c04cd65fe2a45f55ec437ec55e4be941" +checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610" dependencies = [ "memchr", "nom", "serde", ] -[[package]] -name = "rls" -version = "2.0.0" -dependencies = [ - "serde_json", -] - [[package]] name = "run_make_support" version = "0.2.0" dependencies = [ "bstr", "build_helper", - "gimli 0.31.0", + "gimli 0.31.1", "libc", - "object 0.36.4", + "object 0.36.7", "regex", "serde_json", "similar", - "wasmparser 0.216.0", + "wasmparser 0.219.2", ] [[package]] @@ -3162,78 +3164,79 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc-literal-escaper" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04" [[package]] name = "rustc-main" version = "0.0.0" dependencies = [ - "jemalloc-sys", "rustc_codegen_ssa", "rustc_driver", "rustc_driver_impl", "rustc_smir", "stable_mir", + "tikv-jemalloc-sys", ] [[package]] -name = "rustc-perf-wrapper" -version = "0.1.0" -dependencies = [ - "clap", -] - -[[package]] -name = "rustc-rayon" -version = "0.5.0" +name = "rustc-rayon-core" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710" +checksum = "2f42932dcd3bcbe484b38a3ccf79b7906fac41c02d408b5b1bac26da3416efdb" dependencies = [ - "either", - "rustc-rayon-core", + "crossbeam-deque", + "crossbeam-utils", ] [[package]] -name = "rustc-rayon-core" -version = "0.5.0" +name = "rustc-stable-hash" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] +checksum = "781442f29170c5c93b7185ad559492601acdc71d5bb0706f5868094f45cfcd08" [[package]] -name = "rustc-stable-hash" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c9f15eec8235d7cb775ee6f81891db79b98fd54ba1ad8fae565b88ef1ae4e2" +name = "rustc-std-workspace-alloc" +version = "1.0.1" + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.1" + +[[package]] +name = "rustc-std-workspace-std" +version = "1.0.1" [[package]] name = "rustc_abi" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", - "rand", + "bitflags", + "rand 0.9.0", "rand_xoshiro", "rustc_data_structures", + "rustc_hashes", "rustc_index", "rustc_macros", "rustc_serialize", + "rustc_span", "tracing", ] [[package]] name = "rustc_apfloat" -version = "0.2.1+llvm-462a31f5a5ab" +version = "0.2.2+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886d94c63c812a8037c4faca2607453a0fa4cf82f734665266876b022244543f" +checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" dependencies = [ - "bitflags 1.3.2", + "bitflags", "smallvec", ] @@ -3248,12 +3251,12 @@ dependencies = [ name = "rustc_ast" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", + "rustc-literal-escaper", "rustc_ast_ir", "rustc_data_structures", "rustc_index", - "rustc_lexer", "rustc_macros", "rustc_serialize", "rustc_span", @@ -3269,17 +3272,19 @@ dependencies = [ "rustc_data_structures", "rustc_macros", "rustc_serialize", - "rustc_span", ] [[package]] name = "rustc_ast_lowering" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", + "rustc_feature", "rustc_fluent_macro", "rustc_hir", "rustc_index", @@ -3298,9 +3303,10 @@ name = "rustc_ast_passes" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_ast", "rustc_ast_pretty", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -3309,7 +3315,6 @@ dependencies = [ "rustc_parse", "rustc_session", "rustc_span", - "rustc_target", "thin-vec", ] @@ -3325,21 +3330,36 @@ dependencies = [ ] [[package]] -name = "rustc_attr" +name = "rustc_attr_data_structures" version = "0.0.0" dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", + "rustc_macros", + "rustc_serialize", + "rustc_span", + "thin-vec", +] + +[[package]] +name = "rustc_attr_parsing" +version = "0.0.0" +dependencies = [ + "rustc_abi", + "rustc_ast", + "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_errors", "rustc_feature", "rustc_fluent_macro", + "rustc_hir", "rustc_lexer", "rustc_macros", - "rustc_serialize", "rustc_session", "rustc_span", + "thin-vec", ] [[package]] @@ -3360,6 +3380,7 @@ dependencies = [ "either", "itertools", "polonius-engine", + "rustc_abi", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -3373,7 +3394,6 @@ dependencies = [ "rustc_mir_dataflow", "rustc_session", "rustc_span", - "rustc_target", "rustc_trait_selection", "rustc_traits", "smallvec", @@ -3386,12 +3406,13 @@ version = "0.0.0" dependencies = [ "rustc_ast", "rustc_ast_pretty", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_expand", "rustc_feature", "rustc_fluent_macro", + "rustc_hir", "rustc_index", "rustc_lexer", "rustc_lint_defs", @@ -3410,20 +3431,22 @@ dependencies = [ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", + "gimli 0.31.1", "itertools", "libc", "measureme", - "object 0.36.4", + "object 0.36.7", "rustc-demangle", "rustc_abi", "rustc_ast", - "rustc_attr", + "rustc_attr_parsing", "rustc_codegen_ssa", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", "rustc_fs_util", + "rustc_hashes", "rustc_hir", "rustc_index", "rustc_llvm", @@ -3448,30 +3471,30 @@ version = "0.0.0" dependencies = [ "ar_archive_writer", "arrayvec", - "bitflags 2.6.0", + "bitflags", + "bstr", "cc", "either", "itertools", - "jobserver", "libc", - "object 0.36.4", + "object 0.36.7", "pathdiff", "regex", "rustc_abi", "rustc_arena", "rustc_ast", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", "rustc_fs_util", + "rustc_hashes", "rustc_hir", "rustc_incremental", "rustc_index", "rustc_macros", "rustc_metadata", "rustc_middle", - "rustc_monomorphize", "rustc_query_system", "rustc_serialize", "rustc_session", @@ -3479,15 +3502,14 @@ dependencies = [ "rustc_symbol_mangling", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "serde_json", "smallvec", "tempfile", "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder 0.216.0", - "windows", + "wasm-encoder 0.219.2", + "windows 0.59.0", ] [[package]] @@ -3498,7 +3520,7 @@ dependencies = [ "rustc_abi", "rustc_apfloat", "rustc_ast", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -3512,7 +3534,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "tracing", ] @@ -3521,10 +3542,11 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "arrayvec", - "bitflags 2.6.0", + "bitflags", "either", "elsa", "ena", + "hashbrown", "indexmap", "jobserver", "libc", @@ -3532,11 +3554,12 @@ dependencies = [ "memmap2", "parking_lot", "portable-atomic", - "rustc-hash 1.1.0", - "rustc-rayon", + "rustc-hash 2.1.1", + "rustc-rayon-core", "rustc-stable-hash", "rustc_arena", "rustc_graphviz", + "rustc_hashes", "rustc_index", "rustc_macros", "rustc_serialize", @@ -3545,7 +3568,7 @@ dependencies = [ "tempfile", "thin-vec", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -3560,12 +3583,14 @@ name = "rustc_driver_impl" version = "0.0.0" dependencies = [ "ctrlc", + "jiff", "libc", + "rustc_abi", "rustc_ast", "rustc_ast_lowering", "rustc_ast_passes", "rustc_ast_pretty", - "rustc_attr", + "rustc_attr_parsing", "rustc_borrowck", "rustc_builtin_macros", "rustc_codegen_ssa", @@ -3605,9 +3630,8 @@ dependencies = [ "rustc_ty_utils", "serde_json", "shlex", - "time", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -3637,16 +3661,20 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ - "annotate-snippets 0.11.4", + "annotate-snippets 0.11.5", "derive_setters", + "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_error_codes", "rustc_error_messages", "rustc_fluent_macro", + "rustc_hashes", "rustc_hir", "rustc_index", + "rustc_lexer", "rustc_lint_defs", "rustc_macros", "rustc_serialize", @@ -3658,7 +3686,7 @@ dependencies = [ "termcolor", "termize", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -3668,11 +3696,12 @@ dependencies = [ "rustc_ast", "rustc_ast_passes", "rustc_ast_pretty", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", "rustc_fluent_macro", + "rustc_hir", "rustc_lexer", "rustc_lint_defs", "rustc_macros", @@ -3691,18 +3720,20 @@ version = "0.0.0" dependencies = [ "rustc_data_structures", "rustc_span", + "serde", + "serde_json", ] [[package]] name = "rustc_fluent_macro" version = "0.0.0" dependencies = [ - "annotate-snippets 0.11.4", + "annotate-snippets 0.11.5", "fluent-bundle", "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", "unic-langid", ] @@ -3714,20 +3745,31 @@ version = "0.0.0" name = "rustc_graphviz" version = "0.0.0" +[[package]] +name = "rustc_hashes" +version = "0.0.0" +dependencies = [ + "rustc-stable-hash", +] + [[package]] name = "rustc_hir" version = "0.0.0" dependencies = [ "odht", + "rustc_abi", "rustc_arena", "rustc_ast", + "rustc_attr_data_structures", "rustc_data_structures", + "rustc_hashes", "rustc_index", "rustc_macros", "rustc_serialize", "rustc_span", "rustc_target", "smallvec", + "thin-vec", "tracing", ] @@ -3736,15 +3778,15 @@ name = "rustc_hir_analysis" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_arena", "rustc_ast", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", "rustc_fluent_macro", "rustc_hir", - "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_lint_defs", @@ -3754,7 +3796,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "smallvec", "tracing", ] @@ -3763,11 +3804,12 @@ dependencies = [ name = "rustc_hir_pretty" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_hir", "rustc_span", - "rustc_target", ] [[package]] @@ -3777,8 +3819,7 @@ dependencies = [ "itertools", "rustc_abi", "rustc_ast", - "rustc_ast_ir", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -3792,9 +3833,7 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", - "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "smallvec", "tracing", ] @@ -3803,13 +3842,14 @@ dependencies = [ name = "rustc_incremental" version = "0.0.0" dependencies = [ - "rand", + "rand 0.9.0", "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", "rustc_fs_util", "rustc_graphviz", + "rustc_hashes", "rustc_hir", "rustc_macros", "rustc_middle", @@ -3824,7 +3864,6 @@ dependencies = [ name = "rustc_index" version = "0.0.0" dependencies = [ - "arrayvec", "rustc_index_macros", "rustc_macros", "rustc_serialize", @@ -3837,14 +3876,13 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "rustc_infer" version = "0.0.0" dependencies = [ - "rustc_ast_ir", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -3852,9 +3890,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_middle", - "rustc_next_trait_solver", "rustc_span", - "rustc_target", "rustc_type_ir", "smallvec", "thin-vec", @@ -3865,13 +3901,13 @@ dependencies = [ name = "rustc_interface" version = "0.0.0" dependencies = [ - "rustc-rayon", "rustc-rayon-core", + "rustc_abi", "rustc_ast", "rustc_ast_lowering", "rustc_ast_passes", "rustc_ast_pretty", - "rustc_attr", + "rustc_attr_parsing", "rustc_borrowck", "rustc_builtin_macros", "rustc_codegen_llvm", @@ -3900,7 +3936,6 @@ dependencies = [ "rustc_query_impl", "rustc_query_system", "rustc_resolve", - "rustc_serialize", "rustc_session", "rustc_span", "rustc_symbol_mangling", @@ -3916,6 +3951,7 @@ name = "rustc_lexer" version = "0.0.0" dependencies = [ "expect-test", + "memchr", "unicode-properties", "unicode-xid", ] @@ -3924,15 +3960,15 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", "rustc_fluent_macro", "rustc_hir", - "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_macros", @@ -3942,7 +3978,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", + "smallvec", "tracing", "unicode-security", ] @@ -3951,6 +3987,7 @@ dependencies = [ name = "rustc_lint_defs" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_error_messages", @@ -3958,7 +3995,6 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", - "rustc_target", "serde", ] @@ -3974,7 +4010,6 @@ dependencies = [ name = "rustc_log" version = "0.0.0" dependencies = [ - "rustc_span", "tracing", "tracing-core", "tracing-subscriber", @@ -3987,7 +4022,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", "synstructure", ] @@ -3995,11 +4030,13 @@ dependencies = [ name = "rustc_metadata" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", + "libc", "libloading", "odht", + "rustc_abi", "rustc_ast", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_expand", @@ -4015,8 +4052,6 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "rustc_type_ir", - "snap", "tempfile", "tracing", ] @@ -4025,10 +4060,8 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", - "derive-where", + "bitflags", "either", - "field-offset", "gsgdt", "polonius-engine", "rustc-rayon-core", @@ -4037,16 +4070,18 @@ dependencies = [ "rustc_arena", "rustc_ast", "rustc_ast_ir", - "rustc_attr", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_error_messages", "rustc_errors", "rustc_feature", "rustc_fluent_macro", "rustc_graphviz", + "rustc_hashes", "rustc_hir", "rustc_hir_pretty", "rustc_index", + "rustc_lint_defs", "rustc_macros", "rustc_query_system", "rustc_serialize", @@ -4063,8 +4098,8 @@ dependencies = [ name = "rustc_mir_build" version = "0.0.0" dependencies = [ - "either", "itertools", + "rustc_abi", "rustc_apfloat", "rustc_arena", "rustc_ast", @@ -4080,7 +4115,6 @@ dependencies = [ "rustc_pattern_analysis", "rustc_session", "rustc_span", - "rustc_target", "rustc_trait_selection", "tracing", ] @@ -4091,6 +4125,7 @@ version = "0.0.0" dependencies = [ "polonius-engine", "regex", + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4101,7 +4136,6 @@ dependencies = [ "rustc_macros", "rustc_middle", "rustc_span", - "rustc_target", "smallvec", "tracing", ] @@ -4112,9 +4146,10 @@ version = "0.0.0" dependencies = [ "either", "itertools", + "rustc_abi", "rustc_arena", "rustc_ast", - "rustc_attr", + "rustc_attr_parsing", "rustc_const_eval", "rustc_data_structures", "rustc_errors", @@ -4130,7 +4165,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "smallvec", "tracing", ] @@ -4139,6 +4173,9 @@ dependencies = [ name = "rustc_monomorphize" version = "0.0.0" dependencies = [ + "rustc_abi", + "rustc_ast", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4147,6 +4184,7 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", + "rustc_symbol_mangling", "rustc_target", "serde", "serde_json", @@ -4157,9 +4195,7 @@ dependencies = [ name = "rustc_next_trait_solver" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", "derive-where", - "rustc_ast_ir", "rustc_data_structures", "rustc_index", "rustc_macros", @@ -4173,7 +4209,8 @@ dependencies = [ name = "rustc_parse" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", + "rustc-literal-escaper", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -4196,6 +4233,7 @@ dependencies = [ name = "rustc_parse_format" version = "0.0.0" dependencies = [ + "rustc-literal-escaper", "rustc_index", "rustc_lexer", ] @@ -4204,9 +4242,11 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", + "rustc_ast_lowering", "rustc_ast_pretty", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_expand", @@ -4214,7 +4254,6 @@ dependencies = [ "rustc_fluent_macro", "rustc_hir", "rustc_index", - "rustc_lexer", "rustc_macros", "rustc_middle", "rustc_privacy", @@ -4229,7 +4268,8 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", + "rustc_abi", "rustc_apfloat", "rustc_arena", "rustc_data_structures", @@ -4241,7 +4281,6 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", - "rustc_target", "smallvec", "tracing", "tracing-subscriber", @@ -4253,7 +4292,7 @@ name = "rustc_privacy" version = "0.0.0" dependencies = [ "rustc_ast", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4270,10 +4309,9 @@ dependencies = [ name = "rustc_query_impl" version = "0.0.0" dependencies = [ - "field-offset", "measureme", "rustc_data_structures", - "rustc_errors", + "rustc_hashes", "rustc_hir", "rustc_index", "rustc_middle", @@ -4281,7 +4319,6 @@ dependencies = [ "rustc_serialize", "rustc_session", "rustc_span", - "thin-vec", "tracing", ] @@ -4289,22 +4326,24 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ + "hashbrown", "parking_lot", "rustc-rayon-core", + "rustc_abi", "rustc_ast", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_feature", "rustc_fluent_macro", + "rustc_hashes", "rustc_hir", "rustc_index", "rustc_macros", "rustc_serialize", "rustc_session", "rustc_span", - "rustc_target", "smallvec", - "thin-vec", "tracing", ] @@ -4312,19 +4351,19 @@ dependencies = [ name = "rustc_resolve" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", + "itertools", "pulldown-cmark 0.11.3", "rustc_arena", "rustc_ast", "rustc_ast_pretty", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_expand", "rustc_feature", "rustc_fluent_macro", "rustc_hir", - "rustc_index", "rustc_macros", "rustc_metadata", "rustc_middle", @@ -4340,7 +4379,8 @@ dependencies = [ name = "rustc_sanitizers" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", + "rustc_abi", "rustc_data_structures", "rustc_hir", "rustc_middle", @@ -4356,6 +4396,7 @@ name = "rustc_serialize" version = "0.0.0" dependencies = [ "indexmap", + "rustc_hashes", "rustc_macros", "smallvec", "tempfile", @@ -4366,15 +4407,18 @@ dependencies = [ name = "rustc_session" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "getopts", "libc", + "rand 0.9.0", + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_feature", "rustc_fluent_macro", "rustc_fs_util", + "rustc_hashes", "rustc_hir", "rustc_lint_defs", "rustc_macros", @@ -4384,7 +4428,7 @@ dependencies = [ "smallvec", "termize", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -4392,16 +4436,15 @@ name = "rustc_smir" version = "0.0.0" dependencies = [ "rustc_abi", - "rustc_ast", - "rustc_ast_pretty", "rustc_data_structures", "rustc_hir", + "rustc_hir_pretty", "rustc_middle", "rustc_session", "rustc_span", "rustc_target", "scoped-tls", - "stable_mir", + "serde", "tracing", ] @@ -4416,6 +4459,7 @@ dependencies = [ "md-5", "rustc_arena", "rustc_data_structures", + "rustc_hashes", "rustc_index", "rustc_macros", "rustc_serialize", @@ -4432,13 +4476,14 @@ version = "0.0.0" dependencies = [ "punycode", "rustc-demangle", + "rustc_abi", "rustc_data_structures", "rustc_errors", + "rustc_hashes", "rustc_hir", "rustc_middle", "rustc_session", "rustc_span", - "rustc_target", "tracing", ] @@ -4446,13 +4491,11 @@ dependencies = [ name = "rustc_target" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", - "object 0.36.4", + "bitflags", + "object 0.36.7", "rustc_abi", "rustc_data_structures", - "rustc_feature", "rustc_fs_util", - "rustc_index", "rustc_macros", "rustc_serialize", "rustc_span", @@ -4462,24 +4505,22 @@ dependencies = [ [[package]] name = "rustc_tools_util" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f" +version = "0.4.2" [[package]] name = "rustc_tools_util" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3316159ab19e19d1065ecc49278e87f767a9dae9fae80348d2b4d4fa4ae02d4d" +checksum = "a3b75158011a63889ba12084cf1224baad7bcad50f6ee7c842f772b74aa148ed" [[package]] name = "rustc_trait_selection" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_ast", - "rustc_ast_ir", - "rustc_attr", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4489,11 +4530,8 @@ dependencies = [ "rustc_middle", "rustc_next_trait_solver", "rustc_parse_format", - "rustc_query_system", - "rustc_serialize", "rustc_session", "rustc_span", - "rustc_target", "rustc_transmute", "rustc_type_ir", "smallvec", @@ -4519,14 +4557,11 @@ name = "rustc_transmute" version = "0.0.0" dependencies = [ "itertools", - "rustc_ast_ir", + "rustc_abi", "rustc_data_structures", "rustc_hir", - "rustc_infer", - "rustc_macros", "rustc_middle", "rustc_span", - "rustc_target", "tracing", ] @@ -4536,10 +4571,10 @@ version = "0.0.0" dependencies = [ "itertools", "rustc_abi", - "rustc_ast_ir", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", + "rustc_hashes", "rustc_hir", "rustc_index", "rustc_infer", @@ -4549,7 +4584,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "tracing", ] @@ -4557,8 +4591,9 @@ dependencies = [ name = "rustc_type_ir" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "derive-where", + "ena", "indexmap", "rustc-hash 1.1.0", "rustc_ast_ir", @@ -4579,7 +4614,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", "synstructure", ] @@ -4597,17 +4632,19 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "arrayvec", + "askama", "base64", "expect-test", "indexmap", "itertools", "minifier", "pulldown-cmark 0.9.6", + "pulldown-cmark-escape", "regex", - "rinja", "rustdoc-json-types", "serde", "serde_json", + "sha2", "smallvec", "tempfile", "threadpool", @@ -4622,6 +4659,7 @@ name = "rustdoc-gui-test" version = "0.1.0" dependencies = [ "build_helper", + "camino", "compiletest", "getopts", "walkdir", @@ -4632,7 +4670,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "serde", "serde_json", ] @@ -4656,7 +4694,7 @@ checksum = "81864b097046da5df3758fdc6e4822bbb70afa06317e8ca45ea1b51cb8c5e5a4" dependencies = [ "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -4667,7 +4705,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] @@ -4677,7 +4715,7 @@ dependencies = [ "annotate-snippets 0.9.2", "anyhow", "bytecount", - "cargo_metadata", + "cargo_metadata 0.18.1", "clap", "clap-cargo", "diff", @@ -4690,7 +4728,7 @@ dependencies = [ "serde", "serde_json", "term", - "thiserror", + "thiserror 1.0.69", "toml 0.7.8", "tracing", "tracing-subscriber", @@ -4701,37 +4739,37 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ruzstd" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c3938e133aac070997ddc684d4b393777d293ba170f2988c8fd5ea2ad4ce21" +checksum = "fad02996bfc73da3e301efe90b1837be9ed8f4a462b6ed410aa35d00381de89f" dependencies = [ "twox-hash", ] [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -4744,9 +4782,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -4769,51 +4807,50 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" dependencies = [ - "self_cell 1.0.4", + "self_cell 1.2.0", ] [[package]] name = "self_cell" -version = "1.0.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.210" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap", "itoa", "memchr", "ryu", @@ -4874,15 +4911,15 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "similar" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" @@ -4895,21 +4932,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "snap" -version = "1.1.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4927,9 +4958,9 @@ dependencies = [ [[package]] name = "spdx" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" +checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193" dependencies = [ "smallvec", ] @@ -4942,7 +4973,7 @@ checksum = "53d7ac03c67c572d85049d6db815e20a4a19b41b3d5cca732ac582342021ad77" dependencies = [ "nom", "serde", - "thiserror", + "thiserror 1.0.69", "tracing", ] @@ -4959,7 +4990,7 @@ dependencies = [ "spdx-expression", "strum", "strum_macros", - "thiserror", + "thiserror 1.0.69", "uuid", ] @@ -4973,15 +5004,14 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "stable_mir" version = "0.1.0-preview" dependencies = [ - "scoped-tls", - "serde", + "rustc_smir", ] [[package]] name = "stacker" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" +checksum = "601f9201feb9b09c00266478bf459952b9ef9a6b94edb2f21eba14ab681a60a9" dependencies = [ "cc", "cfg-if", @@ -4998,26 +5028,25 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_cache" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", - "once_cell", "parking_lot", - "phf_shared 0.10.0", + "phf_shared", "precomputed-hash", "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -5068,9 +5097,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -5085,7 +5114,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] @@ -5096,7 +5125,7 @@ checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ "core-foundation-sys", "libc", - "windows", + "windows 0.57.0", ] [[package]] @@ -5111,9 +5140,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.42" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", @@ -5122,12 +5151,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.2", "once_cell", "rustix", "windows-sys 0.59.0", @@ -5164,16 +5193,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "terminal_size" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" -dependencies = [ - "rustix", - "windows-sys 0.48.0", -] - [[package]] name = "termize" version = "0.1.1" @@ -5190,46 +5209,66 @@ version = "0.1.0" dependencies = [ "indicatif", "num", - "rand", - "rand_chacha", + "rand 0.9.0", + "rand_chacha 0.9.0", "rayon", ] [[package]] name = "thin-vec" -version = "0.2.13" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d" + +[[package]] +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] [[package]] name = "thiserror" -version = "1.0.64" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "thorin-dwp" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "813ba76597db32dc4f6992fd8bf8f394715b88d352fd97401da67dab6283b4c6" +checksum = "9e9c1e705f82a260173f3eec93f2ff6d7807f23ad5a8cc2e7316a891733ea7a1" dependencies = [ - "gimli 0.30.0", + "gimli 0.31.1", "hashbrown", - "object 0.36.4", + "object 0.36.7", "tracing", ] @@ -5257,15 +5296,17 @@ name = "tidy" version = "0.1.0" dependencies = [ "build_helper", - "cargo_metadata", + "cargo_metadata 0.19.2", "fluent-syntax", "ignore", "miropt-test-tools", "regex", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "semver", + "serde", "similar", "termcolor", + "toml 0.7.8", "walkdir", ] @@ -5274,34 +5315,13 @@ name = "tier-check" version = "0.1.0" [[package]] -name = "time" -version = "0.3.36" +name = "tikv-jemalloc-sys" +version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d" dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", + "cc", + "libc", ] [[package]] @@ -5316,9 +5336,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -5331,9 +5351,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", @@ -5380,15 +5400,9 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] -[[package]] -name = "topological-sort" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" - [[package]] name = "tracing" version = "0.1.37" @@ -5403,13 +5417,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] @@ -5424,9 +5438,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -5481,7 +5495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", - "rand", + "rand 0.8.5", "static_assertions", ] @@ -5496,9 +5510,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ucd-parse" @@ -5511,21 +5525,21 @@ dependencies = [ [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "ui_test" -version = "0.26.5" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ee4c40e5a5f9fa6864ff976473e5d6a6e9884b6ce68b40690d9f87e1994c83" +checksum = "1211b1111c752c73b33073d2958072be08825fd97c9ab4d83444da361a06634b" dependencies = [ - "annotate-snippets 0.11.4", + "annotate-snippets 0.11.5", "anyhow", "bstr", "cargo-platform", - "cargo_metadata", + "cargo_metadata 0.18.1", "color-eyre", "colored", "comma", @@ -5580,37 +5594,21 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.79", + "syn 2.0.100", "unic-langid-impl", ] [[package]] name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bdd" -version = "0.1.0" -dependencies = [ - "ucd-parse", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" @@ -5623,9 +5621,9 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-script" @@ -5649,6 +5647,13 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-table-generator" +version = "0.1.0" +dependencies = [ + "ucd-parse", +] + [[package]] name = "unicode-width" version = "0.1.14" @@ -5686,9 +5691,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -5701,12 +5706,24 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -5715,18 +5732,18 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom", + "getrandom 0.3.2", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -5756,43 +5773,52 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasi-preview1-component-adapter-provider" -version = "24.0.0" +version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e6cadfa74538edd5409b6f8c79628436529138e9618b7373bec7aae7805835" +checksum = "dcd9f21bbde82ba59e415a8725e6ad0d0d7e9e460b1a3ccbca5bdee952c1a324" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5800,36 +5826,42 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-component-ld" -version = "0.5.10" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4aa6bd7fbe7cffbed29fe3e236fda74419def1bdef6f80f989ec51137edf44" +checksum = "580305a8e3f1b7a79859a8db897de643533b2851c5eb080fe5800233f16dec88" dependencies = [ "anyhow", "clap", "lexopt", + "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.219.0", + "wasmparser 0.223.1", "wat", + "windows-sys 0.59.0", + "winsplit", "wit-component", "wit-parser", ] @@ -5843,28 +5875,39 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.216.0" +version = "0.219.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c23aebea22c8a75833ae08ed31ccc020835b12a41999e58c31464271b94a88" +checksum = "8aa79bcd666a043b58f5fa62b221b0b914dd901e6f620e8ab7371057a797f3e1" dependencies = [ "leb128", + "wasmparser 0.219.2", ] [[package]] name = "wasm-encoder" -version = "0.219.0" +version = "0.223.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b1b95711b3ad655656a341e301cc64e33cbee94de9a99a1c5a2ab88efab79d" +checksum = "7a0a96fdeaee8fbeb4bd917fb8157d48c0d61c3b1f4ee4c363c8e8d68b2f4fe8" dependencies = [ "leb128", - "wasmparser 0.219.0", + "wasmparser 0.223.1", +] + +[[package]] +name = "wasm-encoder" +version = "0.228.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d30290541f2d4242a162bbda76b8f2d8b1ac59eab3568ed6f2327d52c9b2c4" +dependencies = [ + "leb128fmt", + "wasmparser 0.228.0", ] [[package]] name = "wasm-metadata" -version = "0.219.0" +version = "0.223.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96132fe00dd17d092d2be289eeed5a0a68ad3cf30b68e8875bc953b96f55f0be" +checksum = "e2e7e37883181704d96b89dbd8f1291be13694c71cd0663aebb94b46d235a377" dependencies = [ "anyhow", "indexmap", @@ -5872,56 +5915,86 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.219.0", - "wasmparser 0.219.0", + "url", + "wasm-encoder 0.223.1", + "wasmparser 0.223.1", ] [[package]] name = "wasmparser" -version = "0.216.0" +version = "0.219.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcdee6bea3619d311fb4b299721e89a986c3470f804b6d534340e412589028e3" +checksum = "5220ee4c6ffcc0cb9d7c47398052203bc902c8ef3985b0c8134118440c0b2921" dependencies = [ - "bitflags 2.6.0", + "bitflags", "indexmap", ] [[package]] name = "wasmparser" -version = "0.219.0" +version = "0.222.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa210fd1788e6b37a1d1930f3389c48e1d6ebd1a013d34fa4b7f9e3e3bf03146" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wasmparser" +version = "0.223.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324b4e56d24439495b88cd81439dad5e97f3c7b1eedc3c7e10455ed1e045e9a2" +checksum = "664b980991ed9a8c834eb528a8979ab1109edcf52dc05dd5751e2cc3fb31035d" dependencies = [ - "ahash", - "bitflags 2.6.0", + "bitflags", "hashbrown", "indexmap", "semver", "serde", ] +[[package]] +name = "wasmparser" +version = "0.228.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" +dependencies = [ + "bitflags", + "indexmap", + "semver", +] + [[package]] name = "wast" -version = "219.0.0" +version = "228.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06880ecb25662bc21db6a83f4fcc27c41f71fbcba4f1980b650c88ada92728e1" +checksum = "9e5aae124478cb51439f6587f074a3a5e835afd22751c59a87b2e2a882727c97" dependencies = [ "bumpalo", - "leb128", + "leb128fmt", "memchr", - "unicode-width 0.1.14", - "wasm-encoder 0.219.0", + "unicode-width 0.2.0", + "wasm-encoder 0.228.0", ] [[package]] name = "wat" -version = "1.219.0" +version = "1.228.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11e56dbf9fc89111b0d97c91e683d7895b1a6e5633a729f2ccad2303724005b6" +checksum = "7ec29c89a8d055df988de7236483bf569988ac3d6905899f6af5ef920f9385ad" dependencies = [ "wast", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -5963,39 +6036,63 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +dependencies = [ + "windows-core 0.59.0", + "windows-targets 0.53.0", +] + [[package]] name = "windows-bindgen" -version = "0.58.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cd28d93c692351f3a6e5615567c56756e330bee1c99c6bdd57bfc5ab15f589" +checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90" dependencies = [ - "proc-macro2", "rayon", "serde", "serde_json", - "syn 2.0.79", - "windows-metadata", ] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.57.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-targets 0.52.6", + "windows-implement 0.59.0", + "windows-interface 0.59.1", + "windows-result 0.3.2", + "windows-strings 0.3.1", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.2", + "windows-strings 0.4.0", ] [[package]] @@ -6006,7 +6103,29 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", +] + +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] @@ -6017,14 +6136,25 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] -name = "windows-metadata" -version = "0.58.0" +name = "windows-link" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e837f3c3012cfe9e7086302a93f441a7999439be1ad4c530d55d2f6d2921809" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-result" @@ -6035,6 +6165,33 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6086,13 +6243,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -6105,6 +6278,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -6117,6 +6296,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -6129,12 +6314,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -6147,6 +6344,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -6159,6 +6362,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -6171,6 +6380,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -6183,6 +6398,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.5.40" @@ -6192,30 +6413,54 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +dependencies = [ + "memchr", +] + +[[package]] +name = "winsplit" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab703352da6a72f35c39a533526393725640575bb211f61987a2748323ad956" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + [[package]] name = "wit-component" -version = "0.219.0" +version = "0.223.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a76111c20444a814019de20499d30940ecd219b9512ee296f034a5edb18a2d" +checksum = "3fc2fcc52a79f6f010a89c867e53e06d4227f86c58984add3e37f32b8e7af5f0" dependencies = [ "anyhow", - "bitflags 2.6.0", + "bitflags", "indexmap", "log", "serde", "serde_derive", "serde_json", - "wasm-encoder 0.219.0", + "wasm-encoder 0.223.1", "wasm-metadata", - "wasmparser 0.219.0", + "wasmparser 0.223.1", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.219.0" +version = "0.223.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23102e180c0c464f36e293d31a27b524e3ece930d7b5527d2f33f9d2c963de64" +checksum = "263fde17f1fbe55a413f16eb59094bf751795c6da469a05c3d45ea6c77df6b40" dependencies = [ "anyhow", "id-arena", @@ -6226,23 +6471,32 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.219.0", + "wasmparser 0.223.1", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "x" +version = "0.1.1" + [[package]] name = "xattr" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "linux-raw-sys", "rustix", ] @@ -6266,9 +6520,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -6278,55 +6532,54 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", "synstructure", ] @@ -6349,5 +6602,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.100", ] diff --git a/Cargo.toml b/Cargo.toml index d4b84250fc469..16ff0f61593ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,49 +1,53 @@ [workspace] resolver = "2" members = [ +# tidy-alphabetical-start "compiler/rustc", + "src/build_helper", "src/etc/test-float-parse", + "src/rustc-std-workspace/rustc-std-workspace-alloc", + "src/rustc-std-workspace/rustc-std-workspace-core", + "src/rustc-std-workspace/rustc-std-workspace-std", "src/rustdoc-json-types", - "src/tools/build_helper", + "src/tools/build-manifest", + "src/tools/bump-stage0", "src/tools/cargotest", "src/tools/clippy", "src/tools/clippy/clippy_dev", + "src/tools/collect-license-metadata", "src/tools/compiletest", - "src/tools/run-make-support", - "src/tools/error_index_generator", + "src/tools/coverage-dump", + "src/tools/features-status-dump", + "src/tools/generate-copyright", + "src/tools/generate-windows-sys", + "src/tools/html-checker", + "src/tools/jsondocck", + "src/tools/jsondoclint", "src/tools/linkchecker", "src/tools/lint-docs", + "src/tools/lld-wrapper", + "src/tools/llvm-bitcode-linker", + "src/tools/miri", + "src/tools/miri/cargo-miri", "src/tools/miropt-test-tools", - "src/tools/unstable-book-gen", - "src/tools/tidy", - "src/tools/tier-check", - "src/tools/build-manifest", + "src/tools/opt-dist", "src/tools/remote-test-client", "src/tools/remote-test-server", + "src/tools/replace-version-placeholder", + "src/tools/run-make-support", "src/tools/rust-installer", "src/tools/rustdoc", - "src/tools/rls", - "src/tools/rustfmt", - "src/tools/miri", - "src/tools/miri/cargo-miri", + "src/tools/rustdoc-gui-test", "src/tools/rustdoc-themes", - "src/tools/unicode-table-generator", - "src/tools/jsondocck", - "src/tools/jsondoclint", - "src/tools/llvm-bitcode-linker", - "src/tools/html-checker", - "src/tools/bump-stage0", - "src/tools/replace-version-placeholder", - "src/tools/lld-wrapper", - "src/tools/collect-license-metadata", - "src/tools/generate-copyright", + "src/tools/rustfmt", "src/tools/suggest-tests", - "src/tools/generate-windows-sys", - "src/tools/rustdoc-gui-test", - "src/tools/opt-dist", - "src/tools/coverage-dump", - "src/tools/rustc-perf-wrapper", + "src/tools/tidy", + "src/tools/tier-check", + "src/tools/unicode-table-generator", + "src/tools/unstable-book-gen", "src/tools/wasm-component-ld", + "src/tools/x", +# tidy-alphabetical-end ] exclude = [ @@ -54,11 +58,6 @@ exclude = [ "tests/rustdoc-gui", # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`. "obj", - # The `x` binary is a thin wrapper that calls `x.py`, which initializes - # submodules, before which workspace members cannot be invoked because - # not all `Cargo.toml` files are available, so we exclude the `x` binary, - # so it can be invoked before the current checkout is set up. - "src/tools/x", ] [profile.release.package.rustc-rayon-core] diff --git a/INSTALL.md b/INSTALL.md index 74fcc58348b43..30e08201d6dfb 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -6,9 +6,9 @@ If you just want to install Rust, check out the [README.md](README.md) instead.* The Rust build system uses a Python script called `x.py` to build the compiler, which manages the bootstrapping process. It lives at the root of the project. -It also uses a file named `config.toml` to determine various configuration +It also uses a file named `bootstrap.toml` to determine various configuration settings for the build. You can see a full list of options in -`config.example.toml`. +`bootstrap.example.toml`. The `x.py` command can be run directly on most Unix systems in the following format: @@ -115,7 +115,7 @@ See [the rustc-dev-guide for more info][sysllvm]. This project provides a configure script and makefile (the latter of which just invokes `x.py`). `./configure` is the recommended way to programmatically -generate a `config.toml`. `make` is not recommended (we suggest using `x.py` +generate a `bootstrap.toml`. `make` is not recommended (we suggest using `x.py` directly), but it is supported and we try not to break it unnecessarily. ```sh @@ -123,7 +123,7 @@ directly), but it is supported and we try not to break it unnecessarily. make && sudo make install ``` -`configure` generates a `config.toml` which can also be used with normal `x.py` +`configure` generates a `bootstrap.toml` which can also be used with normal `x.py` invocations. ## Building on Windows @@ -210,9 +210,13 @@ itself back on after some time). ### MSVC -MSVC builds of Rust additionally require an installation of Visual Studio 2017 -(or later) so `rustc` can use its linker. The simplest way is to get -[Visual Studio], check the "C++ build tools" and "Windows 10 SDK" workload. +MSVC builds of Rust additionally requires an installation of: + +- Visual Studio 2022 (or later) build tools so `rustc` can use its linker. Older + Visual Studio versions such as 2019 *may* work but aren't actively tested. +- A recent Windows 10 or 11 SDK. + +The simplest way is to get [Visual Studio], check the "C++ build tools". [Visual Studio]: https://visualstudio.microsoft.com/downloads/ @@ -251,7 +255,7 @@ Windows build triples are: - `x86_64-pc-windows-msvc` The build triple can be specified by either specifying `--build=<triple>` when -invoking `x.py` commands, or by creating a `config.toml` file (as described in +invoking `x.py` commands, or by creating a `bootstrap.toml` file (as described in [Building on a Unix-like system](#building-on-a-unix-like-system)), and passing `--set build.build=<triple>` to `./configure`. diff --git a/LICENSE-MIT b/LICENSE-MIT index 31aa79387f27e..a2070c4be7acd 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,3 +1,5 @@ +Copyright (c) The Rust Project Contributors + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the diff --git a/LICENSES/Unicode-3.0.txt b/LICENSES/Unicode-3.0.txt new file mode 100644 index 0000000000000..ee8e69b233293 --- /dev/null +++ b/LICENSES/Unicode-3.0.txt @@ -0,0 +1,39 @@ +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2024 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. diff --git a/LICENSES/Unicode-DFS-2016.txt b/LICENSES/Unicode-DFS-2016.txt deleted file mode 100644 index 71fd6ac5e12e1..0000000000000 --- a/LICENSES/Unicode-DFS-2016.txt +++ /dev/null @@ -1,22 +0,0 @@ -UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE - -Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/. - -Unicode Data Files do not include PDF online code charts under the directory http://www.unicode.org/Public/. - -Software includes any source code published in the Unicode Standard or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/. - -NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. - -COPYRIGHT AND PERMISSION NOTICE - -Copyright © 1991-2016 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. - -Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either - - (a) this copyright and permission notice appear with all copies of the Data Files or Software, or - (b) this copyright and permission notice appear in associated Documentation. - -THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. diff --git a/README.md b/README.md index 3690a9c93c528..611260470f12b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ standard library, and documentation. ## Why Rust? -- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrate with other languages. +- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrated with other languages. - **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time. @@ -67,11 +67,11 @@ See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and trademarks and logos (the "Rust Trademarks"). If you want to use these names or brands, please read the -[media guide][media-guide]. +[Rust language trademark policy][trademark-policy]. Third-party logos may be subject to third-party copyrights and trademarks. See [Licenses][policies-licenses] for details. -[rust-foundation]: https://foundation.rust-lang.org/ -[media-guide]: https://foundation.rust-lang.org/policies/logo-policy-and-media-guide/ +[rust-foundation]: https://rustfoundation.org/ +[trademark-policy]: https://rustfoundation.org/policy/rust-trademark-policy/ [policies-licenses]: https://www.rust-lang.org/policies/licenses diff --git a/RELEASES.md b/RELEASES.md index ac72a1d885cbc..0948eb85192e5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,630 @@ +Version 1.86.0 (2025-04-03) +========================== + +<a id="1.86.0-Language"></a> + +Language +-------- +- [Stabilize upcasting trait objects to supertraits.](https://github.com/rust-lang/rust/pull/134367) +- [Allow safe functions to be marked with the `#[target_feature]` attribute.](https://github.com/rust-lang/rust/pull/134090) +- [The `missing_abi` lint now warns-by-default.](https://github.com/rust-lang/rust/pull/132397) +- Rust now lints about double negations, to catch cases that might have intended to be a prefix decrement operator (`--x`) as written in other languages. This was previously a clippy lint, `clippy::double_neg`, and is [now available directly in Rust as `double_negations`.](https://github.com/rust-lang/rust/pull/126604) +- [More pointers are now detected as definitely not-null based on their alignment in const eval.](https://github.com/rust-lang/rust/pull/133700) +- [Empty `repr()` attribute applied to invalid items are now correctly rejected.](https://github.com/rust-lang/rust/pull/133925) +- [Inner attributes `#![test]` and `#![rustfmt::skip]` are no longer accepted in more places than intended.](https://github.com/rust-lang/rust/pull/134276) + +<a id="1.86.0-Compiler"></a> + +Compiler +-------- +- [Debug-assert that raw pointers are non-null on access.](https://github.com/rust-lang/rust/pull/134424) +- [Change `-O` to mean `-C opt-level=3` instead of `-C opt-level=2` to match Cargo's defaults.](https://github.com/rust-lang/rust/pull/135439) +- [Fix emission of `overflowing_literals` under certain macro environments.](https://github.com/rust-lang/rust/pull/136393) + +<a id="1.86.0-Platform-Support"></a> + +Platform Support +---------------- +- [Replace `i686-unknown-redox` target with `i586-unknown-redox`.](https://github.com/rust-lang/rust/pull/136698) +- [Increase baseline CPU of `i686-unknown-hurd-gnu` to Pentium 4.](https://github.com/rust-lang/rust/pull/136700) +- New tier 3 targets: + - [`{aarch64-unknown,x86_64-pc}-nto-qnx710_iosock`](https://github.com/rust-lang/rust/pull/133631). + For supporting Neutrino QNX 7.1 with `io-socket` network stack. + - [`{aarch64-unknown,x86_64-pc}-nto-qnx800`](https://github.com/rust-lang/rust/pull/133631). + For supporting Neutrino QNX 8.0 (`no_std`-only). + - [`{x86_64,i686}-win7-windows-gnu`](https://github.com/rust-lang/rust/pull/134609). + Intended for backwards compatibility with Windows 7. `{x86_64,i686}-win7-windows-msvc` are the Windows MSVC counterparts that already exist as Tier 3 targets. + - [`amdgcn-amd-amdhsa`](https://github.com/rust-lang/rust/pull/134740). + - [`x86_64-pc-cygwin`](https://github.com/rust-lang/rust/pull/134999). + - [`{mips,mipsel}-mti-none-elf`](https://github.com/rust-lang/rust/pull/135074). + Initial bare-metal support. + - [`m68k-unknown-none-elf`](https://github.com/rust-lang/rust/pull/135085). + - [`armv7a-nuttx-{eabi,eabihf}`, `aarch64-unknown-nuttx`, and `thumbv7a-nuttx-{eabi,eabihf}`](https://github.com/rust-lang/rust/pull/135757). + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +<a id="1.86.0-Libraries"></a> + +Libraries +--------- +- The type of `FromBytesWithNulError` in `CStr::from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError>` was [changed from an opaque struct to an enum](https://github.com/rust-lang/rust/pull/134143), allowing users to examine why the conversion failed. +- [Remove `RustcDecodable` and `RustcEncodable`.](https://github.com/rust-lang/rust/pull/134272) +- [Deprecate libtest's `--logfile` option.](https://github.com/rust-lang/rust/pull/134283) +- [On recent versions of Windows, `std::fs::remove_file` will now remove read-only files.](https://github.com/rust-lang/rust/pull/134679) + +<a id="1.86.0-Stabilized-APIs"></a> + +Stabilized APIs +--------------- + +- [`{float}::next_down`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.next_down) +- [`{float}::next_up`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.next_up) +- [`<[_]>::get_disjoint_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.get_disjoint_mut) +- [`<[_]>::get_disjoint_unchecked_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.get_disjoint_unchecked_mut) +- [`slice::GetDisjointMutError`](https://doc.rust-lang.org/stable/std/slice/enum.GetDisjointMutError.html) +- [`HashMap::get_disjoint_mut`](https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.get_disjoint_mut) +- [`HashMap::get_disjoint_unchecked_mut`](https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.get_disjoint_unchecked_mut) +- [`NonZero::count_ones`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.count_ones) +- [`Vec::pop_if`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.pop_if) +- [`sync::Once::wait`](https://doc.rust-lang.org/stable/std/sync/struct.Once.html#method.wait) +- [`sync::Once::wait_force`](https://doc.rust-lang.org/stable/std/sync/struct.Once.html#method.wait_force) +- [`sync::OnceLock::wait`](https://doc.rust-lang.org/stable/std/sync/struct.OnceLock.html#method.wait) + +These APIs are now stable in const contexts: + +- [`hint::black_box`](https://doc.rust-lang.org/stable/std/hint/fn.black_box.html) +- [`io::Cursor::get_mut`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.get_mut) +- [`io::Cursor::set_position`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.set_position) +- [`str::is_char_boundary`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.is_char_boundary) +- [`str::split_at`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at) +- [`str::split_at_checked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_checked) +- [`str::split_at_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_mut) +- [`str::split_at_mut_checked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_mut_checked) + +<a id="1.86.0-Cargo"></a> + +Cargo +----- +- [When merging, replace rather than combine configuration keys that refer to a program path and its arguments.](https://github.com/rust-lang/cargo/pull/15066/) +- [Error if both `--package` and `--workspace` are passed but the requested package is missing.](https://github.com/rust-lang/cargo/pull/15071/) This was previously silently ignored, which was considered a bug since missing packages should be reported. +- [Deprecate the token argument in `cargo login` to avoid shell history leaks.](https://github.com/rust-lang/cargo/pull/15057/) +- [Simplify the implementation of `SourceID` comparisons.](https://github.com/rust-lang/cargo/pull/14980/) This may potentially change behavior if the canonicalized URL compares differently in alternative registries. + +<a id="1.86.0-Rustdoc"></a> + +Rustdoc +----- +- [Add a sans-serif font setting.](https://github.com/rust-lang/rust/pull/133636) + +<a id="1.86.0-Compatibility-Notes"></a> + +Compatibility Notes +------------------- +- [The `wasm_c_abi` future compatibility warning is now a hard error.](https://github.com/rust-lang/rust/pull/133951) + Users of `wasm-bindgen` should upgrade to at least version 0.2.89, otherwise compilation will fail. +- [Remove long-deprecated no-op attributes `#![no_start]` and `#![crate_id]`.](https://github.com/rust-lang/rust/pull/134300) +- [The future incompatibility lint `cenum_impl_drop_cast` has been made into a hard error.](https://github.com/rust-lang/rust/pull/135964) This means it is now an error to cast a field-less enum to an integer if the enum implements `Drop`. +- [SSE2 is now required for "i686" 32-bit x86 hard-float targets; disabling it causes a warning that will become a hard error eventually.](https://github.com/rust-lang/rust/pull/137037) + To compile for pre-SSE2 32-bit x86, use a "i586" target instead. + +<a id="1.86.0-Internal-Changes"></a> + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Build the rustc on AArch64 Linux with ThinLTO + PGO.](https://github.com/rust-lang/rust/pull/133807) + The ARM 64-bit compiler (AArch64) on Linux is now optimized with ThinLTO and PGO, similar to the optimizations we have already performed for the x86-64 compiler on Linux. This should make it up to 30% faster. + + +Version 1.85.1 (2025-03-18) +========================== + +<a id="1.85.1"></a> + +- [Fix the doctest-merging feature of the 2024 Edition.](https://github.com/rust-lang/rust/pull/137899/) +- [Relax some `target_feature` checks when generating docs.](https://github.com/rust-lang/rust/pull/137632/) +- [Fix errors in `std::fs::rename` on Windows 10, version 1607.](https://github.com/rust-lang/rust/pull/137528/) +- [Downgrade bootstrap `cc` to fix custom targets.](https://github.com/rust-lang/rust/pull/137460/) +- [Skip submodule updates when building Rust from a source tarball.](https://github.com/rust-lang/rust/pull/137338/) + +Version 1.85.0 (2025-02-20) +========================== + +<a id="1.85.0-Language"></a> + +Language +-------- +- [The 2024 Edition is now stable.](https://github.com/rust-lang/rust/pull/133349) + See [the edition guide](https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html) for more details. +- [Stabilize async closures](https://github.com/rust-lang/rust/pull/132706) + See [RFC 3668](https://rust-lang.github.io/rfcs/3668-async-closures.html) for more details. +- [Stabilize `#[diagnostic::do_not_recommend]`](https://github.com/rust-lang/rust/pull/132056) +- [Add `unpredictable_function_pointer_comparisons` lint to warn against function pointer comparisons](https://github.com/rust-lang/rust/pull/118833) +- [Lint on combining `#[no_mangle]` and `#[export_name]` attributes.](https://github.com/rust-lang/rust/pull/131558) + +<a id="1.85.0-Compiler"></a> + +Compiler +-------- +- [The unstable flag `-Zpolymorphize` has been removed](https://github.com/rust-lang/rust/pull/133883), see https://github.com/rust-lang/compiler-team/issues/810 for some background. + +<a id="1.85.0-Platform-Support"></a> + +Platform Support +---------------- +- [Promote `powerpc64le-unknown-linux-musl` to tier 2 with host tools](https://github.com/rust-lang/rust/pull/133801) + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +<a id="1.85.0-Libraries"></a> + +Libraries +--------- +- [Panics in the standard library now have a leading `library/` in their path](https://github.com/rust-lang/rust/pull/132390) +- [`std::env::home_dir()` on Windows now ignores the non-standard `$HOME` environment variable](https://github.com/rust-lang/rust/pull/132515) + + It will be un-deprecated in a subsequent release. +- [Add `AsyncFn*` to the prelude in all editions.](https://github.com/rust-lang/rust/pull/132611) + +<a id="1.85.0-Stabilized-APIs"></a> + +Stabilized APIs +--------------- + +- [`BuildHasherDefault::new`](https://doc.rust-lang.org/stable/std/hash/struct.BuildHasherDefault.html#method.new) +- [`ptr::fn_addr_eq`](https://doc.rust-lang.org/std/ptr/fn.fn_addr_eq.html) +- [`io::ErrorKind::QuotaExceeded`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.QuotaExceeded) +- [`io::ErrorKind::CrossesDevices`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.CrossesDevices) +- [`{float}::midpoint`](https://doc.rust-lang.org/core/primitive.f32.html#method.midpoint) +- [Unsigned `{integer}::midpoint`](https://doc.rust-lang.org/std/primitive.u64.html#method.midpoint) +- [`NonZeroU*::midpoint`](https://doc.rust-lang.org/std/num/type.NonZeroU32.html#method.midpoint) +- [impl `std::iter::Extend` for tuples with arity 1 through 12](https://doc.rust-lang.org/stable/std/iter/trait.Extend.html#impl-Extend%3C(A,)%3E-for-(EA,)) +- [`FromIterator<(A, ...)>` for tuples with arity 1 through 12](https://doc.rust-lang.org/stable/std/iter/trait.FromIterator.html#impl-FromIterator%3C(EA,)%3E-for-(A,)) +- [`std::task::Waker::noop`](https://doc.rust-lang.org/stable/std/task/struct.Waker.html#method.noop) + +These APIs are now stable in const contexts: + +- [`mem::size_of_val`](https://doc.rust-lang.org/stable/std/mem/fn.size_of_val.html) +- [`mem::align_of_val`](https://doc.rust-lang.org/stable/std/mem/fn.align_of_val.html) +- [`Layout::for_value`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.for_value) +- [`Layout::align_to`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.align_to) +- [`Layout::pad_to_align`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.pad_to_align) +- [`Layout::extend`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.extend) +- [`Layout::array`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.array) +- [`std::mem::swap`](https://doc.rust-lang.org/stable/std/mem/fn.swap.html) +- [`std::ptr::swap`](https://doc.rust-lang.org/stable/std/ptr/fn.swap.html) +- [`NonNull::new`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new) +- [`HashMap::with_hasher`](https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html#method.with_hasher) +- [`HashSet::with_hasher`](https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html#method.with_hasher) +- [`BuildHasherDefault::new`](https://doc.rust-lang.org/stable/std/hash/struct.BuildHasherDefault.html#method.new) +- [`<float>::recip`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.recip) +- [`<float>::to_degrees`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.to_degrees) +- [`<float>::to_radians`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.to_radians) +- [`<float>::max`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.max) +- [`<float>::min`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.min) +- [`<float>::clamp`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.clamp) +- [`<float>::abs`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.abs) +- [`<float>::signum`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.signum) +- [`<float>::copysign`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.copysign) +- [`MaybeUninit::write`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.write) + +<a id="1.85.0-Cargo"></a> + +Cargo +----- +- [Add future-incompatibility warning against keywords in cfgs and add raw-idents](https://github.com/rust-lang/cargo/pull/14671/) +- [Stabilize higher precedence trailing flags](https://github.com/rust-lang/cargo/pull/14900/) +- [Pass `CARGO_CFG_FEATURE` to build scripts](https://github.com/rust-lang/cargo/pull/14902/) + +<a id="1.85.0-Rustdoc"></a> + +Rustdoc +----- +- [Doc comment on impl blocks shows the first line, even when the impl block is collapsed](https://github.com/rust-lang/rust/pull/132155) + +<a id="1.85.0-Compatibility-Notes"></a> + +Compatibility Notes +------------------- +- [`rustc` no longer treats the `test` cfg as a well known check-cfg](https://github.com/rust-lang/rust/pull/131729), instead it is up to the build systems and users of `--check-cfg`[^check-cfg] to set it as a well known cfg using `--check-cfg=cfg(test)`. + + This is done to enable build systems like Cargo to set it conditionally, as not all source files are suitable for unit tests. + [Cargo (for now) unconditionally sets the `test` cfg as a well known cfg](https://github.com/rust-lang/cargo/pull/14963). + [^check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html +- [Disable potentially incorrect type inference if there are trivial and non-trivial where-clauses](https://github.com/rust-lang/rust/pull/132325) +- `std::env::home_dir()` has been deprecated for years, because it can give surprising results in some Windows configurations if the `HOME` environment variable is set (which is not the normal configuration on Windows). We had previously avoided changing its behavior, out of concern for compatibility with code depending on this non-standard configuration. Given how long this function has been deprecated, we're now fixing its behavior as a bugfix. A subsequent release will remove the deprecation for this function. +- [Make `core::ffi::c_char` signedness more closely match that of the platform-default `char`](https://github.com/rust-lang/rust/pull/132975) + + This changed `c_char` from an `i8` to `u8` or vice versa on many Tier 2 and 3 + targets (mostly Arm and RISC-V embedded targets). The new definition may + result in compilation failures but fixes compatibility issues with C. + + The `libc` crate matches this change as of its 0.2.169 release. +- [When compiling a nested `macro_rules` macro from an external crate, the content of the inner `macro_rules` is now built with the edition of the external crate, not the local crate.](https://github.com/rust-lang/rust/pull/133274) +- [Increase `sparcv9-sun-solaris` and `x86_64-pc-solaris` Solaris baseline to 11.4.](https://github.com/rust-lang/rust/pull/133293) +- [Show `abi_unsupported_vector_types` lint in future breakage reports](https://github.com/rust-lang/rust/pull/133374) +- [Error if multiple super-trait instantiations of `dyn Trait` need associated types to be specified but only one is provided](https://github.com/rust-lang/rust/pull/133392) +- [Change `powerpc64-ibm-aix` default `codemodel` to large](https://github.com/rust-lang/rust/pull/133811) + +<a id="1.85.0-Internal-Changes"></a> + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Build `x86_64-unknown-linux-gnu` with LTO for C/C++ code (e.g., `jemalloc`)](https://github.com/rust-lang/rust/pull/134690) + +Version 1.84.1 (2025-01-30) +========================== + +<a id="1.84.1"></a> + +- [Fix ICE 132920 in duplicate-crate diagnostics.](https://github.com/rust-lang/rust/pull/133304/) +- [Fix errors for overlapping impls in incremental rebuilds.](https://github.com/rust-lang/rust/pull/133828/) +- [Fix slow compilation related to the next-generation trait solver.](https://github.com/rust-lang/rust/pull/135618/) +- [Fix debuginfo when LLVM's location discriminator value limit is exceeded.](https://github.com/rust-lang/rust/pull/135643/) +- Fixes for building Rust from source: + - [Only try to distribute `llvm-objcopy` if llvm tools are enabled.](https://github.com/rust-lang/rust/pull/134240/) + - [Add Profile Override for Non-Git Sources.](https://github.com/rust-lang/rust/pull/135433/) + - [Resolve symlinks of LLVM tool binaries before copying them.](https://github.com/rust-lang/rust/pull/135585/) + - [Make it possible to use ci-rustc on tarball sources.](https://github.com/rust-lang/rust/pull/135722/) + +Version 1.84.0 (2025-01-09) +========================== + +<a id="1.84.0-Language"></a> + +Language +-------- +- [Allow `#[deny]` inside `#[forbid]` as a no-op](https://github.com/rust-lang/rust/pull/121560/) +- [Show a warning when `-Ctarget-feature` is used to toggle features that can lead to unsoundness due to ABI mismatches](https://github.com/rust-lang/rust/pull/129884) +- [Use the next-generation trait solver in coherence](https://github.com/rust-lang/rust/pull/130654) +- [Allow coercions to drop the principal of trait objects](https://github.com/rust-lang/rust/pull/131857) +- [Support `/` as the path separator for `include!()` in all cases on Windows](https://github.com/rust-lang/rust/pull/125205) +- [Taking a raw ref (`raw (const|mut)`) of a deref of a pointer (`*ptr`) is now safe](https://github.com/rust-lang/rust/pull/129248) +- [Stabilize s390x inline assembly](https://github.com/rust-lang/rust/pull/131258) +- [Stabilize Arm64EC inline assembly](https://github.com/rust-lang/rust/pull/131781) +- [Lint against creating pointers to immediately dropped temporaries](https://github.com/rust-lang/rust/pull/128985) +- [Execute drop glue when unwinding in an `extern "C"` function](https://github.com/rust-lang/rust/pull/129582) + +<a id="1.84.0-Compiler"></a> + +Compiler +-------- +- [Add `--print host-tuple` flag to print the host target tuple and affirm the "target tuple" terminology over "target triple"](https://github.com/rust-lang/rust/pull/125579) +- [Declaring functions with a calling convention not supported on the current target now triggers a hard error](https://github.com/rust-lang/rust/pull/129935) +- [Set up indirect access to external data for `loongarch64-unknown-linux-{musl,ohos}`](https://github.com/rust-lang/rust/pull/131583) +- [Enable XRay instrumentation for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/131818) +- [Extend the `unexpected_cfgs` lint to also warn in external macros](https://github.com/rust-lang/rust/pull/132577) +- [Stabilize WebAssembly `multivalue`, `reference-types`, and `tail-call` target features](https://github.com/rust-lang/rust/pull/131080) +- [Added Tier 2 support for the `wasm32v1-none` target](https://github.com/rust-lang/rust/pull/131487) + +<a id="1.84.0-Libraries"></a> + +Libraries +--------- +- [Implement `From<&mut {slice}>` for `Box/Rc/Arc<{slice}>`](https://github.com/rust-lang/rust/pull/129329) +- [Move `<float>::copysign`, `<float>::abs`, `<float>::signum` to `core`](https://github.com/rust-lang/rust/pull/131304) +- [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377) +- [Implement `FromStr` for `CString` and `TryFrom<CString>` for `String`](https://github.com/rust-lang/rust/pull/130608) +- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/123723) + +<a id="1.84.0-Stabilized-APIs"></a> + +Stabilized APIs +--------------- + +- [`Ipv6Addr::is_unique_local`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.is_unique_local) +- [`Ipv6Addr::is_unicast_link_local`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.is_unicast_link_local) +- [`core::ptr::with_exposed_provenance`](https://doc.rust-lang.org/stable/core/ptr/fn.with_exposed_provenance.html) +- [`core::ptr::with_exposed_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.with_exposed_provenance_mut.html) +- [`<ptr>::addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.addr) +- [`<ptr>::expose_provenance`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.expose_provenance) +- [`<ptr>::with_addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.with_addr) +- [`<ptr>::map_addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.map_addr) +- [`<int>::isqrt`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.isqrt) +- [`<int>::checked_isqrt`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.checked_isqrt) +- [`<uint>::isqrt`](https://doc.rust-lang.org/stable/core/primitive.u32.html#method.isqrt) +- [`NonZero::isqrt`](https://doc.rust-lang.org/stable/core/num/struct.NonZero.html#impl-NonZero%3Cu128%3E/method.isqrt) +- [`core::ptr::without_provenance`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance.html) +- [`core::ptr::without_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance_mut.html) +- [`core::ptr::dangling`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling.html) +- [`core::ptr::dangling_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling_mut.html) +- [`Pin::as_deref_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.as_deref_mut) + +These APIs are now stable in const contexts + +- [`AtomicBool::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicBool.html#method.from_ptr) +- [`AtomicPtr::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicPtr.html#method.from_ptr) +- [`AtomicU8::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU8.html#method.from_ptr) +- [`AtomicU16::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU16.html#method.from_ptr) +- [`AtomicU32::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU32.html#method.from_ptr) +- [`AtomicU64::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU64.html#method.from_ptr) +- [`AtomicUsize::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html#method.from_ptr) +- [`AtomicI8::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI8.html#method.from_ptr) +- [`AtomicI16::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI16.html#method.from_ptr) +- [`AtomicI32::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI32.html#method.from_ptr) +- [`AtomicI64::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI64.html#method.from_ptr) +- [`AtomicIsize::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicIsize.html#method.from_ptr) +- [`<ptr>::is_null`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_null-1) +- [`<ptr>::as_ref`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.as_ref-1) +- [`<ptr>::as_mut`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.as_mut) +- [`Pin::new`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.new) +- [`Pin::new_unchecked`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.new_unchecked) +- [`Pin::get_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_ref) +- [`Pin::into_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.into_ref) +- [`Pin::get_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_mut) +- [`Pin::get_unchecked_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_unchecked_mut) +- [`Pin::static_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.static_ref) +- [`Pin::static_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.static_mut) + +<a id="1.84.0-Cargo"></a> + +Cargo +----- +- [Stabilize MSRV-aware resolver config](https://github.com/rust-lang/cargo/pull/14639/) +- [Stabilize resolver v3](https://github.com/rust-lang/cargo/pull/14754/) + +<a id="1.84-Rustdoc"></a> + +Rustdoc +------- + +- [rustdoc-search: improve type-driven search](https://github.com/rust-lang/rust/pull/127589) + +<a id="1.84.0-Compatibility-Notes"></a> + +Compatibility Notes +------------------- +- [Enable by default the `LSX` target feature for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/132140) +- [The unstable `-Zprofile` flag (“gcov-style” coverage instrumentation) has been removed.](https://github.com/rust-lang/rust/pull/131829) This does not affect the stable flags for coverage instrumentation (`-Cinstrument-coverage`) and profile-guided optimization (`-Cprofile-generate`, `-Cprofile-use`), which are unrelated and remain available. +- Support for the target named `wasm32-wasi` has been removed as the target is now named `wasm32-wasip1`. This completes the [transition](https://github.com/rust-lang/compiler-team/issues/607) [plan](https://github.com/rust-lang/compiler-team/issues/695) for this target following [the introduction of `wasm32-wasip1`](https://github.com/rust-lang/rust/pull/120468) in Rust 1.78. Compiler warnings on [use of `wasm32-wasi`](https://github.com/rust-lang/rust/pull/126662) introduced in Rust 1.81 are now gone as well as the target is removed. +- [The syntax `&pin (mut|const) T` is now parsed as a type which in theory could affect macro expansion results in some edge cases](https://github.com/rust-lang/rust/pull/130635#issuecomment-2375462821) +- [Legacy syntax for calling `std::arch` functions is no longer permitted to declare items or bodies (such as closures, inline consts, or async blocks).](https://github.com/rust-lang/rust/pull/130443#issuecomment-2445678945) +- [Declaring functions with a calling convention not supported on the current target now triggers a hard error](https://github.com/rust-lang/rust/pull/129935) +- [The next-generation trait solver is now enabled for coherence, fixing multiple soundness issues](https://github.com/rust-lang/rust/pull/130654) + +Version 1.83.0 (2024-11-28) +========================== + +<a id="1.83.0-Language"></a> + +Language +-------- +- [Stabilize `&mut`, `*mut`, `&Cell`, and `*const Cell` in const.](https://github.com/rust-lang/rust/pull/129195) +- [Allow creating references to statics in `const` initializers.](https://github.com/rust-lang/rust/pull/129759) +- [Implement raw lifetimes and labels (`'r#ident`).](https://github.com/rust-lang/rust/pull/126452) +- [Define behavior when atomic and non-atomic reads race.](https://github.com/rust-lang/rust/pull/128778) +- [Non-exhaustive structs may now be empty.](https://github.com/rust-lang/rust/pull/128934) +- [Disallow implicit coercions from places of type `!`](https://github.com/rust-lang/rust/pull/129392) +- [`const extern` functions can now be defined for other calling conventions.](https://github.com/rust-lang/rust/pull/129753) +- [Stabilize `expr_2021` macro fragment specifier in all editions.](https://github.com/rust-lang/rust/pull/129972) +- [The `non_local_definitions` lint now fires on less code and warns by default.](https://github.com/rust-lang/rust/pull/127117) + + +<a id="1.83.0-Compiler"></a> + +Compiler +-------- +- [Deprecate unsound `-Csoft-float` flag.](https://github.com/rust-lang/rust/pull/129897) +- Add many new tier 3 targets: + - [`aarch64_unknown_nto_qnx700`](https://github.com/rust-lang/rust/pull/127897) + - [`arm64e-apple-tvos`](https://github.com/rust-lang/rust/pull/130614) + - [`armv7-rtems-eabihf`](https://github.com/rust-lang/rust/pull/127021) + - [`loongarch64-unknown-linux-ohos`](https://github.com/rust-lang/rust/pull/130750) + - [`riscv32-wrs-vxworks` and `riscv64-wrs-vxworks`](https://github.com/rust-lang/rust/pull/130549) + - [`riscv32{e|em|emc}-unknown-none-elf`](https://github.com/rust-lang/rust/pull/130555) + - [`x86_64-unknown-hurd-gnu`](https://github.com/rust-lang/rust/pull/128345) + - [`x86_64-unknown-trusty`](https://github.com/rust-lang/rust/pull/130453) + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + + +<a id="1.83.0-Libraries"></a> + +Libraries +--------- +- [Implement `PartialEq` for `ExitCode`.](https://github.com/rust-lang/rust/pull/127633) +- [Document that `catch_unwind` can deal with foreign exceptions without UB, although the exact behavior is unspecified.](https://github.com/rust-lang/rust/pull/128321) +- [Implement `Default` for `HashMap`/`HashSet` iterators that don't already have it.](https://github.com/rust-lang/rust/pull/128711) +- [Bump Unicode to version 16.0.0.](https://github.com/rust-lang/rust/pull/130183) +- [Change documentation of `ptr::add`/`sub` to not claim equivalence with `offset`.](https://github.com/rust-lang/rust/pull/130229) + + +<a id="1.83.0-Stabilized-APIs"></a> + +Stabilized APIs +--------------- + +- [`BufRead::skip_until`](https://doc.rust-lang.org/stable/std/io/trait.BufRead.html#method.skip_until) +- [`ControlFlow::break_value`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.break_value) +- [`ControlFlow::continue_value`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.continue_value) +- [`ControlFlow::map_break`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.map_break) +- [`ControlFlow::map_continue`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.map_continue) +- [`DebugList::finish_non_exhaustive`](https://doc.rust-lang.org/stable/core/fmt/struct.DebugList.html#method.finish_non_exhaustive) +- [`DebugMap::finish_non_exhaustive`](https://doc.rust-lang.org/stable/core/fmt/struct.DebugMap.html#method.finish_non_exhaustive) +- [`DebugSet::finish_non_exhaustive`](https://doc.rust-lang.org/stable/core/fmt/struct.DebugSet.html#method.finish_non_exhaustive) +- [`DebugTuple::finish_non_exhaustive`](https://doc.rust-lang.org/stable/core/fmt/struct.DebugTuple.html#method.finish_non_exhaustive) +- [`ErrorKind::ArgumentListTooLong`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.ArgumentListTooLong) +- [`ErrorKind::Deadlock`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.Deadlock) +- [`ErrorKind::DirectoryNotEmpty`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.DirectoryNotEmpty) +- [`ErrorKind::ExecutableFileBusy`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.ExecutableFileBusy) +- [`ErrorKind::FileTooLarge`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.FileTooLarge) +- [`ErrorKind::HostUnreachable`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.HostUnreachable) +- [`ErrorKind::IsADirectory`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.IsADirectory) +- [`ErrorKind::NetworkDown`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.NetworkDown) +- [`ErrorKind::NetworkUnreachable`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.NetworkUnreachable) +- [`ErrorKind::NotADirectory`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.NotADirectory) +- [`ErrorKind::NotSeekable`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.NotSeekable) +- [`ErrorKind::ReadOnlyFilesystem`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.ReadOnlyFilesystem) +- [`ErrorKind::ResourceBusy`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.ResourceBusy) +- [`ErrorKind::StaleNetworkFileHandle`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.StaleNetworkFileHandle) +- [`ErrorKind::StorageFull`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.StorageFull) +- [`ErrorKind::TooManyLinks`](https://doc.rust-lang.org/stable/std/io/enum.ErrorKind.html#variant.TooManyLinks) +- [`Option::get_or_insert_default`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.get_or_insert_default) +- [`Waker::data`](https://doc.rust-lang.org/stable/core/task/struct.Waker.html#method.data) +- [`Waker::new`](https://doc.rust-lang.org/stable/core/task/struct.Waker.html#method.new) +- [`Waker::vtable`](https://doc.rust-lang.org/stable/core/task/struct.Waker.html#method.vtable) +- [`char::MIN`](https://doc.rust-lang.org/stable/core/primitive.char.html#associatedconstant.MIN) +- [`hash_map::Entry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/hash_map/enum.Entry.html#method.insert_entry) +- [`hash_map::VacantEntry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/hash_map/struct.VacantEntry.html#method.insert_entry) + +These APIs are now stable in const contexts: + +- [`Cell::into_inner`](https://doc.rust-lang.org/stable/core/cell/struct.Cell.html#method.into_inner) +- [`Duration::as_secs_f32`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html#method.as_secs_f32) +- [`Duration::as_secs_f64`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html#method.as_secs_f64) +- [`Duration::div_duration_f32`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html#method.div_duration_f32) +- [`Duration::div_duration_f64`](https://doc.rust-lang.org/stable/core/time/struct.Duration.html#method.div_duration_f64) +- [`MaybeUninit::as_mut_ptr`](https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html#method.as_mut_ptr) +- [`NonNull::as_mut`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.as_mut) +- [`NonNull::copy_from`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.copy_from) +- [`NonNull::copy_from_nonoverlapping`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.copy_from_nonoverlapping) +- [`NonNull::copy_to`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.copy_to) +- [`NonNull::copy_to_nonoverlapping`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.copy_to_nonoverlapping) +- [`NonNull::slice_from_raw_parts`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.slice_from_raw_parts) +- [`NonNull::write`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.write) +- [`NonNull::write_bytes`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.write_bytes) +- [`NonNull::write_unaligned`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.write_unaligned) +- [`OnceCell::into_inner`](https://doc.rust-lang.org/stable/core/cell/struct.OnceCell.html#method.into_inner) +- [`Option::as_mut`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.as_mut) +- [`Option::expect`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.expect) +- [`Option::replace`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.replace) +- [`Option::take`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.take) +- [`Option::unwrap`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.unwrap) +- [`Option::unwrap_unchecked`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.unwrap_unchecked) +- [`Option::<&_>::copied`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.copied) +- [`Option::<&mut _>::copied`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.copied-1) +- [`Option::<Option<_>>::flatten`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.flatten) +- [`Option::<Result<_, _>>::transpose`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.transpose) +- [`RefCell::into_inner`](https://doc.rust-lang.org/stable/core/cell/struct.RefCell.html#method.into_inner) +- [`Result::as_mut`](https://doc.rust-lang.org/stable/core/result/enum.Result.html#method.as_mut) +- [`Result::<&_, _>::copied`](https://doc.rust-lang.org/stable/core/result/enum.Result.html#method.copied) +- [`Result::<&mut _, _>::copied`](https://doc.rust-lang.org/stable/core/result/enum.Result.html#method.copied-1) +- [`Result::<Option<_>, _>::transpose`](https://doc.rust-lang.org/stable/core/result/enum.Result.html#method.transpose) +- [`UnsafeCell::get_mut`](https://doc.rust-lang.org/stable/core/cell/struct.UnsafeCell.html#method.get_mut) +- [`UnsafeCell::into_inner`](https://doc.rust-lang.org/stable/core/cell/struct.UnsafeCell.html#method.into_inner) +- [`array::from_mut`](https://doc.rust-lang.org/stable/core/array/fn.from_mut.html) +- [`char::encode_utf8`](https://doc.rust-lang.org/stable/core/primitive.char.html#method.encode_utf8) +- [`{float}::classify`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.classify) +- [`{float}::is_finite`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_finite) +- [`{float}::is_infinite`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_infinite) +- [`{float}::is_nan`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_nan) +- [`{float}::is_normal`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_normal) +- [`{float}::is_sign_negative`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_sign_negative) +- [`{float}::is_sign_positive`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_sign_positive) +- [`{float}::is_subnormal`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.is_subnormal) +- [`{float}::from_bits`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.from_bits) +- [`{float}::from_be_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.from_be_bytes) +- [`{float}::from_le_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.from_le_bytes) +- [`{float}::from_ne_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.from_ne_bytes) +- [`{float}::to_bits`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.to_bits) +- [`{float}::to_be_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.to_be_bytes) +- [`{float}::to_le_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.to_le_bytes) +- [`{float}::to_ne_bytes`](https://doc.rust-lang.org/stable/core/primitive.f64.html#method.to_ne_bytes) +- [`mem::replace`](https://doc.rust-lang.org/stable/core/mem/fn.replace.html) +- [`ptr::replace`](https://doc.rust-lang.org/stable/core/ptr/fn.replace.html) +- [`ptr::slice_from_raw_parts_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.slice_from_raw_parts_mut.html) +- [`ptr::write`](https://doc.rust-lang.org/stable/core/ptr/fn.write.html) +- [`ptr::write_unaligned`](https://doc.rust-lang.org/stable/core/ptr/fn.write_unaligned.html) +- [`<*const _>::copy_to`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_to) +- [`<*const _>::copy_to_nonoverlapping`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_to_nonoverlapping) +- [`<*mut _>::copy_from`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_from) +- [`<*mut _>::copy_from_nonoverlapping`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_from_nonoverlapping) +- [`<*mut _>::copy_to`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_to-1) +- [`<*mut _>::copy_to_nonoverlapping`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.copy_to_nonoverlapping-1) +- [`<*mut _>::write`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.write) +- [`<*mut _>::write_bytes`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.write_bytes) +- [`<*mut _>::write_unaligned`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.write_unaligned) +- [`slice::from_mut`](https://doc.rust-lang.org/stable/core/slice/fn.from_mut.html) +- [`slice::from_raw_parts_mut`](https://doc.rust-lang.org/stable/core/slice/fn.from_raw_parts_mut.html) +- [`<[_]>::first_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.first_mut) +- [`<[_]>::last_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.last_mut) +- [`<[_]>::first_chunk_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.first_chunk_mut) +- [`<[_]>::last_chunk_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.last_chunk_mut) +- [`<[_]>::split_at_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut) +- [`<[_]>::split_at_mut_checked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut_checked) +- [`<[_]>::split_at_mut_unchecked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut_unchecked) +- [`<[_]>::split_first_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_first_mut) +- [`<[_]>::split_last_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_last_mut) +- [`<[_]>::split_first_chunk_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_first_chunk_mut) +- [`<[_]>::split_last_chunk_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_last_chunk_mut) +- [`str::as_bytes_mut`](https://doc.rust-lang.org/stable/core/primitive.str.html#method.as_bytes_mut) +- [`str::as_mut_ptr`](https://doc.rust-lang.org/stable/core/primitive.str.html#method.as_mut_ptr) +- [`str::from_utf8_unchecked_mut`](https://doc.rust-lang.org/stable/core/str/fn.from_utf8_unchecked_mut.html) + + +<a id="1.83.0-Cargo"></a> + +Cargo +----- +- [Introduced a new `CARGO_MANIFEST_PATH` environment variable, similar to `CARGO_MANIFEST_DIR` but pointing directly to the manifest file.](https://github.com/rust-lang/cargo/pull/14404/) +- [Added `package.autolib` to the manifest, allowing `[lib]` auto-discovery to be disabled.](https://github.com/rust-lang/cargo/pull/14591/) +- [Declare support level for each crate in Cargo's Charter / crate docs.](https://github.com/rust-lang/cargo/pull/14600/) +- [Declare new Intentional Artifacts as 'small' changes.](https://github.com/rust-lang/cargo/pull/14599/) + + +<a id="1.83-Rustdoc"></a> + +Rustdoc +------- + +- [The sidebar / hamburger menu table of contents now includes the `# headers` from the main item's doc comment](https://github.com/rust-lang/rust/pull/120736). This is similar to a third-party feature provided by the rustdoc-search-enhancements browser extension. + + +<a id="1.83.0-Compatibility-Notes"></a> + +Compatibility Notes +------------------- +- [Warn against function pointers using unsupported ABI strings.](https://github.com/rust-lang/rust/pull/128784) +- [Check well-formedness of the source type's signature in fn pointer casts.](https://github.com/rust-lang/rust/pull/129021) This partly closes a soundness hole that comes when casting a function item to function pointer +- [Use equality instead of subtyping when resolving type dependent paths.](https://github.com/rust-lang/rust/pull/129073) +- Linking on macOS now correctly includes Rust's default deployment target. Due to a linker bug, you might have to pass `MACOSX_DEPLOYMENT_TARGET` or fix your `#[link]` attributes to point to the correct frameworks. See <https://github.com/rust-lang/rust/pull/129369>. +- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previous did not have any effect.](https://github.com/rust-lang/rust/pull/129422) +- The future incompatibility lint `deprecated_cfg_attr_crate_type_name` [has been made into a hard error](https://github.com/rust-lang/rust/pull/129670). It was used to deny usage of `#![crate_type]` and `#![crate_name]` attributes in `#![cfg_attr]`, which required a hack in the compiler to be able to change the used crate type and crate name after cfg expansion. + Users can use `--crate-type` instead of `#![cfg_attr(..., crate_type = "...")]` and `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]` when running `rustc`/`cargo rustc` on the command line. + Use of those two attributes outside of `#![cfg_attr]` continue to be fully supported. +- Until now, paths into the sysroot were always prefixed with `/rustc/$hash` in diagnostics, codegen, backtrace, e.g. + ``` + thread 'main' panicked at 'hello world', map-panic.rs:2:50 + stack backtrace: + 0: std::panicking::begin_panic + at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/panicking.rs:616:12 + 1: map_panic::main::{{closure}} + at ./map-panic.rs:2:50 + 2: core::option::Option<T>::map + at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/option.rs:929:29 + 3: map_panic::main + at ./map-panic.rs:2:30 + 4: core::ops::function::FnOnce::call_once + at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/core/src/ops/function.rs:248:5 + note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. + ``` + [RFC 3127 said](https://rust-lang.github.io/rfcs/3127-trim-paths.html#changing-handling-of-sysroot-path-in-rustc) + > We want to change this behaviour such that, when `rust-src` source files can be discovered, the virtual path is discarded and therefore the local path will be embedded, unless there is a `--remap-path-prefix` that causes this local path to be remapped in the usual way. + + [#129687](https://github.com/rust-lang/rust/pull/129687) implements this behaviour, when `rust-src` is present at compile time, `rustc` replaces `/rustc/$hash` with a real path into the local `rust-src` component with best effort. + To sanitize this, users must explicitly supply `--remap-path-prefix=<path to rust-src>=foo` or not have the `rust-src` component installed. + - The allow-by-default `missing_docs` lint used to disable itself when invoked through `rustc --test`/`cargo test`, resulting in `#[expect(missing_docs)]` emitting false positives due to the expectation being wrongly unfulfilled. This behavior [has now been removed](https://github.com/rust-lang/rust/pull/130025), which allows `#[expect(missing_docs)]` to be fulfilled in all scenarios, but will also report new `missing_docs` diagnostics for publicly reachable `#[cfg(test)]` items, [integration test](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#integration-tests) crate-level documentation, and publicly reachable items in integration tests. +- [The `armv8r-none-eabihf` target now uses the Armv8-R required set of floating-point features.](https://github.com/rust-lang/rust/pull/130295) +- [Fix a soundness bug where rustc wouldn't detect unconstrained higher-ranked lifetimes in a `dyn Trait`'s associated types that occur due to supertraits.](https://github.com/rust-lang/rust/pull/130367) +- [Update the minimum external LLVM version to 18.](https://github.com/rust-lang/rust/pull/130487) +- [Remove `aarch64-fuchsia` and `x86_64-fuchsia` target aliases in favor of `aarch64-unknown-fuchsia` and `x86_64-unknown-fuchsia` respectively.](https://github.com/rust-lang/rust/pull/130657) +- [The ABI-level exception class of a Rust panic is now encoded with native-endian bytes, so it is legible in hex dumps.](https://github.com/rust-lang/rust/pull/130897) +- [Visual Studio 2013 is no longer supported for MSVC targets.](https://github.com/rust-lang/rust/pull/131070) +- [The sysroot no longer contains the `std` dynamic library in its top-level `lib/` dir.](https://github.com/rust-lang/rust/pull/131188) + + Version 1.82.0 (2024-10-17) ========================== @@ -11,7 +638,7 @@ Language - [`addr_of(_mut)!` macros and the newly stabilized `&raw (const|mut)` are now safe to use with all static items](https://github.com/rust-lang/rust/pull/125834) - [size_of_val_raw: for length 0 this is safe to call](https://github.com/rust-lang/rust/pull/126152/) - [Reorder trait bound modifiers *after* `for<...>` binder in trait bounds](https://github.com/rust-lang/rust/pull/127054/) -- [Stabilize opaque type precise capturing (RFC 3617)](https://github.com/rust-lang/rust/pull/127672) +- [Stabilize `+ use<'lt>` opaque type precise capturing (RFC 3617)](https://github.com/rust-lang/rust/pull/127672) - [Stabilize `&raw const` and `&raw mut` operators (RFC 2582)](https://github.com/rust-lang/rust/pull/127679) - [Stabilize unsafe extern blocks (RFC 3484)](https://github.com/rust-lang/rust/pull/127921) - [Stabilize nested field access in `offset_of!`](https://github.com/rust-lang/rust/pull/128284) @@ -68,15 +695,15 @@ Stabilized APIs - [`impl Default for std::collections::vec_deque::Iter`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.Iter.html#impl-Default-for-Iter%3C'_,+T%3E) - [`impl Default for std::collections::vec_deque::IterMut`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.IterMut.html#impl-Default-for-IterMut%3C'_,+T%3E) - [`Rc<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit) -- [`Rc<T>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init) +- [`Rc<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init) - [`Rc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit_slice) - [`Rc<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init-1) - [`Arc<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit) -- [`Arc<T>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init) +- [`Arc<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init) - [`Arc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit_slice) - [`Arc<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init-1) - [`Box<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit) -- [`Box<T>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init) +- [`Box<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init) - [`Box<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit_slice) - [`Box<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init-1) - [`core::arch::x86_64::_bextri_u64`](https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bextri_u64.html) @@ -125,7 +752,7 @@ These APIs are now stable in const contexts: - [`std::task::Waker::from_raw`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw) - [`std::task::Context::from_waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.from_waker) - [`std::task::Context::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.waker) -- [`$integer::from_str_radix`](https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.from_str_radix) +- [`{integer}::from_str_radix`](https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.from_str_radix) - [`std::num::ParseIntError::kind`](https://doc.rust-lang.org/nightly/std/num/struct.ParseIntError.html#method.kind) <a id="1.82.0-Cargo"></a> @@ -225,6 +852,7 @@ Libraries - [Replace sort implementations with stable `driftsort` and unstable `ipnsort`.](https://github.com/rust-lang/rust/pull/124032/) All `slice::sort*` and `slice::select_nth*` methods are expected to see significant performance improvements. See the [research project](https://github.com/Voultapher/sort-research-rs) for more details. - [Document behavior of `create_dir_all` with respect to empty paths.](https://github.com/rust-lang/rust/pull/125112/) - [Fix interleaved output in the default panic hook when multiple threads panic simultaneously.](https://github.com/rust-lang/rust/pull/127397/) +- Fix `Command`'s batch files argument escaping not working when file name has trailing whitespace or periods (CVE-2024-43402). <a id="1.81.0-Stabilized-APIs"></a> @@ -271,7 +899,7 @@ Compatibility Notes * We have renamed `std::panic::PanicInfo` to `std::panic::PanicHookInfo`. The old name will continue to work as an alias, but will result in a deprecation warning starting in Rust 1.82.0. `core::panic::PanicInfo` will remain unchanged, however, as this is now a *different type*. - + The reason is that these types have different roles: `std::panic::PanicHookInfo` is the argument to the [panic hook](https://doc.rust-lang.org/stable/std/panic/fn.set_hook.html) in std context (where panics can have an arbitrary payload), while `core::panic::PanicInfo` is the argument to the [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) in no_std context (where panics always carry a formatted *message*). Separating these types allows us to add more useful methods to these types, such as `std::panic::PanicHookInfo::payload_as_str()` and `core::panic::PanicInfo::message()`. * The new sort implementations may panic if a type's implementation of [`Ord`](https://doc.rust-lang.org/std/cmp/trait.Ord.html) (or the given comparison function) does not implement a [total order](https://en.wikipedia.org/wiki/Total_order) as the trait requires. `Ord`'s supertraits (`PartialOrd`, `Eq`, and `PartialEq`) must also be consistent. The previous implementations would not "notice" any problem, but the new implementations have a good chance of detecting inconsistencies, throwing a panic rather than returning knowingly unsorted data. @@ -352,7 +980,7 @@ Stabilized APIs - [`impl Default for Arc<CStr>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3CCStr%3E) - [`impl Default for Arc<[T]>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3C%5BT%5D%3E) - [`impl IntoIterator for Box<[T]>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-IntoIterator-for-Box%3C%5BI%5D,+A%3E) -- [`impl FromIterator<String> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E) +- [`impl FromIterator<String> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E) - [`impl FromIterator<char> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3Cchar%3E-for-Box%3Cstr%3E) - [`LazyCell`](https://doc.rust-lang.org/beta/core/cell/struct.LazyCell.html) - [`LazyLock`](https://doc.rust-lang.org/beta/std/sync/struct.LazyLock.html) @@ -670,13 +1298,6 @@ Cargo - [Support `target.<triple>.rustdocflags` officially](https://github.com/rust-lang/cargo/pull/13197/) - [Stabilize global cache data tracking](https://github.com/rust-lang/cargo/pull/13492/) -<a id="1.78.0-Misc"></a> - -Misc ----- - -- [rustdoc: add `--test-builder-wrapper` arg to support wrappers such as RUSTC_WRAPPER when building doctests](https://github.com/rust-lang/rust/pull/114651/) - <a id="1.78.0-Compatibility-Notes"></a> Compatibility Notes @@ -1591,7 +2212,7 @@ Compiler - [Detect uninhabited types early in const eval](https://github.com/rust-lang/rust/pull/109435/) - [Switch to LLD as default linker for {arm,thumb}v4t-none-eabi](https://github.com/rust-lang/rust/pull/109721/) - [Add tier 3 target `loongarch64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/96971) -- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/), +- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/), - [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112) This catches undefined behavior at runtime, and may cause existing code to fail. @@ -1795,10 +2416,10 @@ Compatibility Notes - [Cargo denies `CARGO_HOME` in the `[env]` configuration table. Cargo itself doesn't pick up this value, but recursive calls to cargo would, which was not intended.](https://github.com/rust-lang/cargo/pull/11644/) - [Debuginfo for build dependencies is now off if not explicitly set. This is expected to improve the overall build time.](https://github.com/rust-lang/cargo/pull/11252/) - [The Rust distribution no longer always includes rustdoc](https://github.com/rust-lang/rust/pull/106886) - If `tools = [...]` is set in config.toml, we will respect a missing rustdoc in that list. By + If `tools = [...]` is set in bootstrap.toml, we will respect a missing rustdoc in that list. By default rustdoc remains included. To retain the prior behavior explicitly add `"rustdoc"` to the list. - + <a id="1.69.0-Internal-Changes"></a> Internal Changes @@ -1842,7 +2463,7 @@ Language -------- - [Stabilize default_alloc_error_handler](https://github.com/rust-lang/rust/pull/102318/) - This allows usage of `alloc` on stable without requiring the + This allows usage of `alloc` on stable without requiring the definition of a handler for allocation failure. Defining custom handlers is still unstable. - [Stabilize `efiapi` calling convention.](https://github.com/rust-lang/rust/pull/105795/) - [Remove implicit promotion for types with drop glue](https://github.com/rust-lang/rust/pull/105085/) @@ -4781,7 +5402,7 @@ related tools. - [Building `rustc` from source now uses `ninja` by default over `make`.][74922] You can continue building with `make` by setting `ninja=false` in - your `config.toml`. + your `bootstrap.toml`. - [cg_llvm: `fewer_names` in `uncached_llvm_type`][76030] - [Made `ensure_sufficient_stack()` non-generic][76680] diff --git a/REUSE.toml b/REUSE.toml index 3005bb56609b5..816c6d730c824 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -22,12 +22,13 @@ path = [ "Cargo.lock", "Cargo.toml", "CODE_OF_CONDUCT.md", - "config.example.toml", + "bootstrap.example.toml", "configure", "CONTRIBUTING.md", "COPYRIGHT", "INSTALL.md", "LICENSE-APACHE", + "license-metadata.json", "LICENSE-MIT", "README.md", "RELEASES.md", @@ -63,8 +64,8 @@ SPDX-License-Identifier = "Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT [[annotations]] path = "library/core/src/unicode/unicode_data.rs" precedence = "override" -SPDX-FileCopyrightText = "1991-2022 Unicode, Inc. All rights reserved." -SPDX-License-Identifier = "Unicode-DFS-2016" +SPDX-FileCopyrightText = "1991-2024 Unicode, Inc." +SPDX-License-Identifier = "Unicode-3.0" [[annotations]] path = "library/std/src/sync/mpmc/**" @@ -91,7 +92,7 @@ SPDX-FileCopyrightText = "2015 Anders Kaseorg <andersk@mit.edu>" SPDX-License-Identifier = "MIT" [[annotations]] -path = "src/librustdoc/html/static/fonts/FiraSans**" +path = "src/librustdoc/html/static/fonts/Fira**" precedence = "override" SPDX-FileCopyrightText = ["2014, Mozilla Foundation", "2014, Telefonica S.A."] SPDX-License-Identifier = "OFL-1.1" diff --git a/bootstrap.example.toml b/bootstrap.example.toml new file mode 100644 index 0000000000000..72c4492d465d8 --- /dev/null +++ b/bootstrap.example.toml @@ -0,0 +1,1010 @@ +# Sample TOML configuration file for building Rust. +# +# To configure bootstrap, run `./configure` or `./x.py setup`. +# See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-bootstraptoml for more information. +# +# All options are commented out by default in this file, and they're commented +# out with their default values. The build system by default looks for +# `bootstrap.toml` in the current directory of a build for build configuration, but +# a custom configuration file can also be specified with `--config` to the build +# system. + +# ============================================================================= +# Global Settings +# ============================================================================= + +# Use different pre-set defaults than the global defaults. +# +# See `src/bootstrap/defaults` for more information. +# Note that this has no default value (x.py uses the defaults in `bootstrap.example.toml`). +#profile = <none> + +# Inherits configuration values from different configuration files (a.k.a. config extensions). +# Supports absolute paths, and uses the current directory (where the bootstrap was invoked) +# as the base if the given path is not absolute. +# +# The overriding logic follows a right-to-left order. For example, in `include = ["a.toml", "b.toml"]`, +# extension `b.toml` overrides `a.toml`. Also, parent extensions always overrides the inner ones. +#include = [] + +# Keeps track of major changes made to this configuration. +# +# This value also represents ID of the PR that caused major changes. Meaning, +# you can visit github.com/rust-lang/rust/pull/{change-id} to check for more details. +# +# A 'major change' includes any of the following +# - A new option +# - A change in the default values +# +# If the change-id does not match the version currently in use, x.py will +# display the changes made to the bootstrap. +# To suppress these warnings, you can set change-id = "ignore". +#change-id = <latest change id in src/bootstrap/src/utils/change_tracker.rs> + +# ============================================================================= +# Tweaking how LLVM is compiled +# ============================================================================= +[llvm] + +# Whether to use Rust CI built LLVM instead of locally building it. +# +# Unless you're developing for a target where Rust CI doesn't build a compiler +# toolchain or changing LLVM locally, you probably want to leave this enabled. +# +# Set this to `true` to download if CI llvm available otherwise it builds +# from `src/llvm-project`. +# +# Set this to `"if-unchanged"` to download only if the llvm-project has not +# been modified. You can also use this if you are unsure whether you're on a +# tier 1 target. All tier 1 targets are currently supported. + +# Currently, we only support this when building LLVM for the build triple. +# +# Note that many of the LLVM options are not currently supported for +# downloading. Currently only the "assertions" option can be toggled. +#download-ci-llvm = true + +# Indicates whether the LLVM build is a Release or Debug build +#optimize = true + +# Indicates whether LLVM should be built with ThinLTO. Note that this will +# only succeed if you use clang, lld, llvm-ar, and llvm-ranlib in your C/C++ +# toolchain (see the `cc`, `cxx`, `linker`, `ar`, and `ranlib` options below). +# More info at: https://clang.llvm.org/docs/ThinLTO.html#clang-bootstrap +#thin-lto = false + +# Indicates whether an LLVM Release build should include debug info +#release-debuginfo = false + +# Indicates whether the LLVM assertions are enabled or not +# NOTE: When assertions are disabled, bugs in the integration between rustc and LLVM can lead to +# unsoundness (segfaults, etc.) in the rustc process itself, not just in the generated code. +#assertions = false + +# Indicates whether the LLVM testsuite is enabled in the build or not. Does +# not execute the tests as part of the build as part of x.py build et al, +# just makes it possible to do `ninja check-llvm` in the staged LLVM build +# directory when doing LLVM development as part of Rust development. +#tests = false + +# Indicates whether the LLVM plugin is enabled or not +#plugins = false + +# Whether to build Enzyme as AutoDiff backend. +#enzyme = false + +# Whether to build LLVM with support for it's gpu offload runtime. +#offload = false + +# When true, link libstdc++ statically into the rustc_llvm. +# This is useful if you don't want to use the dynamic version of that +# library provided by LLVM. +#static-libstdcpp = false + +# Enable LLVM to use zstd for compression. +#libzstd = false + +# Whether to use Ninja to build LLVM. This runs much faster than make. +#ninja = true + +# LLVM targets to build support for. +# Note: this is NOT related to Rust compilation targets. However, as Rust is +# dependent on LLVM for code generation, turning targets off here WILL lead to +# the resulting rustc being unable to compile for the disabled architectures. +# +# To add support for new targets, see https://rustc-dev-guide.rust-lang.org/building/new-target.html. +#targets = "AArch64;AMDGPU;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" + +# LLVM experimental targets to build support for. These targets are specified in +# the same format as above, but since these targets are experimental, they are +# not built by default and the experimental Rust compilation targets that depend +# on them will not work unless the user opts in to building them. +#experimental-targets = "AVR;M68k;CSKY" + +# Cap the number of parallel linker invocations when compiling LLVM. +# This can be useful when building LLVM with debug info, which significantly +# increases the size of binaries and consequently the memory required by +# each linker process. +# If set to 0, linker invocations are treated like any other job and +# controlled by bootstrap's -j parameter. +#link-jobs = 0 + +# Whether to build LLVM as a dynamically linked library (as opposed to statically linked). +# Under the hood, this passes `--shared` to llvm-config. +# NOTE: To avoid performing LTO multiple times, we suggest setting this to `true` when `thin-lto` is enabled. +#link-shared = llvm.thin-lto + +# When building llvm, this configures what is being appended to the version. +# To use LLVM version as is, provide an empty string. +#version-suffix = if rust.channel == "dev" { "-rust-dev" } else { "-rust-$version-$channel" } + +# On MSVC you can compile LLVM with clang-cl, but the test suite doesn't pass +# with clang-cl, so this is special in that it only compiles LLVM with clang-cl. +# Note that this takes a /path/to/clang-cl, not a boolean. +#clang-cl = cc + +# Pass extra compiler and linker flags to the LLVM CMake build. +#cflags = "" +#cxxflags = "" +#ldflags = "" + +# Use libc++ when building LLVM instead of libstdc++. This is the default on +# platforms already use libc++ as the default C++ library, but this option +# allows you to use libc++ even on platforms when it's not. You need to ensure +# that your host compiler ships with libc++. +#use-libcxx = false + +# The value specified here will be passed as `-DLLVM_USE_LINKER` to CMake. +#use-linker = <none> (path) + +# Whether or not to specify `-DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=YES` +#allow-old-toolchain = false + +# Whether to include the Polly optimizer. +#polly = false + +# Whether to build the clang compiler. +#clang = false + +# Whether to enable llvm compilation warnings. +#enable-warnings = false + +# Custom CMake defines to set when building LLVM. +#build-config = {} + +# ============================================================================= +# Tweaking how GCC is compiled +# ============================================================================= +[gcc] +# Download GCC from CI instead of building it locally. +# Note that this will attempt to download GCC even if there are local +# modifications to the `src/gcc` submodule. +# Currently, this is only supported for the `x86_64-unknown-linux-gnu` target. +# download-ci-gcc = false + +# ============================================================================= +# General build configuration options +# ============================================================================= +[build] + +# The default stage to use for the `check` subcommand +#check-stage = 0 + +# The default stage to use for the `doc` subcommand +#doc-stage = 0 + +# The default stage to use for the `build` subcommand +#build-stage = 1 + +# The default stage to use for the `test` subcommand +#test-stage = 1 + +# The default stage to use for the `dist` subcommand +#dist-stage = 2 + +# The default stage to use for the `install` subcommand +#install-stage = 2 + +# The default stage to use for the `bench` subcommand +#bench-stage = 2 + +# A descriptive string to be appended to version output (e.g., `rustc --version`), +# which is also used in places like debuginfo `DW_AT_producer`. This may be useful for +# supplementary build information, like distro-specific package versions. +# +# The Rust compiler will differentiate between versions of itself, including +# based on this string, which means that if you wish to be compatible with +# upstream Rust you need to set this to "". However, note that if you set this to "" but +# are not actually compatible -- for example if you've backported patches that change +# behavior -- this may lead to miscompilations or other bugs. +#description = "" + +# Build triple for the pre-compiled snapshot compiler. If `rustc` is set, this must match its host +# triple (see `rustc --version --verbose`; cross-compiling the rust build system itself is NOT +# supported). If `rustc` is unset, this must be a platform with pre-compiled host tools +# (https://doc.rust-lang.org/nightly/rustc/platform-support.html). The current platform must be +# able to run binaries of this build triple. +# +# If `rustc` is present in path, this defaults to the host it was compiled for. +# Otherwise, `x.py` will try to infer it from the output of `uname`. +# If `uname` is not found in PATH, we assume this is `x86_64-pc-windows-msvc`. +# This may be changed in the future. +#build = "x86_64-unknown-linux-gnu" (as an example) + +# Which triples to produce a compiler toolchain for. Each of these triples will be bootstrapped from +# the build triple themselves. In other words, this is the list of triples for which to build a +# compiler that can RUN on that triple. +# +# Defaults to just the `build` triple. +#host = [build.build] (list of triples) + +# Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of these triples will +# be bootstrapped from the build triple themselves. In other words, this is the list of triples for +# which to build a library that can CROSS-COMPILE to that triple. +# +# Defaults to `host`. If you set this explicitly, you likely want to add all +# host triples to this list as well in order for those host toolchains to be +# able to compile programs for their native target. +#target = build.host (list of triples) + +# Use this directory to store build artifacts. Paths are relative to the current directory, not to +# the root of the repository. +#build-dir = "build" + +# Instead of downloading the src/stage0 version of Cargo specified, use +# this Cargo binary instead to build all Rust code +# If you set this, you likely want to set `rustc` as well. +#cargo = "/path/to/cargo" + +# Instead of downloading the src/stage0 version of the compiler +# specified, use this rustc binary instead as the stage0 snapshot compiler. +# If you set this, you likely want to set `cargo` as well. +#rustc = "/path/to/rustc" + +# Instead of downloading the src/stage0 version of rustfmt specified, +# use this rustfmt binary instead as the stage0 snapshot rustfmt. +#rustfmt = "/path/to/rustfmt" + +# Instead of downloading the src/stage0 version of cargo-clippy specified, +# use this cargo-clippy binary instead as the stage0 snapshot cargo-clippy. +# +# Note that this option should be used with the same toolchain as the `rustc` option above. +# Otherwise, clippy is likely to fail due to a toolchain conflict. +#cargo-clippy = "/path/to/cargo-clippy" + +# Whether to build documentation by default. If false, rustdoc and +# friends will still be compiled but they will not be used to generate any +# documentation. +# +# You can still build documentation when this is disabled by explicitly passing paths, +# e.g. `x doc library`. +#docs = true + +# Flag to specify whether CSS, JavaScript, and HTML are minified when +# docs are generated. JSON is always minified, because it's enormous, +# and generated in already-minified form from the beginning. +#docs-minification = true + +# Flag to specify whether private items should be included in the library docs. +#library-docs-private-items = false + +# Indicate whether to build compiler documentation by default. +# You can still build documentation when this is disabled by explicitly passing a path: `x doc compiler`. +#compiler-docs = false + +# Indicate whether git submodules are managed and updated automatically. +#submodules = true + +# The path to (or name of) the GDB executable to use. This is only used for +# executing the debuginfo test suite. +#gdb = "gdb" + +# The path to (or name of) the LLDB executable to use. This is only used for +# executing the debuginfo test suite. +#lldb = "lldb" + +# The node.js executable to use. Note that this is only used for the emscripten +# target when running tests, otherwise this can be omitted. +#nodejs = "node" + +# The npm executable to use. Note that this is used for rustdoc-gui tests, +# otherwise this can be omitted. +# +# Under Windows this should be `npm.cmd` or path to it (verified on nodejs v18.06), or +# error will be emitted. +#npm = "npm" + +# Python interpreter to use for various tasks throughout the build, notably +# rustdoc tests, the lldb python interpreter, and some dist bits and pieces. +# +# Defaults to the Python interpreter used to execute x.py. +#python = "python" + +# The path to the REUSE executable to use. Note that REUSE is not required in +# most cases, as our tooling relies on a cached (and shrunk) copy of the +# REUSE output present in the git repository and in our source tarballs. +# +# REUSE is only needed if your changes caused the overall licensing of the +# repository to change, and the cached copy has to be regenerated. +# +# Defaults to the "reuse" command in the system path. +#reuse = "reuse" + +# Force Cargo to check that Cargo.lock describes the precise dependency +# set that all the Cargo.toml files create, instead of updating it. +#locked-deps = false + +# Indicate whether the vendored sources are used for Rust dependencies or not. +# +# Vendoring requires additional setup. We recommend using the pre-generated source tarballs if you +# want to use vendoring. See https://forge.rust-lang.org/infra/other-installation-methods.html#source-code. +#vendor = if "is a tarball source" && "vendor" dir exists && ".cargo/config.toml" file exists { true } else { false } + +# Typically the build system will build the Rust compiler twice. The second +# compiler, however, will simply use its own libraries to link against. If you +# would rather to perform a full bootstrap, compiling the compiler three times, +# then you can set this option to true. +# +# This is only useful for verifying that rustc generates reproducible builds. +#full-bootstrap = false + +# Set the bootstrap/download cache path. It is useful when building rust +# repeatedly in a CI environment. +#bootstrap-cache-path = /path/to/shared/cache + +# Enable a build of the extended Rust tool set which is not only the compiler +# but also tools such as Cargo. This will also produce "combined installers" +# which are used to install Rust and Cargo together. +# The `tools` (check `bootstrap.example.toml` to see its default value) option specifies +# which tools should be built if `extended = true`. +# +# This is disabled by default. +#extended = false + +# Set of tools to be included in the installation. +# +# If `extended = false`, the only one of these built by default is rustdoc. +# +# If `extended = true`, they are all included. +# +# If any enabled tool fails to build, the installation fails. +#tools = [ +# "cargo", +# "clippy", +# "rustdoc", +# "rustfmt", +# "rust-analyzer", +# "rust-analyzer-proc-macro-srv", +# "analysis", +# "src", +# "wasm-component-ld", +# "miri", "cargo-miri" # for dev/nightly channels +#] + +# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation +#verbose = 0 + +# Build the sanitizer runtimes +#sanitizers = false + +# Build the profiler runtime (required when compiling with options that depend +# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`). +#profiler = false + +# Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics. +# Requires the LLVM submodule to be managed by bootstrap (i.e. not external) so that `compiler-rt` +# sources are available. +# +# Setting this to `false` generates slower code, but removes the requirement for a C toolchain in +# order to run `x check`. +#optimized-compiler-builtins = if rust.channel == "dev" { false } else { true } + +# Indicates whether the native libraries linked into Cargo will be statically +# linked or not. +#cargo-native-static = false + +# Run the build with low priority, by setting the process group's "nice" value +# to +10 on Unix platforms, and by using a "low priority" job object on Windows. +#low-priority = false + +# Arguments passed to the `./configure` script, used during distcheck. You +# probably won't fill this in but rather it's filled in by the `./configure` +# script. Useful for debugging. +#configure-args = [] + +# Indicates that a local rebuild is occurring instead of a full bootstrap, +# essentially skipping stage0 as the local compiler is recompiling itself again. +# Useful for modifying only the stage2 compiler without having to pass `--keep-stage 0` each time. +#local-rebuild = false + +# Print out how long each bootstrap step took (mostly intended for CI and +# tracking over time) +#print-step-timings = false + +# Print out resource usage data for each bootstrap step, as defined by the Unix +# struct rusage. (Note that this setting is completely unstable: the data it +# captures, what platforms it supports, the format of its associated output, and +# this setting's very existence, are all subject to change.) +#print-step-rusage = false + +# Always patch binaries for usage with Nix toolchains. If `true` then binaries +# will be patched unconditionally. If `false` or unset, binaries will be patched +# only if the current distribution is NixOS. This option is useful when using +# a Nix toolchain on non-NixOS distributions. +#patch-binaries-for-nix = false + +# Collect information and statistics about the current build, and write it to +# disk. Enabling this has no impact on the resulting build output. The +# schema of the file generated by the build metrics feature is unstable, and +# this is not intended to be used during local development. +#metrics = false + +# Specify the location of the Android NDK. Used when targeting Android. +#android-ndk = "/path/to/android-ndk-r26d" + +# Number of parallel jobs to be used for building and testing. If set to `0` or +# omitted, it will be automatically determined. This is the `-j`/`--jobs` flag +# passed to cargo invocations. +#jobs = 0 + +# What custom diff tool to use for displaying compiletest tests. +#compiletest-diff-tool = <none> + +# Whether to use the precompiled stage0 libtest with compiletest. +#compiletest-use-stage0-libtest = true + +# Indicates whether ccache is used when building certain artifacts (e.g. LLVM). +# Set to `true` to use the first `ccache` in PATH, or set an absolute path to use +# a specific version. +#ccache = false + +# List of paths to exclude from the build and test processes. +# For example, exclude = ["tests/ui", "src/tools/tidy"]. +#exclude = [] + +# ============================================================================= +# General install configuration options +# ============================================================================= +[install] + +# Where to install the generated toolchain. Must be an absolute path. +#prefix = "/usr/local" + +# Where to install system configuration files. +# If this is a relative path, it will get installed in `prefix` above +#sysconfdir = "/etc" + +# Where to install documentation in `prefix` above +#docdir = "share/doc/rust" + +# Where to install binaries in `prefix` above +#bindir = "bin" + +# Where to install libraries in `prefix` above +#libdir = "lib" + +# Where to install man pages in `prefix` above +#mandir = "share/man" + +# Where to install data in `prefix` above +#datadir = "share" + +# ============================================================================= +# Options for compiling Rust code itself +# ============================================================================= +[rust] + +# Whether or not to optimize when compiling the compiler and standard library, +# and what level of optimization to use. +# WARNING: Building with optimize = false is NOT SUPPORTED. Due to bootstrapping, +# building without optimizations takes much longer than optimizing. Further, some platforms +# fail to build without this optimization (c.f. #65352). +# The valid options are: +# true - Enable optimizations. +# false - Disable optimizations. +# 0 - Disable optimizations. +# 1 - Basic optimizations. +# 2 - Some optimizations. +# 3 - All optimizations. +# "s" - Optimize for binary size. +# "z" - Optimize for binary size, but also turn off loop vectorization. +#optimize = true + +# Indicates that the build should be configured for debugging Rust. A +# `debug`-enabled compiler and standard library will be somewhat +# slower (due to e.g. checking of debug assertions) but should remain +# usable. +# +# Note: If this value is set to `true`, it will affect a number of +# configuration options below as well, if they have been left +# unconfigured in this file. +# +# Note: changes to the `debug` setting do *not* affect `optimize` +# above. In theory, a "maximally debuggable" environment would +# set `optimize` to `false` above to assist the introspection +# facilities of debuggers like lldb and gdb. To recreate such an +# environment, explicitly set `optimize` to `false` and `debug` +# to `true`. In practice, everyone leaves `optimize` set to +# `true`, because an unoptimized rustc with debugging +# enabled becomes *unusably slow* (e.g. rust-lang/rust#24840 +# reported a 25x slowdown) and bootstrapping the supposed +# "maximally debuggable" environment (notably libstd) takes +# hours to build. +# +#debug = false + +# Whether to download the stage 1 and 2 compilers from CI. This is useful if you +# are working on tools, doc-comments, or library (you will be able to build the +# standard library without needing to build the compiler). +# +# Set this to "if-unchanged" if you are working on `src/tools`, `tests` or +# `library` (on CI, `library` changes triggers in-tree compiler build) to speed +# up the build process if you don't need to build a compiler from the latest +# commit from `master`. +# +# Set this to `true` to always download or `false` to always use the in-tree +# compiler. +#download-rustc = false + +# Number of codegen units to use for each compiler invocation. A value of 0 +# means "the number of cores on this machine", and 1+ is passed through to the +# compiler. +# +# Uses the rustc defaults: https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units +#codegen-units = if incremental { 256 } else { 16 } + +# Sets the number of codegen units to build the standard library with, +# regardless of what the codegen-unit setting for the rest of the compiler is. +# NOTE: building with anything other than 1 is known to occasionally have bugs. +#codegen-units-std = codegen-units + +# Whether or not debug assertions are enabled for the compiler and standard library. +# These can help find bugs at the cost of a small runtime slowdown. +# +# Defaults to rust.debug value +#debug-assertions = rust.debug (boolean) + +# Whether or not debug assertions are enabled for the standard library. +# Overrides the `debug-assertions` option, if defined. +# +# Defaults to rust.debug-assertions value +#debug-assertions-std = rust.debug-assertions (boolean) + +# Whether or not to leave debug! and trace! calls in the rust binary. +# +# Defaults to rust.debug-assertions value +# +# If you see a message from `tracing` saying "some trace filter directives would enable traces that +# are disabled statically" because `max_level_info` is enabled, set this value to `true`. +#debug-logging = rust.debug-assertions (boolean) + +# Whether or not to build rustc, tools and the libraries with randomized type layout +#randomize-layout = false + +# Whether or not overflow checks are enabled for the compiler and standard +# library. +# +# Defaults to rust.debug value +#overflow-checks = rust.debug (boolean) + +# Whether or not overflow checks are enabled for the standard library. +# Overrides the `overflow-checks` option, if defined. +# +# Defaults to rust.overflow-checks value +#overflow-checks-std = rust.overflow-checks (boolean) + +# Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. +# See https://doc.rust-lang.org/rustc/codegen-options/index.html#debuginfo for available options. +# +# Can be overridden for specific subsets of Rust code (rustc, std or tools). +# Debuginfo for tests run with compiletest is not controlled by this option +# and needs to be enabled separately with `debuginfo-level-tests`. +# +# Note that debuginfo-level = 2 generates several gigabytes of debuginfo +# and will slow down the linking process significantly. +#debuginfo-level = if rust.debug { 1 } else { 0 } + +# Debuginfo level for the compiler. +#debuginfo-level-rustc = rust.debuginfo-level + +# Debuginfo level for the standard library. +#debuginfo-level-std = rust.debuginfo-level + +# Debuginfo level for the tools. +#debuginfo-level-tools = rust.debuginfo-level + +# Debuginfo level for the test suites run with compiletest. +# FIXME(#61117): Some tests fail when this option is enabled. +#debuginfo-level-tests = 0 + +# Should rustc and the standard library be built with split debuginfo? Default +# is platform dependent. +# +# This field is deprecated, use `target.<triple>.split-debuginfo` instead. +# +# The value specified here is only used when targeting the `build.build` triple, +# and is overridden by `target.<triple>.split-debuginfo` if specified. +# +#split-debuginfo = see target.<triple>.split-debuginfo + +# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) +#backtrace = true + +# Whether to always use incremental compilation when building rustc +#incremental = false + +# The default linker that will be hard-coded into the generated +# compiler for targets that don't specify a default linker explicitly +# in their target specifications. Note that this is not the linker +# used to link said compiler. It can also be set per-target (via the +# `[target.<triple>]` block), which may be useful in a cross-compilation +# setting. +# +# See https://doc.rust-lang.org/rustc/codegen-options/index.html#linker for more information. +#default-linker = <none> (path) + +# The "channel" for the Rust build to produce. The stable/beta channels only +# allow using stable features, whereas the nightly and dev channels allow using +# nightly features. +# +# You can set the channel to "auto-detect" to load the channel name from `src/ci/channel`. +# +# If using tarball sources, default value is "auto-detect", otherwise, it's "dev". +#channel = if "is a tarball source" { "auto-detect" } else { "dev" } + +# The root location of the musl installation directory. The library directory +# will also need to contain libunwind.a for an unwinding implementation. Note +# that this option only makes sense for musl targets that produce statically +# linked binaries. +# +# Defaults to /usr on musl hosts. Has no default otherwise. +#musl-root = <platform specific> (path) + +# By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix +# platforms to ensure that the compiler is usable by default from the build +# directory (as it links to a number of dynamic libraries). This may not be +# desired in distributions, for example. +#rpath = true + +# Indicates whether symbols should be stripped using `-Cstrip=symbols`. +#strip = false + +# Forces frame pointers to be used with `-Cforce-frame-pointers`. +# This can be helpful for profiling at a small performance cost. +#frame-pointers = false + +# Indicates whether stack protectors should be used +# via the unstable option `-Zstack-protector`. +# +# Valid options are : `none`(default),`basic`,`strong`, or `all`. +# `strong` and `basic` options may be buggy and are not recommended, see rust-lang/rust#114903. +#stack-protector = "none" + +# Prints each test name as it is executed, to help debug issues in the test harness itself. +#verbose-tests = if is_verbose { true } else { false } + +# Flag indicating whether tests are compiled with optimizations (the -O flag). +#optimize-tests = true + +# Flag indicating whether codegen tests will be run or not. If you get an error +# saying that the FileCheck executable is missing, you may want to disable this. +# Also see the target's llvm-filecheck option. +#codegen-tests = true + +# Flag indicating whether git info will be retrieved from .git automatically. +# Having the git information can cause a lot of rebuilds during development. +#omit-git-hash = if rust.channel == "dev" { true } else { false } + +# Whether to create a source tarball by default when running `x dist`. +# +# You can still build a source tarball when this is disabled by explicitly passing `x dist rustc-src`. +#dist-src = true + +# After building or testing an optional component (e.g. the nomicon or reference), append the +# result (broken, compiling, testing) into this JSON file. +#save-toolstates = <none> (path) + +# This is an array of the codegen backends that will be compiled for the rustc +# that's being compiled. The default is to only build the LLVM codegen backend, +# and currently the only standard options supported are `"llvm"`, `"cranelift"` +# and `"gcc"`. The first backend in this list will be used as default by rustc +# when no explicit backend is specified. +#codegen-backends = ["llvm"] + +# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and +# whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be +# when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from +# the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will +# make this default to false. +#lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true + +# Indicates whether LLD will be used to link Rust crates during bootstrap on +# supported platforms. +# If set to `true` or `"external"`, a global `lld` binary that has to be in $PATH +# will be used. +# If set to `"self-contained"`, rust-lld from the snapshot compiler will be used. +# +# On MSVC, LLD will not be used if we're cross linking. +# +# Explicitly setting the linker for a target will override this option when targeting MSVC. +#use-lld = false + +# Indicates whether some LLVM tools, like llvm-objdump, will be made available in the +# sysroot. +#llvm-tools = true + +# Indicates whether the `self-contained` llvm-bitcode-linker, will be made available +# in the sysroot. It is required for running nvptx tests. +#llvm-bitcode-linker = false + +# Whether to deny warnings in crates +#deny-warnings = true + +# Print backtrace on internal compiler errors during bootstrap +#backtrace-on-ice = false + +# Whether to verify generated LLVM IR +#verify-llvm-ir = false + +# Compile the compiler with a non-default ThinLTO import limit. This import +# limit controls the maximum size of functions imported by ThinLTO. Decreasing +# will make code compile faster at the expense of lower runtime performance. +#thin-lto-import-instr-limit = if incremental { 10 } else { LLVM default (currently 100) } + +# Map debuginfo paths to `/rust/$sha/...`. +# Useful for reproducible builds. Generally only set for releases +#remap-debuginfo = false + +# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator. +# This option is only tested on Linux and OSX. It can also be configured per-target in the +# [target.<tuple>] section. +#jemalloc = false + +# Run tests in various test suites with the "nll compare mode" in addition to +# running the tests in normal mode. Largely only used on CI and during local +# development of NLL +#test-compare-mode = false + +# Global default for llvm-libunwind for all targets. See the target-specific +# documentation for llvm-libunwind below. Note that the target-specific +# option will override this if set. +#llvm-libunwind = 'no' + +# Enable Windows Control Flow Guard checks in the standard library. +# This only applies from stage 1 onwards, and only for Windows targets. +#control-flow-guard = false + +# Enable Windows EHCont Guard checks in the standard library. +# This only applies from stage 1 onwards, and only for Windows targets. +#ehcont-guard = false + +# Enable symbol-mangling-version v0. This can be helpful when profiling rustc, +# as generics will be preserved in symbols (rather than erased into opaque T). +# When no setting is given, the new scheme will be used when compiling the +# compiler and its tools and the legacy scheme will be used when compiling the +# standard library. +# If an explicit setting is given, it will be used for all parts of the codebase. +#new-symbol-mangling = true|false (see comment) + +# Select LTO mode that will be used for compiling rustc. By default, thin local LTO +# (LTO within a single crate) is used (like for any Rust crate). You can also select +# "thin" or "fat" to apply Thin/Fat LTO to the `rustc_driver` dylib, or "off" to disable +# LTO entirely. +#lto = "thin-local" + +# Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std` +#validate-mir-opts = 3 + +# Configure `std` features used during bootstrap. +# +# Default features will be expanded in the following cases: +# - If `rust.llvm-libunwind` or `target.llvm-libunwind` is enabled: +# - "llvm-libunwind" will be added for in-tree LLVM builds. +# - "system-llvm-libunwind" will be added for system LLVM builds. +# - If `rust.backtrace` is enabled, "backtrace" will be added. +# - If `rust.profiler` or `target.profiler` is enabled, "profiler" will be added. +# - If building for a zkvm target, "compiler-builtins-mem" will be added. +# +# Since libstd also builds libcore and liballoc as dependencies and all their features are mirrored +# as libstd features, this option can also be used to configure features such as optimize_for_size. +#std-features = ["panic_unwind"] + +# ============================================================================= +# Options for specific targets +# +# Each of the following options is scoped to the specific target triple in +# question and is used for determining how to compile each target. +# ============================================================================= +[target.x86_64-unknown-linux-gnu] + +# C compiler to be used to compile C code. Note that the +# default value is platform specific, and if not specified it may also depend on +# what platform is crossing to what platform. +# See `src/bootstrap/src/utils/cc_detect.rs` for details. +#cc = "cc" (path) + +# C++ compiler to be used to compile C++ code (e.g. LLVM and our LLVM shims). +# This is only used for host targets. +# See `src/bootstrap/src/utils/cc_detect.rs` for details. +#cxx = "c++" (path) + +# Archiver to be used to assemble static libraries compiled from C/C++ code. +# Note: an absolute path should be used, otherwise LLVM build will break. +#ar = "ar" (path) + +# Ranlib to be used to assemble static libraries compiled from C/C++ code. +# Note: an absolute path should be used, otherwise LLVM build will break. +#ranlib = "ranlib" (path) + +# Linker to be used to bootstrap Rust code. Note that the +# default value is platform specific, and if not specified it may also depend on +# what platform is crossing to what platform. +# Setting this will override the `use-lld` option for Rust code when targeting MSVC. +#linker = "cc" (path) + +# Should rustc and the standard library be built with split debuginfo? Default +# is platform dependent. +# +# Valid values are the same as those accepted by `-C split-debuginfo` +# (`off`/`unpacked`/`packed`). +# +# On Linux, split debuginfo is disabled by default. +# +# On Apple platforms, unpacked split debuginfo is used by default. Unpacked +# debuginfo does not run `dsymutil`, which packages debuginfo from disparate +# object files into a single `.dSYM` file. `dsymutil` adds time to builds for +# no clear benefit, and also makes it more difficult for debuggers to find +# debug info. The compiler currently defaults to running `dsymutil` to preserve +# its historical default, but when compiling the compiler itself, we skip it by +# default since we know it's safe to do so in that case. +# +# On Windows platforms, packed debuginfo is the only supported option, +# producing a `.pdb` file. +#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked } + +# Path to the `llvm-config` binary of the installation of a custom LLVM to link +# against. Note that if this is specified we don't compile LLVM at all for this +# target. +#llvm-config = <none> (path) + +# Override detection of whether this is a Rust-patched LLVM. This would be used +# in conjunction with either an llvm-config or build.submodules = false. +#llvm-has-rust-patches = if llvm-config { false } else { true } + +# Normally the build system can find LLVM's FileCheck utility, but if +# not, you can specify an explicit file name for it. +#llvm-filecheck = "/path/to/llvm-version/bin/FileCheck" + +# Use LLVM libunwind as the implementation for Rust's unwinder. +# Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false). +# This option only applies for Linux and Fuchsia targets. +# On Linux target, if crt-static is not enabled, 'no' means dynamic link to +# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind +# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled, +# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both +# means static link to the in-tree build of llvm libunwind, and 'system' means +# static link to `libunwind.a` provided by system. Due to the limitation of glibc, +# it must link to `libgcc_eh.a` to get a working output, and this option have no effect. +#llvm-libunwind = 'no' if Linux, 'in-tree' if Fuchsia + +# Build the sanitizer runtimes for this target. +# This option will override the same option under [build] section. +#sanitizers = build.sanitizers (bool) + +# When true, build the profiler runtime for this target (required when compiling +# with options that depend on this runtime, such as `-C profile-generate` or +# `-C instrument-coverage`). This may also be given a path to an existing build +# of the profiling runtime library from LLVM's compiler-rt. +# This option will override the same option under [build] section. +#profiler = build.profiler (bool) + +# This option supports enable `rpath` in each target independently, +# and will override the same option under [rust] section. It only works on Unix platforms +#rpath = rust.rpath (bool) + +# Force static or dynamic linkage of the standard library for this target. If +# this target is a host for rustc, this will also affect the linkage of the +# compiler itself. This is useful for building rustc on targets that normally +# only use static libraries. If unset, the target's default linkage is used. +#crt-static = <platform-specific> (bool) + +# The root location of the musl installation directory. The library directory +# will also need to contain libunwind.a for an unwinding implementation. Note +# that this option only makes sense for musl targets that produce statically +# linked binaries. +#musl-root = build.musl-root (path) + +# The full path to the musl libdir. +#musl-libdir = musl-root/lib + +# The root location of the `wasm32-wasip1` sysroot. Only used for WASI +# related targets. Make sure to create a `[target.wasm32-wasip1]` +# section and move this field there (or equivalent for the target being built). +#wasi-root = <none> (path) + +# Used in testing for configuring where the QEMU images are located, you +# probably don't want to use this. +#qemu-rootfs = <none> (path) + +# Skip building the `std` library for this target. Enabled by default for +# target triples containing `-none`, `nvptx`, `switch`, or `-uefi`. +#no-std = <platform-specific> (bool) + +# This is an array of the codegen backends that will be +# compiled for this target, overriding the global rust.codegen-backends option. +# See that option for more info. +#codegen-backends = rust.codegen-backends (array) + +# This is a "runner" to pass to `compiletest` when executing tests. Tests will +# execute this tool where the binary-to-test is passed as an argument. Can +# be useful for situations such as when WebAssembly is being tested and a +# runtime needs to be configured. This value is similar to +# Cargo's `CARGO_$target_RUNNER` configuration. +# +# This configuration is a space-separated list of arguments so `foo bar` would +# execute the program `foo` with the first argument as `bar` and the second +# argument as the test binary. +#runner = <none> (string) + +# Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics +# on this target. +# Requires the LLVM submodule to be managed by bootstrap (i.e. not external) so that `compiler-rt` +# sources are available. +# +# Setting this to `false` generates slower code, but removes the requirement for a C toolchain in +# order to run `x check`. +#optimized-compiler-builtins = build.optimized-compiler-builtins (bool) + +# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator. +# This overrides the global `rust.jemalloc` option. See that option for more info. +#jemalloc = rust.jemalloc (bool) + +# ============================================================================= +# Distribution options +# +# These options are related to distribution, mostly for the Rust project itself. +# You probably won't need to concern yourself with any of these options +# ============================================================================= +[dist] + +# This is the folder of artifacts that the build system will sign. All files in +# this directory will be signed with the default gpg key using the system `gpg` +# binary. The `asc` and `sha256` files will all be output into the standard dist +# output folder (currently `build/dist`) +# +# This folder should be populated ahead of time before the build system is +# invoked. +#sign-folder = <none> (path) + +# The remote address that all artifacts will eventually be uploaded to. The +# build system generates manifests which will point to these urls, and for the +# manifests to be correct they'll have to have the right URLs encoded. +# +# Note that this address should not contain a trailing slash as file names will +# be appended to it. +#upload-addr = <none> (URL) + +# Whether to build a plain source tarball to upload +# We disable that on Windows not to override the one already uploaded on S3 +# as the one built on Windows will contain backslashes in paths causing problems +# on linux +#src-tarball = true + +# List of compression formats to use when generating dist tarballs. The list of +# formats is provided to rust-installer, which must support all of them. +# +# This list must be non-empty. +#compression-formats = ["gz", "xz"] + +# How much time should be spent compressing the tarballs. The better the +# compression profile, the longer compression will take. +# +# Available options: fast, balanced, best +#compression-profile = "fast" + +# Copy the linker, DLLs, and various libraries from MinGW into the Rust toolchain. +# Only applies when the host or target is pc-windows-gnu. +#include-mingw-linker = true + +# Whether to vendor dependencies for the dist tarball. +#vendor = if "is a tarball source" || "is a git repository" { true } else { false } diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index a2fc9d5c408e3..f4caa3ef769d5 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc-main" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -20,16 +20,15 @@ rustc_smir = { path = "../rustc_smir" } stable_mir = { path = "../stable_mir" } # tidy-alphabetical-end -[dependencies.jemalloc-sys] -version = "0.5.0" +[dependencies.tikv-jemalloc-sys] +version = "0.6.0" optional = true features = ['unprefixed_malloc_on_supported_platforms'] [features] # tidy-alphabetical-start -jemalloc = ['dep:jemalloc-sys'] +jemalloc = ['dep:tikv-jemalloc-sys'] llvm = ['rustc_driver_impl/llvm'] max_level_info = ['rustc_driver_impl/max_level_info'] rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts'] -rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler'] # tidy-alphabetical-end diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index e9a7397557eb1..ca1bb59e59d60 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -1,5 +1,7 @@ // We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`. #![feature(rustc_private)] +// Several crates are depended upon but unused so that they are present in the sysroot +#![expect(unused_crate_dependencies)] // A note about jemalloc: rustc uses jemalloc when built for CI and // distribution. The obvious way to do this is with the `#[global_allocator]` @@ -41,6 +43,8 @@ fn main() { { use std::os::raw::{c_int, c_void}; + use tikv_jemalloc_sys as jemalloc_sys; + #[used] static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc; #[used] @@ -61,7 +65,7 @@ fn main() { // linking, so we need to explicitly depend on the function. #[cfg(target_os = "macos")] { - extern "C" { + unsafe extern "C" { fn _rjem_je_zone_register(); } diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 7448f066d0ac1..5f9afc46a1ace 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -1,17 +1,19 @@ [package] name = "rustc_abi" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rand = { version = "0.8.4", default-features = false, optional = true } -rand_xoshiro = { version = "0.6.0", optional = true } -rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rand = { version = "0.9.0", default-features = false, optional = true } +rand_xoshiro = { version = "0.7.0", optional = true } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } -rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_span = { path = "../rustc_span", optional = true } tracing = "0.1" # tidy-alphabetical-end @@ -24,6 +26,7 @@ nightly = [ "dep:rustc_data_structures", "dep:rustc_macros", "dep:rustc_serialize", + "dep:rustc_span", "rustc_index/nightly", ] randomize = ["dep:rand", "dep:rand_xoshiro", "nightly"] diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index 2ecac8a9df1c6..a21e1aee9b08a 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -1,68 +1,9 @@ -mod abi { - pub(crate) use crate::Primitive::*; - pub(crate) use crate::Variants; -} - -use rustc_macros::HashStable_Generic; - -use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum RegKind { - Integer, - Float, - Vector, -} +#[cfg(feature = "nightly")] +use crate::{BackendRepr, FieldsShape, Primitive, Size, TyAbiInterface, TyAndLayout, Variants}; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub struct Reg { - pub kind: RegKind, - pub size: Size, -} +mod reg; -macro_rules! reg_ctor { - ($name:ident, $kind:ident, $bits:expr) => { - pub fn $name() -> Reg { - Reg { kind: RegKind::$kind, size: Size::from_bits($bits) } - } - }; -} - -impl Reg { - reg_ctor!(i8, Integer, 8); - reg_ctor!(i16, Integer, 16); - reg_ctor!(i32, Integer, 32); - reg_ctor!(i64, Integer, 64); - reg_ctor!(i128, Integer, 128); - - reg_ctor!(f32, Float, 32); - reg_ctor!(f64, Float, 64); -} - -impl Reg { - pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { - let dl = cx.data_layout(); - match self.kind { - RegKind::Integer => match self.size.bits() { - 1 => dl.i1_align.abi, - 2..=8 => dl.i8_align.abi, - 9..=16 => dl.i16_align.abi, - 17..=32 => dl.i32_align.abi, - 33..=64 => dl.i64_align.abi, - 65..=128 => dl.i128_align.abi, - _ => panic!("unsupported integer: {self:?}"), - }, - RegKind::Float => match self.size.bits() { - 16 => dl.f16_align.abi, - 32 => dl.f32_align.abi, - 64 => dl.f64_align.abi, - 128 => dl.f128_align.abi, - _ => panic!("unsupported float: {self:?}"), - }, - RegKind::Vector => dl.vector_align(self.size).abi, - } - } -} +pub use reg::{Reg, RegKind}; /// Return value from the `homogeneous_aggregate` test function. #[derive(Copy, Clone, Debug)] @@ -108,15 +49,8 @@ impl HomogeneousAggregate { } } +#[cfg(feature = "nightly")] impl<'a, Ty> TyAndLayout<'a, Ty> { - /// Returns `true` if this is an aggregate type (including a ScalarPair!) - pub fn is_aggregate(&self) -> bool { - match self.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, - } - } - /// Returns `Homogeneous` if this layout is an aggregate containing fields of /// only a single type (e.g., `(u32, u32)`). Such aggregates are often /// special-cased in ABIs. @@ -130,19 +64,17 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { where Ty: TyAbiInterface<'a, C> + Copy, { - match self.abi { - Abi::Uninhabited => Err(Heterogeneous), - + match self.backend_repr { // The primitive for this algorithm. - Abi::Scalar(scalar) => { + BackendRepr::Scalar(scalar) => { let kind = match scalar.primitive() { - abi::Int(..) | abi::Pointer(_) => RegKind::Integer, - abi::Float(_) => RegKind::Float, + Primitive::Int(..) | Primitive::Pointer(_) => RegKind::Integer, + Primitive::Float(_) => RegKind::Float, }; Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) } - Abi::Vector { .. } => { + BackendRepr::SimdVector { .. } => { assert!(!self.is_zst()); Ok(HomogeneousAggregate::Homogeneous(Reg { kind: RegKind::Vector, @@ -150,7 +82,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } - Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => { + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). let from_fields_at = @@ -208,8 +140,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; match &self.variants { - abi::Variants::Single { .. } => {} - abi::Variants::Multiple { variants, .. } => { + Variants::Single { .. } | Variants::Empty => {} + Variants::Multiple { variants, .. } => { // Treat enum variants like union members. // HACK(eddyb) pretend the `enum` field (discriminant) // is at the start of every variant (otherwise the gap @@ -248,7 +180,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ok(result) } } - Abi::Aggregate { sized: false } => Err(Heterogeneous), + BackendRepr::Memory { sized: false } => Err(Heterogeneous), } } } diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs new file mode 100644 index 0000000000000..8cf140dbaad4e --- /dev/null +++ b/compiler/rustc_abi/src/callconv/reg.rs @@ -0,0 +1,63 @@ +#[cfg(feature = "nightly")] +use rustc_macros::HashStable_Generic; + +use crate::{Align, HasDataLayout, Size}; + +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum RegKind { + Integer, + Float, + Vector, +} + +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Reg { + pub kind: RegKind, + pub size: Size, +} + +macro_rules! reg_ctor { + ($name:ident, $kind:ident, $bits:expr) => { + pub fn $name() -> Reg { + Reg { kind: RegKind::$kind, size: Size::from_bits($bits) } + } + }; +} + +impl Reg { + reg_ctor!(i8, Integer, 8); + reg_ctor!(i16, Integer, 16); + reg_ctor!(i32, Integer, 32); + reg_ctor!(i64, Integer, 64); + reg_ctor!(i128, Integer, 128); + + reg_ctor!(f32, Float, 32); + reg_ctor!(f64, Float, 64); +} + +impl Reg { + pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { + let dl = cx.data_layout(); + match self.kind { + RegKind::Integer => match self.size.bits() { + 1 => dl.i1_align.abi, + 2..=8 => dl.i8_align.abi, + 9..=16 => dl.i16_align.abi, + 17..=32 => dl.i32_align.abi, + 33..=64 => dl.i64_align.abi, + 65..=128 => dl.i128_align.abi, + _ => panic!("unsupported integer: {self:?}"), + }, + RegKind::Float => match self.size.bits() { + 16 => dl.f16_align.abi, + 32 => dl.f32_align.abi, + 64 => dl.f64_align.abi, + 128 => dl.f128_align.abi, + _ => panic!("unsupported float: {self:?}"), + }, + RegKind::Vector => dl.llvmlike_vector_align(self.size).abi, + } + } +} diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs new file mode 100644 index 0000000000000..55f4845d21670 --- /dev/null +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -0,0 +1,241 @@ +use std::cmp::Ordering; +use std::fmt; +use std::hash::{Hash, Hasher}; + +#[cfg(feature = "nightly")] +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd}; +#[cfg(feature = "nightly")] +use rustc_macros::{Decodable, Encodable}; + +#[cfg(test)] +mod tests; + +use ExternAbi as Abi; + +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))] +pub enum ExternAbi { + // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the + // hashing tests. These are used in many places, so giving them stable values reduces test + // churn. The specific values are meaningless. + Rust, + C { + unwind: bool, + }, + Cdecl { + unwind: bool, + }, + Stdcall { + unwind: bool, + }, + Fastcall { + unwind: bool, + }, + Vectorcall { + unwind: bool, + }, + Thiscall { + unwind: bool, + }, + Aapcs { + unwind: bool, + }, + Win64 { + unwind: bool, + }, + SysV64 { + unwind: bool, + }, + PtxKernel, + Msp430Interrupt, + X86Interrupt, + /// An entry-point function called by the GPU's host + // FIXME: should not be callable from Rust on GPU targets, is for host's use only + GpuKernel, + EfiApi, + AvrInterrupt, + AvrNonBlockingInterrupt, + CCmseNonSecureCall, + CCmseNonSecureEntry, + System { + unwind: bool, + }, + RustCall, + /// *Not* a stable ABI, just directly use the Rust types to describe the ABI for LLVM. Even + /// normally ABI-compatible Rust types can become ABI-incompatible with this ABI! + Unadjusted, + /// For things unlikely to be called, where reducing register pressure in + /// `extern "Rust"` callers is worth paying extra cost in the callee. + /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. + RustCold, + RiscvInterruptM, + RiscvInterruptS, +} + +macro_rules! abi_impls { + ($e_name:ident = { + $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)* + }) => { + impl $e_name { + pub const ALL_VARIANTS: &[Self] = &[ + $($e_name::$variant $({ unwind: $uw })*,)* + ]; + pub const fn as_str(&self) -> &'static str { + match self { + $($e_name::$variant $( { unwind: $uw } )* => $tok,)* + } + } + } + + impl ::core::str::FromStr for $e_name { + type Err = AbiFromStrErr; + fn from_str(s: &str) -> Result<$e_name, Self::Err> { + match s { + $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)* + _ => Err(AbiFromStrErr::Unknown), + } + } + } + } +} + +#[derive(Debug)] +pub enum AbiFromStrErr { + Unknown, +} + +abi_impls! { + ExternAbi = { + C { unwind: false } =><= "C", + CCmseNonSecureCall =><= "C-cmse-nonsecure-call", + CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry", + C { unwind: true } =><= "C-unwind", + Rust =><= "Rust", + Aapcs { unwind: false } =><= "aapcs", + Aapcs { unwind: true } =><= "aapcs-unwind", + AvrInterrupt =><= "avr-interrupt", + AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt", + Cdecl { unwind: false } =><= "cdecl", + Cdecl { unwind: true } =><= "cdecl-unwind", + EfiApi =><= "efiapi", + Fastcall { unwind: false } =><= "fastcall", + Fastcall { unwind: true } =><= "fastcall-unwind", + GpuKernel =><= "gpu-kernel", + Msp430Interrupt =><= "msp430-interrupt", + PtxKernel =><= "ptx-kernel", + RiscvInterruptM =><= "riscv-interrupt-m", + RiscvInterruptS =><= "riscv-interrupt-s", + RustCall =><= "rust-call", + RustCold =><= "rust-cold", + Stdcall { unwind: false } =><= "stdcall", + Stdcall { unwind: true } =><= "stdcall-unwind", + System { unwind: false } =><= "system", + System { unwind: true } =><= "system-unwind", + SysV64 { unwind: false } =><= "sysv64", + SysV64 { unwind: true } =><= "sysv64-unwind", + Thiscall { unwind: false } =><= "thiscall", + Thiscall { unwind: true } =><= "thiscall-unwind", + Unadjusted =><= "unadjusted", + Vectorcall { unwind: false } =><= "vectorcall", + Vectorcall { unwind: true } =><= "vectorcall-unwind", + Win64 { unwind: false } =><= "win64", + Win64 { unwind: true } =><= "win64-unwind", + X86Interrupt =><= "x86-interrupt", + } +} + +impl Ord for ExternAbi { + fn cmp(&self, rhs: &Self) -> Ordering { + self.as_str().cmp(rhs.as_str()) + } +} + +impl PartialOrd for ExternAbi { + fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> { + Some(self.cmp(rhs)) + } +} + +impl PartialEq for ExternAbi { + fn eq(&self, rhs: &Self) -> bool { + self.cmp(rhs) == Ordering::Equal + } +} + +impl Eq for ExternAbi {} + +impl Hash for ExternAbi { + fn hash<H: Hasher>(&self, state: &mut H) { + self.as_str().hash(state); + // double-assurance of a prefix breaker + u32::from_be_bytes(*b"ABI\0").hash(state); + } +} + +#[cfg(feature = "nightly")] +impl<C> HashStable<C> for ExternAbi { + #[inline] + fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) { + Hash::hash(self, hasher); + } +} + +#[cfg(feature = "nightly")] +impl StableOrd for ExternAbi { + const CAN_USE_UNSTABLE_SORT: bool = true; + + // because each ABI is hashed like a string, there is no possible instability + const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); +} + +impl ExternAbi { + /// An ABI "like Rust" + /// + /// These ABIs are fully controlled by the Rust compiler, which means they + /// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"` + /// - often diverge from the C ABI + /// - are subject to change between compiler versions + pub fn is_rustic_abi(self) -> bool { + use ExternAbi::*; + matches!(self, Rust | RustCall | RustCold) + } + + pub fn supports_varargs(self) -> bool { + // * C and Cdecl obviously support varargs. + // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs. + // * EfiApi is based on Win64 or C, so it also supports it. + // + // * Stdcall does not, because it would be impossible for the callee to clean + // up the arguments. (callee doesn't know how many arguments are there) + // * Same for Fastcall, Vectorcall and Thiscall. + // * Other calling conventions are related to hardware or the compiler itself. + match self { + Self::C { .. } + | Self::Cdecl { .. } + | Self::Aapcs { .. } + | Self::Win64 { .. } + | Self::SysV64 { .. } + | Self::EfiApi => true, + _ => false, + } + } +} + +pub fn all_names() -> Vec<&'static str> { + ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect() +} + +impl ExternAbi { + /// Default ABI chosen for `extern fn` declarations without an explicit ABI. + pub const FALLBACK: Abi = Abi::C { unwind: false }; + + pub fn name(self) -> &'static str { + self.as_str() + } +} + +impl fmt::Display for ExternAbi { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "\"{}\"", self.as_str()) + } +} diff --git a/compiler/rustc_abi/src/extern_abi/tests.rs b/compiler/rustc_abi/src/extern_abi/tests.rs new file mode 100644 index 0000000000000..fc546a6570f0a --- /dev/null +++ b/compiler/rustc_abi/src/extern_abi/tests.rs @@ -0,0 +1,31 @@ +use std::assert_matches::assert_matches; +use std::str::FromStr; + +use super::*; + +#[allow(non_snake_case)] +#[test] +fn lookup_Rust() { + let abi = ExternAbi::from_str("Rust"); + assert!(abi.is_ok() && abi.unwrap().as_str() == "Rust"); +} + +#[test] +fn lookup_cdecl() { + let abi = ExternAbi::from_str("cdecl"); + assert!(abi.is_ok() && abi.unwrap().as_str() == "cdecl"); +} + +#[test] +fn lookup_baz() { + let abi = ExternAbi::from_str("baz"); + assert_matches!(abi, Err(AbiFromStrErr::Unknown)); +} + +#[test] +fn guarantee_lexicographic_ordering() { + let abis = ExternAbi::ALL_VARIANTS; + let mut sorted_abis = abis.to_vec(); + sorted_abis.sort_unstable(); + assert_eq!(abis, sorted_abis); +} diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 6e1299944a09d..42250aa173bbd 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -2,17 +2,24 @@ use std::fmt::{self, Write}; use std::ops::{Bound, Deref}; use std::{cmp, iter}; +use rustc_hashes::Hash64; use rustc_index::Idx; +use rustc_index::bit_set::BitMatrix; use tracing::debug; use crate::{ - Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, - LayoutS, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, + AbiAndPrefAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, + LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; +mod coroutine; +mod simple; + +#[cfg(feature = "nightly")] mod ty; +#[cfg(feature = "nightly")] pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; // A variant is absent if it's uninhabited and only has ZST fields. @@ -24,9 +31,9 @@ fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice<FieldIdx, F>) -> bool where FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug, { - let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); + let uninhabited = fields.iter().any(|f| f.is_uninhabited()); // We cannot ignore alignment; that might lead us to entirely discard a variant and // produce an enum that is less aligned than it should be! let is_1zst = fields.iter().all(|f| f.is_1zst()); @@ -39,7 +46,7 @@ enum NicheBias { End, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LayoutCalculatorError<F> { /// An unsized type was found in a location where a sized type was expected. /// @@ -54,10 +61,53 @@ pub enum LayoutCalculatorError<F> { /// A union had no fields. EmptyUnion, + + /// The fields or variants have irreconcilable reprs + ReprConflict, + + /// The length of an SIMD type is zero + ZeroLengthSimdType, + + /// The length of an SIMD type exceeds the maximum number of lanes + OversizedSimdType { max_lanes: u64 }, + + /// An element type of an SIMD type isn't a primitive + NonPrimitiveSimdType(F), +} + +impl<F> LayoutCalculatorError<F> { + pub fn without_payload(&self) -> LayoutCalculatorError<()> { + use LayoutCalculatorError::*; + match *self { + UnexpectedUnsized(_) => UnexpectedUnsized(()), + SizeOverflow => SizeOverflow, + EmptyUnion => EmptyUnion, + ReprConflict => ReprConflict, + ZeroLengthSimdType => ZeroLengthSimdType, + OversizedSimdType { max_lanes } => OversizedSimdType { max_lanes }, + NonPrimitiveSimdType(_) => NonPrimitiveSimdType(()), + } + } + + /// Format an untranslated diagnostic for this type + /// + /// Intended for use by rust-analyzer, as neither it nor `rustc_abi` depend on fluent infra. + pub fn fallback_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use LayoutCalculatorError::*; + f.write_str(match self { + UnexpectedUnsized(_) => "an unsized type was found where a sized type was expected", + SizeOverflow => "size overflow", + EmptyUnion => "type is a union with no fields", + ReprConflict => "type has an invalid repr", + ZeroLengthSimdType | OversizedSimdType { .. } | NonPrimitiveSimdType(_) => { + "invalid simd type definition" + } + }) + } } type LayoutCalculatorResult<FieldIdx, VariantIdx, F> = - Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>; + Result<LayoutData<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>; #[derive(Clone, Copy, Debug)] pub struct LayoutCalculator<Cx> { @@ -69,44 +119,122 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Self { cx } } - pub fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>( + pub fn array_like<FieldIdx: Idx, VariantIdx: Idx, F>( &self, - a: Scalar, - b: Scalar, - ) -> LayoutS<FieldIdx, VariantIdx> { + element: &LayoutData<FieldIdx, VariantIdx>, + count_if_sized: Option<u64>, // None for slices + ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> { + let count = count_if_sized.unwrap_or(0); + let size = + element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?; + + Ok(LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Array { stride: element.size, count }, + backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() }, + largest_niche: element.largest_niche.filter(|_| count != 0), + uninhabited: element.uninhabited && count != 0, + align: element.align, + size, + max_repr_align: None, + unadjusted_abi_align: element.align.abi, + randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)), + }) + } + + pub fn simd_type< + FieldIdx: Idx, + VariantIdx: Idx, + F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug, + >( + &self, + element: F, + count: u64, + repr_packed: bool, + ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> { + let elt = element.as_ref(); + if count == 0 { + return Err(LayoutCalculatorError::ZeroLengthSimdType); + } else if count > crate::MAX_SIMD_LANES { + return Err(LayoutCalculatorError::OversizedSimdType { + max_lanes: crate::MAX_SIMD_LANES, + }); + } + + let BackendRepr::Scalar(e_repr) = elt.backend_repr else { + return Err(LayoutCalculatorError::NonPrimitiveSimdType(element)); + }; + + // Compute the size and alignment of the vector let dl = self.cx.data_layout(); - let b_align = b.align(dl); - let align = a.align(dl).max(b_align).max(dl.aggregate_align); - let b_offset = a.size(dl).align_to(b_align.abi); - let size = (b_offset + b.size(dl)).align_to(align.abi); - - // HACK(nox): We iter on `b` and then `a` because `max_by_key` - // returns the last maximum. - let largest_niche = Niche::from_scalar(dl, b_offset, b) - .into_iter() - .chain(Niche::from_scalar(dl, Size::ZERO, a)) - .max_by_key(|niche| niche.available(dl)); - - LayoutS { + let size = + elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; + let (repr, align) = if repr_packed && !count.is_power_of_two() { + // Non-power-of-two vectors have padding up to the next power-of-two. + // If we're a packed repr, remove the padding while keeping the alignment as close + // to a vector as possible. + ( + BackendRepr::Memory { sized: true }, + AbiAndPrefAlign { + abi: Align::max_aligned_factor(size), + pref: dl.llvmlike_vector_align(size).pref, + }, + ) + } else { + (BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size)) + }; + let size = size.align_to(align.abi); + + Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { - offsets: [Size::ZERO, b_offset].into(), - memory_index: [0, 1].into(), + offsets: [Size::ZERO].into(), + memory_index: [0].into(), }, - abi: Abi::ScalarPair(a, b), - largest_niche, - align, + backend_repr: repr, + largest_niche: elt.largest_niche, + uninhabited: false, size, + align, max_repr_align: None, - unadjusted_abi_align: align.abi, - } + unadjusted_abi_align: elt.align.abi, + randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)), + }) + } + + /// Compute the layout for a coroutine. + /// + /// This uses dedicated code instead of [`Self::layout_of_struct_or_enum`], as coroutine + /// fields may be shared between multiple variants (see the [`coroutine`] module for details). + pub fn coroutine< + 'a, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + VariantIdx: Idx, + FieldIdx: Idx, + LocalIdx: Idx, + >( + &self, + local_layouts: &IndexSlice<LocalIdx, F>, + prefix_layouts: IndexVec<FieldIdx, F>, + variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>, + storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>, + tag_to_layout: impl Fn(Scalar) -> F, + ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> { + coroutine::layout( + self, + local_layouts, + prefix_layouts, + variant_fields, + storage_conflicts, + tag_to_layout, + ) } pub fn univariant< 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, fields: &IndexSlice<FieldIdx, F>, @@ -177,33 +305,17 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { layout } - pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>( - &self, - ) -> LayoutS<FieldIdx, VariantIdx> { - let dl = self.cx.data_layout(); - LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Primitive, - abi: Abi::Uninhabited, - largest_niche: None, - align: dl.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, - } - } - pub fn layout_of_struct_or_enum< 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>, is_enum: bool, - is_unsafe_cell: bool, + is_special_no_niche: bool, scalar_valid_range: (Bound<u128>, Bound<u128>), discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), discriminants: impl Iterator<Item = (VariantIdx, i128)>, @@ -220,7 +332,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Some(present_first) => present_first, // Uninhabited because it has no variants, or only absent ones. None if is_enum => { - return Ok(self.layout_of_never_type()); + return Ok(LayoutData::never_type(&self.cx)); } // If it's a struct, still compute a layout so that we can still compute the // field offsets. @@ -236,7 +348,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { repr, variants, is_enum, - is_unsafe_cell, + is_special_no_niche, scalar_valid_range, always_sized, present_first, @@ -260,7 +372,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -270,10 +382,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut max_repr_align = repr.align; - // If all the non-ZST fields have the same ABI and union ABI optimizations aren't - // disabled, we can use that common ABI for the union as a whole. + // If all the non-ZST fields have the same repr and union repr optimizations aren't + // disabled, we can use that common repr for the union as a whole. struct AbiMismatch; - let mut common_non_zst_abi_and_align = if repr.inhibits_union_abi_opt() { + let mut common_non_zst_repr_and_align = if repr.inhibits_union_abi_opt() { // Can't optimize Err(AbiMismatch) } else { @@ -297,18 +409,18 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { continue; } - if let Ok(common) = common_non_zst_abi_and_align { + if let Ok(common) = common_non_zst_repr_and_align { // Discard valid range information and allow undef - let field_abi = field.abi.to_union(); + let field_abi = field.backend_repr.to_union(); if let Some((common_abi, common_align)) = common { if common_abi != field_abi { // Different fields have different ABI: disable opt - common_non_zst_abi_and_align = Err(AbiMismatch); + common_non_zst_repr_and_align = Err(AbiMismatch); } else { // Fields with the same non-Aggregate ABI should also // have the same alignment - if !matches!(common_abi, Abi::Aggregate { .. }) { + if !matches!(common_abi, BackendRepr::Memory { .. }) { assert_eq!( common_align, field.align.abi, "non-Aggregate field with matching ABI but differing alignment" @@ -317,7 +429,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } } else { // First non-ZST field: record its ABI and alignment - common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi))); + common_non_zst_repr_and_align = Ok(Some((field_abi, field.align.abi))); } } } @@ -336,31 +448,49 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // If all non-ZST fields have the same ABI, we may forward that ABI // for the union as a whole, unless otherwise inhibited. - let abi = match common_non_zst_abi_and_align { - Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true }, - Ok(Some((abi, _))) => { - if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) { - // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt - Abi::Aggregate { sized: true } - } else { - abi + let backend_repr = match common_non_zst_repr_and_align { + Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true }, + Ok(Some((repr, _))) => match repr { + // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _) + if repr.scalar_align(dl).unwrap() != align.abi => + { + BackendRepr::Memory { sized: true } } - } + // Vectors require at least element alignment, else disable the opt + BackendRepr::SimdVector { element, count: _ } + if element.align(dl).abi > align.abi => + { + BackendRepr::Memory { sized: true } + } + // the alignment tests passed and we can use this + BackendRepr::Scalar(..) + | BackendRepr::ScalarPair(..) + | BackendRepr::SimdVector { .. } + | BackendRepr::Memory { .. } => repr, + }, }; let Some(union_field_count) = NonZeroUsize::new(only_variant.len()) else { return Err(LayoutCalculatorError::EmptyUnion); }; - Ok(LayoutS { + let combined_seed = only_variant + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + + Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), - abi, + backend_repr, largest_niche: None, + uninhabited: false, align, size: size.align_to(align.abi), max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }) } @@ -369,13 +499,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>, is_enum: bool, - is_unsafe_cell: bool, + is_special_no_niche: bool, scalar_valid_range: (Bound<u128>, Bound<u128>), always_sized: bool, present_first: VariantIdx, @@ -394,7 +524,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let mut st = self.univariant(&variants[v], repr, kind)?; st.variants = Variants::Single { index: v }; - if is_unsafe_cell { + if is_special_no_niche { let hide_niches = |scalar: &mut _| match scalar { Scalar::Initialized { value, valid_range } => { *valid_range = WrappingRange::full(value.size(dl)) @@ -402,23 +532,22 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Already doesn't have any niches Scalar::Union { .. } => {} }; - match &mut st.abi { - Abi::Uninhabited => {} - Abi::Scalar(scalar) => hide_niches(scalar), - Abi::ScalarPair(a, b) => { + match &mut st.backend_repr { + BackendRepr::Scalar(scalar) => hide_niches(scalar), + BackendRepr::ScalarPair(a, b) => { hide_niches(a); hide_niches(b); } - Abi::Vector { element, count: _ } => hide_niches(element), - Abi::Aggregate { sized: _ } => {} + BackendRepr::SimdVector { element, count: _ } => hide_niches(element), + BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; return Ok(st); } let (start, end) = scalar_valid_range; - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { + match st.backend_repr { + BackendRepr::Scalar(ref mut scalar) | BackendRepr::ScalarPair(ref mut scalar, _) => { // Enlarging validity ranges would result in missed // optimizations, *not* wrongly assuming the inner // value is valid. e.g. unions already enlarge validity ranges, @@ -469,7 +598,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -484,11 +613,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // overall LayoutS. Store the overall LayoutS // and the variant LayoutSs here until then. struct TmpLayout<FieldIdx: Idx, VariantIdx: Idx> { - layout: LayoutS<FieldIdx, VariantIdx>, - variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>, + layout: LayoutData<FieldIdx, VariantIdx>, + variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>, } let dl = self.cx.data_layout(); + // bail if the enum has an incoherent repr that cannot be computed + if repr.packed() { + return Err(LayoutCalculatorError::ReprConflict); + } let calculate_niche_filling_layout = || -> Option<TmpLayout<FieldIdx, VariantIdx>> { if dont_niche_optimize_enum { @@ -571,8 +704,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } // It can't be a Scalar or ScalarPair because the offset isn't 0. - if !layout.abi.is_uninhabited() { - layout.abi = Abi::Aggregate { sized: true }; + if !layout.is_uninhabited() { + layout.backend_repr = BackendRepr::Memory { sized: true }; } layout.size += this_offset; @@ -591,29 +724,33 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let same_size = size == variant_layouts[largest_variant_index].size; let same_align = align == variant_layouts[largest_variant_index].align; - let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { - Abi::Uninhabited - } else if same_size && same_align && others_zst { - match variant_layouts[largest_variant_index].abi { + let uninhabited = variant_layouts.iter().all(|v| v.is_uninhabited()); + let abi = if same_size && same_align && others_zst { + match variant_layouts[largest_variant_index].backend_repr { // When the total alignment and size match, we can use the // same ABI as the scalar variant with the reserved niche. - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { + BackendRepr::Scalar(_) => BackendRepr::Scalar(niche_scalar), + BackendRepr::ScalarPair(first, second) => { // Only the niche is guaranteed to be initialised, // so use union layouts for the other primitive. if niche_offset == Size::ZERO { - Abi::ScalarPair(niche_scalar, second.to_union()) + BackendRepr::ScalarPair(niche_scalar, second.to_union()) } else { - Abi::ScalarPair(first.to_union(), niche_scalar) + BackendRepr::ScalarPair(first.to_union(), niche_scalar) } } - _ => Abi::Aggregate { sized: true }, + _ => BackendRepr::Memory { sized: true }, } } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; - let layout = LayoutS { + let combined_seed = variant_layouts + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + + let layout = LayoutData { variants: Variants::Multiple { tag: niche_scalar, tag_encoding: TagEncoding::Niche { @@ -628,12 +765,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { offsets: [niche_offset].into(), memory_index: [0].into(), }, - abi, + backend_repr: abi, largest_niche, + uninhabited, size, align, max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }; Some(TmpLayout { layout, variants: variant_layouts }) @@ -645,7 +784,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let discr_type = repr.discr_type(); let bits = Integer::from_attr(dl, discr_type).size().bits(); for (i, mut val) in discriminants { - if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) { + if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) { continue; } if discr_type.is_signed() { @@ -797,14 +936,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { end: (max as u128 & tag_mask), }, }; - let mut abi = Abi::Aggregate { sized: true }; + let mut abi = BackendRepr::Memory { sized: true }; - if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } else if tag.size(dl) == size { + let uninhabited = layout_variants.iter().all(|v| v.is_uninhabited()); + if tag.size(dl) == size { // Make sure we only use scalar layout when the enum is entirely its // own tag (i.e. it has no padding nor any non-ZST variant fields). - abi = Abi::Scalar(tag); + abi = BackendRepr::Scalar(tag); } else { // Try to use a ScalarPair for all tagged enums. // That's possible only if we can find a common primitive type for all variants. @@ -828,8 +966,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { break; } }; - let prim = match field.abi { - Abi::Scalar(scalar) => { + let prim = match field.backend_repr { + BackendRepr::Scalar(scalar) => { common_prim_initialized_in_all_variants &= matches!(scalar, Scalar::Initialized { .. }); scalar.primitive() @@ -883,7 +1021,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Common prim might be uninit. Scalar::Union { value: prim } }; - let pair = self.scalar_pair::<FieldIdx, VariantIdx>(tag, prim_scalar); + let pair = + LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index.raw, [0, 1]); @@ -898,7 +1037,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { { // We can use `ScalarPair` only when it matches our // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + abi = pair.backend_repr; } } } @@ -906,12 +1045,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the // variants to ensure they are consistent. This is because a downcast is // semantically a NOP, and thus should not affect layout. - if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { for variant in &mut layout_variants { // We only do this for variants with fields; the others are not accessed anyway. // Also do not overwrite any already existing "clever" ABIs. - if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) { - variant.abi = abi; + if variant.fields.count() > 0 + && matches!(variant.backend_repr, BackendRepr::Memory { .. }) + { + variant.backend_repr = abi; // Also need to bump up the size and alignment, so that the entire value fits // in here. variant.size = cmp::max(variant.size, size); @@ -922,7 +1063,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - let tagged_layout = LayoutS { + let combined_seed = layout_variants + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + + let tagged_layout = LayoutData { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, @@ -934,11 +1080,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { memory_index: [0].into(), }, largest_niche, - abi, + uninhabited, + backend_repr: abi, align, size, max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }; let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; @@ -966,8 +1114,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Variants::Multiple { tag, tag_encoding, tag_field, .. } => { Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants } } - Variants::Single { .. } => { - panic!("encountered a single-variant enum during multi-variant layout") + Variants::Single { .. } | Variants::Empty => { + panic!("encountered a single-variant or empty enum during multi-variant layout") } }; Ok(best_layout.layout) @@ -977,7 +1125,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy, >( &self, fields: &IndexSlice<FieldIdx, F>, @@ -991,12 +1139,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let mut max_repr_align = repr.align; let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect(); let optimize_field_order = !repr.inhibit_struct_field_reordering(); - if optimize_field_order && fields.len() > 1 { - let end = - if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index.raw[..end]; - let fields_excluding_tail = &fields.raw[..end]; + let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; + let optimizing = &mut inverse_memory_index.raw[..end]; + let fields_excluding_tail = &fields.raw[..end]; + // unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts. + let field_seed = fields_excluding_tail + .iter() + .fold(Hash64::ZERO, |acc, f| acc.wrapping_add(f.randomization_seed)); + if optimize_field_order && fields.len() > 1 { // If `-Z randomize-layout` was enabled for the type definition we can shuffle // the field ordering to try and catch some code making assumptions about layouts // we don't guarantee. @@ -1007,8 +1158,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { use rand::seq::SliceRandom; // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field // ordering. - let mut rng = - rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); + let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64( + field_seed.wrapping_add(repr.field_shuffle_seed).as_u64(), + ); // Shuffle the ordering of the fields. optimizing.shuffle(&mut rng); @@ -1216,7 +1368,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } let mut layout_of_single_non_zst_field = None; let sized = unsized_field.is_none(); - let mut abi = Abi::Aggregate { sized }; + let mut abi = BackendRepr::Memory { sized }; let optimize_abi = !repr.inhibit_newtype_abi_optimization(); @@ -1234,16 +1386,18 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Field fills the struct and it has a scalar or scalar pair ABI. if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size { - match field.abi { + match field.backend_repr { // For plain scalars, or vectors of them, we can't unpack // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize_abi => { - abi = field.abi; + BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + if optimize_abi => + { + abi = field.backend_repr; } // But scalar pairs are Rust-specific and get // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi; + BackendRepr::ScalarPair(..) => { + abi = field.backend_repr; } _ => {} } @@ -1252,15 +1406,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Two non-ZST fields, and they're both scalars. (Some((i, a)), Some((j, b)), None) => { - match (a.abi, b.abi) { - (Abi::Scalar(a), Abi::Scalar(b)) => { + match (a.backend_repr, b.backend_repr) { + (BackendRepr::Scalar(a), BackendRepr::Scalar(b)) => { // Order by the memory placement, not source order. let ((i, a), (j, b)) = if offsets[i] < offsets[j] { ((i, a), (j, b)) } else { ((j, b), (i, a)) }; - let pair = self.scalar_pair::<FieldIdx, VariantIdx>(a, b); + let pair = + LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index.raw, [0, 1]); @@ -1279,7 +1434,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { { // We can use `ScalarPair` only when it matches our // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + abi = pair.backend_repr; } } _ => {} @@ -1289,9 +1444,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { _ => {} } } - if fields.iter().any(|f| f.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } + let uninhabited = fields.iter().any(|f| f.is_uninhabited()); let unadjusted_abi_align = if repr.transparent() { match layout_of_single_non_zst_field { @@ -1305,15 +1458,19 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { unadjusted_abi_align }; - Ok(LayoutS { + let seed = field_seed.wrapping_add(repr.field_shuffle_seed); + + Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, - abi, + backend_repr: abi, largest_niche, + uninhabited, align, size, max_repr_align, unadjusted_abi_align, + randomization_seed: seed, }) } @@ -1321,10 +1478,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug, + F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug, >( &self, - layout: &LayoutS<FieldIdx, VariantIdx>, + layout: &LayoutData<FieldIdx, VariantIdx>, fields: &IndexSlice<FieldIdx, F>, ) -> String { let dl = self.cx.data_layout(); diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs new file mode 100644 index 0000000000000..27e704d538c83 --- /dev/null +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -0,0 +1,320 @@ +//! Coroutine layout logic. +//! +//! When laying out coroutines, we divide our saved local fields into two +//! categories: overlap-eligible and overlap-ineligible. +//! +//! Those fields which are ineligible for overlap go in a "prefix" at the +//! beginning of the layout, and always have space reserved for them. +//! +//! Overlap-eligible fields are only assigned to one variant, so we lay +//! those fields out for each variant and put them right after the +//! prefix. +//! +//! Finally, in the layout details, we point to the fields from the +//! variants they are assigned to. It is possible for some fields to be +//! included in multiple variants. No field ever "moves around" in the +//! layout; its offset is always the same. +//! +//! Also included in the layout are the upvars and the discriminant. +//! These are included as fields on the "outer" layout; they are not part +//! of any variant. + +use std::iter; + +use rustc_index::bit_set::{BitMatrix, DenseBitSet}; +use rustc_index::{Idx, IndexSlice, IndexVec}; +use tracing::{debug, trace}; + +use crate::{ + BackendRepr, FieldsShape, HasDataLayout, Integer, LayoutData, Primitive, ReprOptions, Scalar, + StructKind, TagEncoding, Variants, WrappingRange, +}; + +/// Overlap eligibility and variant assignment for each CoroutineSavedLocal. +#[derive(Clone, Debug, PartialEq)] +enum SavedLocalEligibility<VariantIdx, FieldIdx> { + Unassigned, + Assigned(VariantIdx), + Ineligible(Option<FieldIdx>), +} + +/// Compute the eligibility and assignment of each local. +fn coroutine_saved_local_eligibility<VariantIdx: Idx, FieldIdx: Idx, LocalIdx: Idx>( + nb_locals: usize, + variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>, + storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>, +) -> (DenseBitSet<LocalIdx>, IndexVec<LocalIdx, SavedLocalEligibility<VariantIdx, FieldIdx>>) { + use SavedLocalEligibility::*; + + let mut assignments: IndexVec<LocalIdx, _> = IndexVec::from_elem_n(Unassigned, nb_locals); + + // The saved locals not eligible for overlap. These will get + // "promoted" to the prefix of our coroutine. + let mut ineligible_locals = DenseBitSet::new_empty(nb_locals); + + // Figure out which of our saved locals are fields in only + // one variant. The rest are deemed ineligible for overlap. + for (variant_index, fields) in variant_fields.iter_enumerated() { + for local in fields { + match assignments[*local] { + Unassigned => { + assignments[*local] = Assigned(variant_index); + } + Assigned(idx) => { + // We've already seen this local at another suspension + // point, so it is no longer a candidate. + trace!( + "removing local {:?} in >1 variant ({:?}, {:?})", + local, variant_index, idx + ); + ineligible_locals.insert(*local); + assignments[*local] = Ineligible(None); + } + Ineligible(_) => {} + } + } + } + + // Next, check every pair of eligible locals to see if they + // conflict. + for local_a in storage_conflicts.rows() { + let conflicts_a = storage_conflicts.count(local_a); + if ineligible_locals.contains(local_a) { + continue; + } + + for local_b in storage_conflicts.iter(local_a) { + // local_a and local_b are storage live at the same time, therefore they + // cannot overlap in the coroutine layout. The only way to guarantee + // this is if they are in the same variant, or one is ineligible + // (which means it is stored in every variant). + if ineligible_locals.contains(local_b) || assignments[local_a] == assignments[local_b] { + continue; + } + + // If they conflict, we will choose one to make ineligible. + // This is not always optimal; it's just a greedy heuristic that + // seems to produce good results most of the time. + let conflicts_b = storage_conflicts.count(local_b); + let (remove, other) = + if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) }; + ineligible_locals.insert(remove); + assignments[remove] = Ineligible(None); + trace!("removing local {:?} due to conflict with {:?}", remove, other); + } + } + + // Count the number of variants in use. If only one of them, then it is + // impossible to overlap any locals in our layout. In this case it's + // always better to make the remaining locals ineligible, so we can + // lay them out with the other locals in the prefix and eliminate + // unnecessary padding bytes. + { + let mut used_variants = DenseBitSet::new_empty(variant_fields.len()); + for assignment in &assignments { + if let Assigned(idx) = assignment { + used_variants.insert(*idx); + } + } + if used_variants.count() < 2 { + for assignment in assignments.iter_mut() { + *assignment = Ineligible(None); + } + ineligible_locals.insert_all(); + } + } + + // Write down the order of our locals that will be promoted to the prefix. + { + for (idx, local) in ineligible_locals.iter().enumerate() { + assignments[local] = Ineligible(Some(FieldIdx::new(idx))); + } + } + debug!("coroutine saved local assignments: {:?}", assignments); + + (ineligible_locals, assignments) +} + +/// Compute the full coroutine layout. +pub(super) fn layout< + 'a, + F: core::ops::Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + core::fmt::Debug + Copy, + VariantIdx: Idx, + FieldIdx: Idx, + LocalIdx: Idx, +>( + calc: &super::LayoutCalculator<impl HasDataLayout>, + local_layouts: &IndexSlice<LocalIdx, F>, + mut prefix_layouts: IndexVec<FieldIdx, F>, + variant_fields: &IndexSlice<VariantIdx, IndexVec<FieldIdx, LocalIdx>>, + storage_conflicts: &BitMatrix<LocalIdx, LocalIdx>, + tag_to_layout: impl Fn(Scalar) -> F, +) -> super::LayoutCalculatorResult<FieldIdx, VariantIdx, F> { + use SavedLocalEligibility::*; + + let (ineligible_locals, assignments) = + coroutine_saved_local_eligibility(local_layouts.len(), variant_fields, storage_conflicts); + + // Build a prefix layout, including "promoting" all ineligible + // locals as part of the prefix. We compute the layout of all of + // these fields at once to get optimal packing. + let tag_index = prefix_layouts.len(); + + // `variant_fields` already accounts for the reserved variants, so no need to add them. + let max_discr = (variant_fields.len() - 1) as u128; + let discr_int = Integer::fit_unsigned(max_discr); + let tag = Scalar::Initialized { + value: Primitive::Int(discr_int, /* signed = */ false), + valid_range: WrappingRange { start: 0, end: max_discr }, + }; + + let promoted_layouts = ineligible_locals.iter().map(|local| local_layouts[local]); + prefix_layouts.push(tag_to_layout(tag)); + prefix_layouts.extend(promoted_layouts); + let prefix = + calc.univariant(&prefix_layouts, &ReprOptions::default(), StructKind::AlwaysSized)?; + + let (prefix_size, prefix_align) = (prefix.size, prefix.align); + + // Split the prefix layout into the "outer" fields (upvars and + // discriminant) and the "promoted" fields. Promoted fields will + // get included in each variant that requested them in + // CoroutineLayout. + debug!("prefix = {:#?}", prefix); + let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { + FieldsShape::Arbitrary { mut offsets, memory_index } => { + let mut inverse_memory_index = memory_index.invert_bijective_mapping(); + + // "a" (`0..b_start`) and "b" (`b_start..`) correspond to + // "outer" and "promoted" fields respectively. + let b_start = FieldIdx::new(tag_index + 1); + let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index())); + let offsets_a = offsets; + + // Disentangle the "a" and "b" components of `inverse_memory_index` + // by preserving the order but keeping only one disjoint "half" each. + // FIXME(eddyb) build a better abstraction for permutations, if possible. + let inverse_memory_index_b: IndexVec<u32, FieldIdx> = inverse_memory_index + .iter() + .filter_map(|&i| i.index().checked_sub(b_start.index()).map(FieldIdx::new)) + .collect(); + inverse_memory_index.raw.retain(|&i| i.index() < b_start.index()); + let inverse_memory_index_a = inverse_memory_index; + + // Since `inverse_memory_index_{a,b}` each only refer to their + // respective fields, they can be safely inverted + let memory_index_a = inverse_memory_index_a.invert_bijective_mapping(); + let memory_index_b = inverse_memory_index_b.invert_bijective_mapping(); + + let outer_fields = + FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; + (outer_fields, offsets_b, memory_index_b) + } + _ => unreachable!(), + }; + + let mut size = prefix.size; + let mut align = prefix.align; + let variants = variant_fields + .iter_enumerated() + .map(|(index, variant_fields)| { + // Only include overlap-eligible fields when we compute our variant layout. + let variant_only_tys = variant_fields + .iter() + .filter(|local| match assignments[**local] { + Unassigned => unreachable!(), + Assigned(v) if v == index => true, + Assigned(_) => unreachable!("assignment does not match variant"), + Ineligible(_) => false, + }) + .map(|local| local_layouts[*local]); + + let mut variant = calc.univariant( + &variant_only_tys.collect::<IndexVec<_, _>>(), + &ReprOptions::default(), + StructKind::Prefixed(prefix_size, prefix_align.abi), + )?; + variant.variants = Variants::Single { index }; + + let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else { + unreachable!(); + }; + + // Now, stitch the promoted and variant-only fields back together in + // the order they are mentioned by our CoroutineLayout. + // Because we only use some subset (that can differ between variants) + // of the promoted fields, we can't just pick those elements of the + // `promoted_memory_index` (as we'd end up with gaps). + // So instead, we build an "inverse memory_index", as if all of the + // promoted fields were being used, but leave the elements not in the + // subset as `invalid_field_idx`, which we can filter out later to + // obtain a valid (bijective) mapping. + let invalid_field_idx = promoted_memory_index.len() + memory_index.len(); + let mut combined_inverse_memory_index = + IndexVec::from_elem_n(FieldIdx::new(invalid_field_idx), invalid_field_idx); + + let mut offsets_and_memory_index = iter::zip(offsets, memory_index); + let combined_offsets = variant_fields + .iter_enumerated() + .map(|(i, local)| { + let (offset, memory_index) = match assignments[*local] { + Unassigned => unreachable!(), + Assigned(_) => { + let (offset, memory_index) = offsets_and_memory_index.next().unwrap(); + (offset, promoted_memory_index.len() as u32 + memory_index) + } + Ineligible(field_idx) => { + let field_idx = field_idx.unwrap(); + (promoted_offsets[field_idx], promoted_memory_index[field_idx]) + } + }; + combined_inverse_memory_index[memory_index] = i; + offset + }) + .collect(); + + // Remove the unused slots and invert the mapping to obtain the + // combined `memory_index` (also see previous comment). + combined_inverse_memory_index.raw.retain(|&i| i.index() != invalid_field_idx); + let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping(); + + variant.fields = FieldsShape::Arbitrary { + offsets: combined_offsets, + memory_index: combined_memory_index, + }; + + size = size.max(variant.size); + align = align.max(variant.align); + Ok(variant) + }) + .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; + + size = size.align_to(align.abi); + + let uninhabited = prefix.uninhabited || variants.iter().all(|v| v.is_uninhabited()); + let abi = BackendRepr::Memory { sized: true }; + + Ok(LayoutData { + variants: Variants::Multiple { + tag, + tag_encoding: TagEncoding::Direct, + tag_field: tag_index, + variants, + }, + fields: outer_fields, + backend_repr: abi, + // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to + // self-referentiality), getting the discriminant can cause aliasing violations. + // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that + // would do the same for us here. + // See <https://github.com/rust-lang/rust/issues/63818>, <https://github.com/rust-lang/miri/issues/3780>. + // FIXME: Remove when <https://github.com/rust-lang/rust/issues/125735> is implemented and aliased coroutine fields are wrapped in `UnsafePinned`. + largest_niche: None, + uninhabited, + size, + align, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Default::default(), + }) +} diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs new file mode 100644 index 0000000000000..0d0706defc2e5 --- /dev/null +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -0,0 +1,148 @@ +use std::num::NonZero; + +use rustc_hashes::Hash64; +use rustc_index::{Idx, IndexVec}; + +use crate::{ + BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants, +}; + +/// "Simple" layout constructors that cannot fail. +impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { + pub fn unit<C: HasDataLayout>(cx: &C, sized: bool) -> Self { + let dl = cx.data_layout(); + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Arbitrary { + offsets: IndexVec::new(), + memory_index: IndexVec::new(), + }, + backend_repr: BackendRepr::Memory { sized }, + largest_niche: None, + uninhabited: false, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::new(0), + } + } + + pub fn never_type<C: HasDataLayout>(cx: &C) -> Self { + let dl = cx.data_layout(); + // This is also used for uninhabited enums, so we use `Variants::Empty`. + LayoutData { + variants: Variants::Empty, + fields: FieldsShape::Primitive, + backend_repr: BackendRepr::Memory { sized: true }, + largest_niche: None, + uninhabited: true, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::ZERO, + } + } + + pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self { + let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); + let size = scalar.size(cx); + let align = scalar.align(cx); + + let range = scalar.valid_range(cx); + + // All primitive types for which we don't have subtype coercions should get a distinct seed, + // so that types wrapping them can use randomization to arrive at distinct layouts. + // + // Some type information is already lost at this point, so as an approximation we derive + // the seed from what remains. For example on 64-bit targets usize and u64 can no longer + // be distinguished. + let randomization_seed = size + .bytes() + .wrapping_add( + match scalar.primitive() { + Primitive::Int(_, true) => 1, + Primitive::Int(_, false) => 2, + Primitive::Float(_) => 3, + Primitive::Pointer(_) => 4, + } << 32, + ) + // distinguishes references from pointers + .wrapping_add((range.start as u64).rotate_right(16)) + // distinguishes char from u32 and bool from u8 + .wrapping_add((range.end as u64).rotate_right(16)); + + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Primitive, + backend_repr: BackendRepr::Scalar(scalar), + largest_niche, + uninhabited: false, + size, + align, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Hash64::new(randomization_seed), + } + } + + pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self { + let dl = cx.data_layout(); + let b_align = b.align(dl); + let align = a.align(dl).max(b_align).max(dl.aggregate_align); + let b_offset = a.size(dl).align_to(b_align.abi); + let size = (b_offset + b.size(dl)).align_to(align.abi); + + // HACK(nox): We iter on `b` and then `a` because `max_by_key` + // returns the last maximum. + let largest_niche = Niche::from_scalar(dl, b_offset, b) + .into_iter() + .chain(Niche::from_scalar(dl, Size::ZERO, a)) + .max_by_key(|niche| niche.available(dl)); + + let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes()); + + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Arbitrary { + offsets: [Size::ZERO, b_offset].into(), + memory_index: [0, 1].into(), + }, + backend_repr: BackendRepr::ScalarPair(a, b), + largest_niche, + uninhabited: false, + align, + size, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Hash64::new(combined_seed), + } + } + + /// Returns a dummy layout for an uninhabited variant. + /// + /// Uninhabited variants get pruned as part of the layout calculation, + /// so this can be used after the fact to reconstitute a layout. + pub fn uninhabited_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self { + let dl = cx.data_layout(); + LayoutData { + variants: Variants::Single { index }, + fields: match NonZero::new(fields) { + Some(fields) => FieldsShape::Union(fields), + None => FieldsShape::Arbitrary { + offsets: IndexVec::new(), + memory_index: IndexVec::new(), + }, + }, + backend_repr: BackendRepr::Memory { sized: true }, + largest_niche: None, + uninhabited: true, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::ZERO, + } + } +} diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index c6812c4d4c075..4f43c0e6f8e96 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -1,13 +1,15 @@ use std::fmt; use std::ops::Deref; -use Float::*; -use Primitive::*; use rustc_data_structures::intern::Interned; use rustc_macros::HashStable_Generic; +use crate::{ + AbiAndPrefAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche, + PointeeInfo, Primitive, Scalar, Size, TargetDataLayout, Variants, +}; + // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`. -use crate::{Float, *}; rustc_index::newtype_index! { /// The *source-order* index of a field in a variant. @@ -58,7 +60,7 @@ rustc_index::newtype_index! { } #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] #[rustc_pass_by_value] -pub struct Layout<'a>(pub Interned<'a, LayoutS<FieldIdx, VariantIdx>>); +pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>); impl<'a> fmt::Debug for Layout<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -68,8 +70,8 @@ impl<'a> fmt::Debug for Layout<'a> { } impl<'a> Deref for Layout<'a> { - type Target = &'a LayoutS<FieldIdx, VariantIdx>; - fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> { + type Target = &'a LayoutData<FieldIdx, VariantIdx>; + fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> { &self.0.0 } } @@ -83,8 +85,8 @@ impl<'a> Layout<'a> { &self.0.0.variants } - pub fn abi(self) -> Abi { - self.0.0.abi + pub fn backend_repr(self) -> BackendRepr { + self.0.0.backend_repr } pub fn largest_niche(self) -> Option<Niche> { @@ -114,7 +116,7 @@ impl<'a> Layout<'a> { pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool { self.size() == data_layout.pointer_size && self.align().abi == data_layout.pointer_align.abi - && matches!(self.abi(), Abi::Scalar(Scalar::Initialized { .. })) + && matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. })) } } @@ -142,12 +144,18 @@ impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> { } impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { - type Target = &'a LayoutS<FieldIdx, VariantIdx>; - fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> { + type Target = &'a LayoutData<FieldIdx, VariantIdx>; + fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> { &self.layout.0.0 } } +impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> { + fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> { + &*self.layout.0.0 + } +} + /// Trait that needs to be implemented by the higher-level type representation /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality. pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug { @@ -196,9 +204,11 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty: TyAbiInterface<'a, C>, C: HasDataLayout, { - match self.abi { - Abi::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)), - Abi::Aggregate { .. } => { + match self.backend_repr { + BackendRepr::Scalar(scalar) => { + matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64)) + } + BackendRepr::Memory { .. } => { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { self.field(cx, 0).is_single_fp_element(cx) } else { @@ -209,6 +219,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { } } + pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool + where + Ty: TyAbiInterface<'a, C>, + C: HasDataLayout, + { + match self.backend_repr { + BackendRepr::SimdVector { .. } => self.size == expected_size, + BackendRepr::Memory { .. } => { + if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { + self.field(cx, 0).is_single_vector_element(cx, expected_size) + } else { + false + } + } + _ => false, + } + } + pub fn is_adt<C>(self) -> bool where Ty: TyAbiInterface<'a, C>, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 84d756b6d517c..59b74d2922145 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1,12 +1,44 @@ // tidy-alphabetical-start #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", doc(rust_logo))] +#![cfg_attr(feature = "nightly", feature(assert_matches))] #![cfg_attr(feature = "nightly", feature(rustc_attrs))] #![cfg_attr(feature = "nightly", feature(rustdoc_internals))] #![cfg_attr(feature = "nightly", feature(step_trait))] -#![warn(unreachable_pub)] // tidy-alphabetical-end +/*! ABI handling for rustc + +## What is an "ABI"? + +Literally, "application binary interface", which means it is everything about how code interacts, +at the machine level, with other code. This means it technically covers all of the following: +- object binary format for e.g. relocations or offset tables +- in-memory layout of types +- procedure calling conventions + +When we discuss "ABI" in the context of rustc, we are probably discussing calling conventions. +To describe those `rustc_abi` also covers type layout, as it must for values passed on the stack. +Despite `rustc_abi` being about calling conventions, it is good to remember these usages exist. +You will encounter all of them and more if you study target-specific codegen enough! +Even in general conversation, when someone says "the Rust ABI is unstable", it may allude to +either or both of +- `repr(Rust)` types have a mostly-unspecified layout +- `extern "Rust" fn(A) -> R` has an unspecified calling convention + +## Crate Goal + +ABI is a foundational concept, so the `rustc_abi` crate serves as an equally foundational crate. +It cannot carry all details relevant to an ABI: those permeate code generation and linkage. +Instead, `rustc_abi` is intended to provide the interface for reasoning about the binary interface. +It should contain traits and types that other crates then use in their implementation. +For example, a platform's `extern "C" fn` calling convention will be implemented in `rustc_target` +but `rustc_abi` contains the types for calculating layout and describing register-passing. +This makes it easier to describe things in the same way across targets, codegen backends, and +even other Rust compilers, such as rust-analyzer! + +*/ + use std::fmt; #[cfg(feature = "nightly")] use std::iter::Step; @@ -17,30 +49,35 @@ use std::str::FromStr; use bitflags::bitflags; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::StableOrd; +use rustc_hashes::Hash64; use rustc_index::{Idx, IndexSlice, IndexVec}; #[cfg(feature = "nightly")] -use rustc_macros::HashStable_Generic; -#[cfg(feature = "nightly")] -use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic}; mod callconv; mod layout; #[cfg(test)] mod tests; +mod extern_abi; + pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; -pub use layout::{ - FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface, - TyAndLayout, VariantIdx, -}; +pub use extern_abi::{ExternAbi, all_names}; +#[cfg(feature = "nightly")] +pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; +pub use layout::{LayoutCalculator, LayoutCalculatorError}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. +#[cfg(feature = "nightly")] pub trait HashStableContext {} #[derive(Clone, Copy, PartialEq, Eq, Default)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub struct ReprFlags(u8); bitflags! { @@ -72,7 +109,10 @@ impl std::fmt::Debug for ReprFlags { } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub enum IntegerType { /// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g. /// `Pointer(true)` means `isize`. @@ -93,7 +133,10 @@ impl IntegerType { /// Represents the repr options provided by the user. #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub struct ReprOptions { pub int: Option<IntegerType>, pub align: Option<Align>, @@ -106,7 +149,7 @@ pub struct ReprOptions { /// hash without loss, but it does pay the price of being larger. /// Everything's a tradeoff, a 64-bit seed should be sufficient for our /// purposes (primarily `-Z randomize-layout`) - pub field_shuffle_seed: u64, + pub field_shuffle_seed: Hash64, } impl ReprOptions { @@ -170,6 +213,13 @@ impl ReprOptions { } } +/// The maximum supported number of lanes in a SIMD vector. +/// +/// This value is selected based on backend support: +/// * LLVM does not appear to have a vector width limit. +/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer. +pub const MAX_SIMD_LANES: u64 = 1 << 0xF; + /// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout) /// for a target, which contains everything needed to compute layouts. #[derive(Debug, PartialEq, Eq)] @@ -294,19 +344,19 @@ impl TargetDataLayout { [p] if p.starts_with('P') => { dl.instruction_address_space = parse_address_space(&p[1..], "P")? } - ["a", ref a @ ..] => dl.aggregate_align = parse_align(a, "a")?, - ["f16", ref a @ ..] => dl.f16_align = parse_align(a, "f16")?, - ["f32", ref a @ ..] => dl.f32_align = parse_align(a, "f32")?, - ["f64", ref a @ ..] => dl.f64_align = parse_align(a, "f64")?, - ["f128", ref a @ ..] => dl.f128_align = parse_align(a, "f128")?, + ["a", a @ ..] => dl.aggregate_align = parse_align(a, "a")?, + ["f16", a @ ..] => dl.f16_align = parse_align(a, "f16")?, + ["f32", a @ ..] => dl.f32_align = parse_align(a, "f32")?, + ["f64", a @ ..] => dl.f64_align = parse_align(a, "f64")?, + ["f128", a @ ..] => dl.f128_align = parse_align(a, "f128")?, // FIXME(erikdesjardins): we should be parsing nonzero address spaces // this will require replacing TargetDataLayout::{pointer_size,pointer_align} // with e.g. `fn pointer_size_in(AddressSpace)` - [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => { + [p @ "p", s, a @ ..] | [p @ "p0", s, a @ ..] => { dl.pointer_size = parse_size(s, p)?; dl.pointer_align = parse_align(a, p)?; } - [s, ref a @ ..] if s.starts_with('i') => { + [s, a @ ..] if s.starts_with('i') => { let Ok(bits) = s[1..].parse::<u64>() else { parse_size(&s[1..], "i")?; // For the user error. continue; @@ -327,7 +377,7 @@ impl TargetDataLayout { dl.i128_align = a; } } - [s, ref a @ ..] if s.starts_with('v') => { + [s, a @ ..] if s.starts_with('v') => { let v_size = parse_size(&s[1..], "v")?; let a = parse_align(a, s)?; if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) { @@ -373,16 +423,21 @@ impl TargetDataLayout { } } + /// psABI-mandated alignment for a vector type, if any #[inline] - pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign { - for &(size, align) in &self.vector_align { - if size == vec_size { - return align; - } - } - // Default to natural alignment, which is what LLVM does. - // That is, use the size, rounded up to a power of 2. - AbiAndPrefAlign::new(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap()) + fn cabi_vector_align(&self, vec_size: Size) -> Option<AbiAndPrefAlign> { + self.vector_align + .iter() + .find(|(size, _align)| *size == vec_size) + .map(|(_size, align)| *align) + } + + /// an alignment resembling the one LLVM would pick for a vector + #[inline] + pub fn llvmlike_vector_align(&self, vec_size: Size) -> AbiAndPrefAlign { + self.cabi_vector_align(vec_size).unwrap_or(AbiAndPrefAlign::new( + Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(), + )) } } @@ -441,7 +496,10 @@ impl FromStr for Endian { /// Size of a type in bytes. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub struct Size { raw: u64, } @@ -630,7 +688,7 @@ impl AddAssign for Size { #[cfg(feature = "nightly")] impl Step for Size { #[inline] - fn steps_between(start: &Self, end: &Self) -> Option<usize> { + fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) { u64::steps_between(&start.bytes(), &end.bytes()) } @@ -667,7 +725,10 @@ impl Step for Size { /// Alignment of a type in bytes (always a power of two). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub struct Align { pow2: u8, } @@ -756,7 +817,7 @@ impl Align { } #[inline] - pub fn bytes(self) -> u64 { + pub const fn bytes(self) -> u64 { 1 << self.pow2 } @@ -766,7 +827,7 @@ impl Align { } #[inline] - pub fn bits(self) -> u64 { + pub const fn bits(self) -> u64 { self.bytes() * 8 } @@ -775,20 +836,19 @@ impl Align { self.bits().try_into().unwrap() } - /// Computes the best alignment possible for the given offset - /// (the largest power of two that the offset is a multiple of). + /// Obtain the greatest factor of `size` that is an alignment + /// (the largest power of two the Size is a multiple of). /// - /// N.B., for an offset of `0`, this happens to return `2^64`. + /// Note that all numbers are factors of 0 #[inline] - pub fn max_for_offset(offset: Size) -> Align { - Align { pow2: offset.bytes().trailing_zeros() as u8 } + pub fn max_aligned_factor(size: Size) -> Align { + Align { pow2: size.bytes().trailing_zeros() as u8 } } - /// Lower the alignment, if necessary, such that the given offset - /// is aligned to it (the offset is a multiple of the alignment). + /// Reduces Align to an aligned factor of `size`. #[inline] - pub fn restrict_for_offset(self, offset: Size) -> Align { - self.min(Align::max_for_offset(offset)) + pub fn restrict_for_offset(self, size: Size) -> Align { + self.min(Align::max_aligned_factor(size)) } } @@ -827,7 +887,10 @@ impl AbiAndPrefAlign { /// Integers, also used for enum discriminants. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub enum Integer { I8, I16, @@ -1144,10 +1207,13 @@ impl Scalar { #[inline] pub fn is_bool(&self) -> bool { use Integer::*; - matches!(self, Scalar::Initialized { - value: Primitive::Int(I8, false), - valid_range: WrappingRange { start: 0, end: 1 } - }) + matches!( + self, + Scalar::Initialized { + value: Primitive::Int(I8, false), + valid_range: WrappingRange { start: 0, end: 1 } + } + ) } /// Get the primitive representation of this type, ignoring the valid range and whether the @@ -1207,6 +1273,15 @@ impl Scalar { Scalar::Union { .. } => true, } } + + /// Returns `true` if this is a signed integer scalar + #[inline] + pub fn is_signed(&self) -> bool { + match self.primitive() { + Primitive::Int(_, signed) => signed, + _ => false, + } + } } // NOTE: This struct is generic over the FieldIdx for rust-analyzer usage. @@ -1298,7 +1373,7 @@ impl<FieldIdx: Idx> FieldsShape<FieldIdx> { /// Gets source indices of the fields by increasing offsets. #[inline] - pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator<Item = usize> + '_ { + pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator<Item = usize> { let mut inverse_small = [0u8; 64]; let mut inverse_big = IndexVec::new(); let use_small = self.count() <= inverse_small.len(); @@ -1344,31 +1419,41 @@ impl AddressSpace { 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. +/// The way we represent values to the backend +/// +/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI. +/// In reality, this implies little about that, but is mostly used to describe the syntactic form +/// emitted for the backend, as most backends handle SSA values and blobs of memory differently. +/// The psABI may need consideration in doing so, but this enum does not constitute a promise for +/// how the value will be lowered to the calling convention, in itself. +/// +/// Generally, a codegen backend will prefer to handle smaller values as a scalar or short vector, +/// and larger values will usually prefer to be represented as memory. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] -pub enum Abi { - Uninhabited, +pub enum BackendRepr { Scalar(Scalar), ScalarPair(Scalar, Scalar), - Vector { + SimdVector { element: Scalar, count: u64, }, - Aggregate { + // FIXME: I sometimes use memory, sometimes use an IR aggregate! + Memory { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, }, } -impl Abi { +impl BackendRepr { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { match *self { - Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, - Abi::Aggregate { sized } => !sized, + BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) + | BackendRepr::SimdVector { .. } => false, + BackendRepr::Memory { sized } => !sized, } } @@ -1377,76 +1462,73 @@ impl Abi { !self.is_unsized() } - /// Returns `true` if this is a single signed integer scalar + /// Returns `true` if this is a single signed integer scalar. + /// Sanity check: panics if this is not a scalar type (see PR #70189). #[inline] pub fn is_signed(&self) -> bool { match self { - Abi::Scalar(scal) => match scal.primitive() { - Primitive::Int(_, signed) => signed, - _ => false, - }, + BackendRepr::Scalar(scal) => scal.is_signed(), _ => panic!("`is_signed` on non-scalar ABI {self:?}"), } } - /// Returns `true` if this is an uninhabited type - #[inline] - pub fn is_uninhabited(&self) -> bool { - matches!(*self, Abi::Uninhabited) - } - /// Returns `true` if this is a scalar type #[inline] pub fn is_scalar(&self) -> bool { - matches!(*self, Abi::Scalar(_)) + matches!(*self, BackendRepr::Scalar(_)) } /// Returns `true` if this is a bool #[inline] pub fn is_bool(&self) -> bool { - matches!(*self, Abi::Scalar(s) if s.is_bool()) + matches!(*self, BackendRepr::Scalar(s) if s.is_bool()) } - /// Returns the fixed alignment of this ABI, if any is mandated. - pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> { - Some(match *self { - Abi::Scalar(s) => s.align(cx), - Abi::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)), - Abi::Vector { element, count } => { - cx.data_layout().vector_align(element.size(cx) * count) - } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, - }) + /// The psABI alignment for a `Scalar` or `ScalarPair` + /// + /// `None` for other variants. + pub fn scalar_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> { + match *self { + BackendRepr::Scalar(s) => Some(s.align(cx).abi), + BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi), + // The align of a Vector can vary in surprising ways + BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None, + } } - /// Returns the fixed size of this ABI, if any is mandated. - pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> { - Some(match *self { - Abi::Scalar(s) => { - // No padding in scalars. - s.size(cx) - } - Abi::ScalarPair(s1, s2) => { - // May have some padding between the pair. + /// The psABI size for a `Scalar` or `ScalarPair` + /// + /// `None` for other variants + pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> { + match *self { + // No padding in scalars. + BackendRepr::Scalar(s) => Some(s.size(cx)), + // May have some padding between the pair. + BackendRepr::ScalarPair(s1, s2) => { let field2_offset = s1.size(cx).align_to(s2.align(cx).abi); - (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi) - } - Abi::Vector { element, count } => { - // No padding in vectors, except possibly for trailing padding - // to make the size a multiple of align (e.g. for vectors of size 3). - (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) + let size = (field2_offset + s2.size(cx)).align_to( + self.scalar_align(cx) + // We absolutely must have an answer here or everything is FUBAR. + .unwrap(), + ); + Some(size) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, - }) + // The size of a Vector can vary in surprising ways + BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None, + } } /// Discard validity range information and allow undef. pub fn to_union(&self) -> Self { match *self { - Abi::Scalar(s) => Abi::Scalar(s.to_union()), - Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()), - Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count }, - Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, + BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()), + BackendRepr::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair(s1.to_union(), s2.to_union()) + } + BackendRepr::SimdVector { element, count } => { + BackendRepr::SimdVector { element: element.to_union(), count } + } + BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true }, } } @@ -1454,12 +1536,12 @@ impl Abi { match (self, other) { // Scalar, Vector, ScalarPair have `Scalar` in them where we ignore validity ranges. // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x). - (Abi::Scalar(l), Abi::Scalar(r)) => l.primitive() == r.primitive(), + (BackendRepr::Scalar(l), BackendRepr::Scalar(r)) => l.primitive() == r.primitive(), ( - Abi::Vector { element: element_l, count: count_l }, - Abi::Vector { element: element_r, count: count_r }, + BackendRepr::SimdVector { element: element_l, count: count_l }, + BackendRepr::SimdVector { element: element_r, count: count_r }, ) => element_l.primitive() == element_r.primitive() && count_l == count_r, - (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => { + (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => { l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive() } // Everything else must be strictly identical. @@ -1472,8 +1554,14 @@ impl Abi { #[derive(PartialEq, Eq, Hash, Clone, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> { + /// A type with no valid variants. Must be uninhabited. + Empty, + /// Single enum variants, structs/tuples, unions, and all non-ADTs. - Single { index: VariantIdx }, + Single { + /// Always `0` for types that cannot have multiple variants. + index: VariantIdx, + }, /// Enum-likes with more than one variant: each variant comes with /// a *discriminant* (usually the same as the variant index but the user can @@ -1485,7 +1573,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> { tag: Scalar, tag_encoding: TagEncoding<VariantIdx>, tag_field: usize, - variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>, + variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>, }, } @@ -1502,14 +1590,22 @@ pub enum TagEncoding<VariantIdx: Idx> { /// The variant `untagged_variant` contains a niche at an arbitrary /// offset (field `tag_field` of the enum), which for a variant with /// discriminant `d` is set to - /// `(d - niche_variants.start).wrapping_add(niche_start)`. + /// `(d - niche_variants.start).wrapping_add(niche_start)` + /// (this is wrapping arithmetic using the type of the niche field). /// /// For example, `Option<(usize, &T)>` is represented such that /// `None` has a null pointer for the second tuple field, and /// `Some` is the identity function (with a non-null reference). + /// + /// Other variants that are not `untagged_variant` and that are outside the `niche_variants` + /// range cannot be represented; they must be uninhabited. Niche { untagged_variant: VariantIdx, + /// This range *may* contain `untagged_variant`; that is then just a "dead value" and + /// not used to encode anything. niche_variants: RangeInclusive<VariantIdx>, + /// This is inbounds of the type of the niche field + /// (not sign-extended, i.e., all bits beyond the niche field size are 0). niche_start: u128, }, } @@ -1603,7 +1699,7 @@ impl Niche { // NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage. #[derive(PartialEq, Eq, Hash, Clone)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] -pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> { +pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> { /// Says where the fields are located within the layout. pub fields: FieldsShape<FieldIdx>, @@ -1616,18 +1712,23 @@ pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> { /// must be taken into account. pub variants: Variants<FieldIdx, VariantIdx>, - /// The `abi` defines how this data is passed between functions, and it defines - /// value restrictions via `valid_range`. + /// The `backend_repr` defines how this data will be represented to the codegen backend, + /// and encodes value restrictions via `valid_range`. /// /// Note that this is entirely orthogonal to the recursive structure defined by /// `variants` and `fields`; for example, `ManuallyDrop<Result<isize, isize>>` has - /// `Abi::ScalarPair`! So, even with non-`Aggregate` `abi`, `fields` and `variants` + /// `IrForm::ScalarPair`! So, even with non-`Memory` `backend_repr`, `fields` and `variants` /// have to be taken into account to find all fields of this layout. - pub abi: Abi, + pub backend_repr: BackendRepr, /// The leaf scalar with the largest number of invalid values /// (i.e. outside of its `valid_range`), if it exists. pub largest_niche: Option<Niche>, + /// Is this type known to be uninhabted? + /// + /// This is separate from BackendRepr because uninhabited return types can affect ABI, + /// especially in the case of by-pointer struct returns, which allocate stack even when unused. + pub uninhabited: bool, pub align: AbiAndPrefAlign, pub size: Size, @@ -1641,27 +1742,36 @@ pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> { /// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment /// in some cases. pub unadjusted_abi_align: Align, + + /// The randomization seed based on this type's own repr and its fields. + /// + /// Since randomization is toggled on a per-crate basis even crates that do not have randomization + /// enabled should still calculate a seed so that downstream uses can use it to distinguish different + /// types. + /// + /// For every T and U for which we do not guarantee that a repr(Rust) `Foo<T>` can be coerced or + /// transmuted to `Foo<U>` we aim to create probalistically distinct seeds so that Foo can choose + /// to reorder its fields based on that information. The current implementation is a conservative + /// approximation of this goal. + pub randomization_seed: Hash64, } -impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { - pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self { - let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); - let size = scalar.size(cx); - let align = scalar.align(cx); - LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Primitive, - abi: Abi::Scalar(scalar), - largest_niche, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, +impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { + /// Returns `true` if this is an aggregate type (including a ScalarPair!) + pub fn is_aggregate(&self) -> bool { + match self.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false, + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } + + /// Returns `true` if this is an uninhabited type + pub fn is_uninhabited(&self) -> bool { + self.uninhabited + } } -impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutS<FieldIdx, VariantIdx> +impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx> where FieldsShape<FieldIdx>: fmt::Debug, Variants<FieldIdx, VariantIdx>: fmt::Debug, @@ -1670,25 +1780,29 @@ where // This is how `Layout` used to print before it become // `Interned<LayoutS>`. We print it like this to avoid having to update // expected output in a lot of tests. - let LayoutS { + let LayoutData { size, align, - abi, + backend_repr, fields, largest_niche, + uninhabited, variants, max_repr_align, unadjusted_abi_align, + randomization_seed, } = self; f.debug_struct("Layout") .field("size", size) .field("align", align) - .field("abi", abi) + .field("backend_repr", backend_repr) .field("fields", fields) .field("largest_niche", largest_niche) + .field("uninhabited", uninhabited) .field("variants", variants) .field("max_repr_align", max_repr_align) .field("unadjusted_abi_align", unadjusted_abi_align) + .field("randomization_seed", randomization_seed) .finish() } } @@ -1704,27 +1818,35 @@ pub enum PointerKind { Box { unpin: bool, global: bool }, } -/// Note that this information is advisory only, and backends are free to ignore it. -/// It can only be used to encode potential optimizations, but no critical information. +/// Encodes extra information we have about a pointer. +/// Note that this information is advisory only, and backends are free to ignore it: +/// if the information is wrong, that can cause UB, but if the information is absent, +/// that must always be okay. #[derive(Copy, Clone, Debug)] pub struct PointeeInfo { - pub size: Size, - pub align: Align, /// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to /// be reliable. pub safe: Option<PointerKind>, + /// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes. + /// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration + /// of this function call", i.e. it is UB for the memory that this pointer points to be freed + /// while this function is still running. + /// The size can be zero if the pointer is not dereferenceable. + pub size: Size, + /// If `safe` is `Some`, then the pointer is aligned as indicated. + pub align: Align, } -impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { +impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { - self.abi.is_unsized() + self.backend_repr.is_unsized() } #[inline] pub fn is_sized(&self) -> bool { - self.abi.is_sized() + self.backend_repr.is_sized() } /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). @@ -1737,10 +1859,11 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { /// Note that this does *not* imply that the type is irrelevant for layout! It can still have /// non-trivial alignment constraints. You probably want to use `is_1zst` instead. pub fn is_zst(&self) -> bool { - match self.abi { - Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, - Abi::Uninhabited => self.size.bytes() == 0, - Abi::Aggregate { sized } => sized && self.size.bytes() == 0, + match self.backend_repr { + BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) + | BackendRepr::SimdVector { .. } => false, + BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } } @@ -1755,8 +1878,8 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> { // 2nd point is quite hard to check though. self.size == other.size && self.is_sized() == other.is_sized() - && self.abi.eq_up_to_validity(&other.abi) - && self.abi.is_bool() == other.abi.is_bool() + && self.backend_repr.eq_up_to_validity(&other.backend_repr) + && self.backend_repr.is_bool() == other.backend_repr.is_bool() && self.align.abi == other.align.abi && self.max_repr_align == other.max_repr_align && self.unadjusted_abi_align == other.unadjusted_abi_align diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml index 382ab2b077547..bbcd8ea6d389d 100644 --- a/compiler/rustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_arena" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index cecf223b96193..6aaac072e4b28 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -23,8 +23,6 @@ #![feature(maybe_uninit_slice)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![feature(strict_provenance)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::alloc::Layout; @@ -79,7 +77,7 @@ impl<T> ArenaChunk<T> { // been initialized. unsafe { let slice = self.storage.as_mut(); - ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len])); + slice[..len].assume_init_drop(); } } } @@ -94,7 +92,7 @@ impl<T> ArenaChunk<T> { #[inline] fn end(&mut self) -> *mut T { unsafe { - if mem::size_of::<T>() == 0 { + if size_of::<T>() == 0 { // A pointer as large as possible for zero-sized elements. ptr::without_provenance_mut(!0) } else { @@ -152,7 +150,7 @@ impl<T> TypedArena<T> { } unsafe { - if mem::size_of::<T>() == 0 { + if size_of::<T>() == 0 { self.ptr.set(self.ptr.get().wrapping_byte_add(1)); let ptr = ptr::NonNull::<T>::dangling().as_ptr(); // Don't drop the object. This `write` is equivalent to `forget`. @@ -174,13 +172,13 @@ impl<T> TypedArena<T> { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). let available_bytes = self.end.get().addr() - self.ptr.get().addr(); - let additional_bytes = additional.checked_mul(mem::size_of::<T>()).unwrap(); + let additional_bytes = additional.checked_mul(size_of::<T>()).unwrap(); available_bytes >= additional_bytes } #[inline] fn alloc_raw_slice(&self, len: usize) -> *mut T { - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); assert!(len != 0); // Ensure the current chunk can fit `len` objects. @@ -214,7 +212,7 @@ impl<T> TypedArena<T> { // So we collect all the elements beforehand, which takes care of reentrancy and panic // safety. This function is much less hot than `DroplessArena::alloc_from_iter`, so it // doesn't need to be hyper-optimized. - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); if vec.is_empty() { @@ -237,7 +235,7 @@ impl<T> TypedArena<T> { unsafe { // We need the element size to convert chunk sizes (ranging from // PAGE to HUGE_PAGE bytes) to element counts. - let elem_size = cmp::max(1, mem::size_of::<T>()); + let elem_size = cmp::max(1, size_of::<T>()); let mut chunks = self.chunks.borrow_mut(); let mut new_cap; if let Some(last_chunk) = chunks.last_mut() { @@ -247,7 +245,7 @@ impl<T> TypedArena<T> { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). let used_bytes = self.ptr.get().addr() - last_chunk.start().addr(); - last_chunk.entries = used_bytes / mem::size_of::<T>(); + last_chunk.entries = used_bytes / size_of::<T>(); } // If the previous chunk's len is less than HUGE_PAGE @@ -277,7 +275,7 @@ impl<T> TypedArena<T> { let end = self.ptr.get().addr(); // We then calculate the number of elements to be dropped in the last chunk, // which is the filled area's length. - let diff = if mem::size_of::<T>() == 0 { + let diff = if size_of::<T>() == 0 { // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get // the number of zero-sized values in the last and only chunk, just out of caution. // Recall that `end` was incremented for each allocated value. @@ -285,7 +283,7 @@ impl<T> TypedArena<T> { } else { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). - (end - start) / mem::size_of::<T>() + (end - start) / size_of::<T>() }; // Pass that to the `destroy` method. unsafe { @@ -330,7 +328,7 @@ fn align_up(val: usize, align: usize) -> usize { // Pointer alignment is common in compiler types, so keep `DroplessArena` aligned to them // to optimize away alignment code. -const DROPLESS_ALIGNMENT: usize = mem::align_of::<usize>(); +const DROPLESS_ALIGNMENT: usize = align_of::<usize>(); /// An arena that can hold objects of multiple different types that impl `Copy` /// and/or satisfy `!mem::needs_drop`. @@ -448,7 +446,7 @@ impl DroplessArena { #[inline] pub fn alloc<T>(&self, object: T) -> &mut T { assert!(!mem::needs_drop::<T>()); - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); let mem = self.alloc_raw(Layout::new::<T>()) as *mut T; @@ -472,7 +470,7 @@ impl DroplessArena { T: Copy, { assert!(!mem::needs_drop::<T>()); - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); assert!(!slice.is_empty()); let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T; @@ -547,7 +545,7 @@ impl DroplessArena { // Warning: this function is reentrant: `iter` could hold a reference to `&self` and // allocate additional elements while we're iterating. let iter = iter.into_iter(); - assert!(mem::size_of::<T>() != 0); + assert!(size_of::<T>() != 0); assert!(!mem::needs_drop::<T>()); let size_hint = iter.size_hint(); diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 34c612dac692b..b2d3b90fc4494 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "rustc_ast" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" memchr = "2.7.4" +rustc-literal-escaper = "0.0.2" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } -rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 02cb6f188a718..1532ca77f713e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -19,7 +19,8 @@ //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. use std::borrow::Cow; -use std::{cmp, fmt, mem}; +use std::sync::Arc; +use std::{cmp, fmt}; pub use GenericArgs::*; pub use UnsafeSource::*; @@ -27,19 +28,18 @@ pub use rustc_ast_ir::{Movability, Mutability, Pinnedness}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::tagged_ptr::Tag; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; pub use rustc_span::AttrId; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; pub use crate::format::*; use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter}; use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream}; -pub use crate::util::parser::ExprPrecedence; +use crate::util::parser::{ExprPrecedence, Fixity}; /// A "Label" is an identifier of some point in sources, /// e.g. in the following code: @@ -100,7 +100,7 @@ pub struct Path { impl PartialEq<Symbol> for Path { #[inline] fn eq(&self, symbol: &Symbol) -> bool { - self.segments.len() == 1 && { self.segments[0].ident.name == *symbol } + matches!(&self.segments[..], [segment] if segment.ident.name == *symbol) } } @@ -120,14 +120,34 @@ impl Path { Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None } } + pub fn is_ident(&self, name: Symbol) -> bool { + if let [segment] = self.segments.as_ref() + && segment.args.is_none() + && segment.ident.name == name + { + true + } else { + false + } + } + pub fn is_global(&self) -> bool { - !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot + self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot) } - /// If this path is a single identifier with no arguments, does not ensure - /// that the path resolves to a const param, the caller should check this. - pub fn is_potential_trivial_const_arg(&self) -> bool { - self.segments.len() == 1 && self.segments[0].args.is_none() + /// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_ + /// be represented without an anon const in the HIR. + /// + /// If `allow_mgca_arg` is true (as should be the case in most situations when + /// `#![feature(min_generic_const_args)]` is enabled), then this always returns true + /// because all paths are valid. + /// + /// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args + /// (i.e., it is _potentially_ a const parameter). + #[tracing::instrument(level = "debug", ret)] + pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { + allow_mgca_arg + || self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none()) } } @@ -242,15 +262,15 @@ impl AngleBracketedArg { } } -impl Into<P<GenericArgs>> for AngleBracketedArgs { - fn into(self) -> P<GenericArgs> { - P(GenericArgs::AngleBracketed(self)) +impl From<AngleBracketedArgs> for P<GenericArgs> { + fn from(val: AngleBracketedArgs) -> Self { + P(GenericArgs::AngleBracketed(val)) } } -impl Into<P<GenericArgs>> for ParenthesizedArgs { - fn into(self) -> P<GenericArgs> { - P(GenericArgs::Parenthesized(self)) +impl From<ParenthesizedArgs> for P<GenericArgs> { + fn from(val: ParenthesizedArgs) -> Self { + P(GenericArgs::Parenthesized(val)) } } @@ -288,6 +308,7 @@ impl ParenthesizedArgs { } } +use crate::AstDeref; pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId}; /// Modifiers on a trait bound like `~const`, `?` and `!`. @@ -388,22 +409,15 @@ impl GenericParam { /// Represents lifetime, type and const parameters attached to a declaration of /// a function, enum, trait, etc. -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug, Default)] pub struct Generics { pub params: ThinVec<GenericParam>, pub where_clause: WhereClause, pub span: Span, } -impl Default for Generics { - /// Creates an instance of `Generics`. - fn default() -> Generics { - Generics { params: ThinVec::new(), where_clause: Default::default(), span: DUMMY_SP } - } -} - /// A where-clause in a definition. -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug, Default)] pub struct WhereClause { /// `true` if we ate a `where` token. /// @@ -414,15 +428,25 @@ pub struct WhereClause { pub span: Span, } -impl Default for WhereClause { - fn default() -> WhereClause { - WhereClause { has_where_token: false, predicates: ThinVec::new(), span: DUMMY_SP } +impl WhereClause { + pub fn is_empty(&self) -> bool { + !self.has_where_token && self.predicates.is_empty() } } /// A single predicate in a where-clause. #[derive(Clone, Encodable, Decodable, Debug)] -pub enum WherePredicate { +pub struct WherePredicate { + pub attrs: AttrVec, + pub kind: WherePredicateKind, + pub id: NodeId, + pub span: Span, + pub is_placeholder: bool, +} + +/// Predicate kind in where-clause. +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum WherePredicateKind { /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). BoundPredicate(WhereBoundPredicate), /// A lifetime predicate (e.g., `'a: 'b + 'c`). @@ -431,22 +455,11 @@ pub enum WherePredicate { EqPredicate(WhereEqPredicate), } -impl WherePredicate { - pub fn span(&self) -> Span { - match self { - WherePredicate::BoundPredicate(p) => p.span, - WherePredicate::RegionPredicate(p) => p.span, - WherePredicate::EqPredicate(p) => p.span, - } - } -} - /// A type bound. /// /// E.g., `for<'c> Foo: Send + Clone + 'c`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct WhereBoundPredicate { - pub span: Span, /// Any generics from a `for` binding. pub bound_generic_params: ThinVec<GenericParam>, /// The type being bounded. @@ -460,7 +473,6 @@ pub struct WhereBoundPredicate { /// E.g., `'a: 'b + 'c`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct WhereRegionPredicate { - pub span: Span, pub lifetime: Lifetime, pub bounds: GenericBounds, } @@ -470,7 +482,6 @@ pub struct WhereRegionPredicate { /// E.g., `T = int`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct WhereEqPredicate { - pub span: Span, pub lhs_ty: P<Ty>, pub rhs_ty: P<Ty>, } @@ -545,14 +556,6 @@ pub struct Block { pub rules: BlockCheckMode, pub span: Span, pub tokens: Option<LazyAttrTokenStream>, - /// The following *isn't* a parse error, but will cause multiple errors in following stages. - /// ```compile_fail - /// let x = { - /// foo: var - /// }; - /// ``` - /// #34255 - pub could_be_bare_literal: bool, } /// A match pattern. @@ -571,6 +574,7 @@ impl Pat { /// This is intended for use by diagnostics. pub fn to_ty(&self) -> Option<P<Ty>> { let kind = match &self.kind { + PatKind::Missing => unreachable!(), // In a type expression `_` is an inference variable. PatKind::Wild => TyKind::Infer, // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`. @@ -626,15 +630,18 @@ impl Pat { | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)), // Trivial wrappers over inner patterns. - PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => { - s.walk(it) - } + PatKind::Box(s) + | PatKind::Deref(s) + | PatKind::Ref(s, _) + | PatKind::Paren(s) + | PatKind::Guard(s, _) => s.walk(it), // These patterns do not contain subpatterns, skip. - PatKind::Wild + PatKind::Missing + | PatKind::Wild | PatKind::Rest | PatKind::Never - | PatKind::Lit(_) + | PatKind::Expr(_) | PatKind::Range(..) | PatKind::Ident(..) | PatKind::Path(..) @@ -682,6 +689,7 @@ impl Pat { /// Return a name suitable for diagnostics. pub fn descr(&self) -> Option<String> { match &self.kind { + PatKind::Missing => unreachable!(), PatKind::Wild => Some("_".to_string()), PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")), PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())), @@ -775,6 +783,9 @@ pub enum RangeSyntax { // Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum PatKind { + /// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`. + Missing, + /// Represents a wildcard pattern (`_`). Wild, @@ -812,8 +823,8 @@ pub enum PatKind { /// A reference pattern (e.g., `&mut (a, b)`). Ref(P<Pat>, Mutability), - /// A literal. - Lit(P<Expr>), + /// A literal, const block or path. + Expr(P<Expr>), /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>), @@ -838,6 +849,9 @@ pub enum PatKind { // A never pattern `!`. Never, + /// A guard pattern (e.g., `x if guard(x)`). + Guard(P<Pat>, P<Expr>), + /// Parentheses in patterns used for grouping (i.e., `(PAT)`). Paren(P<Pat>), @@ -853,6 +867,8 @@ pub enum PatKind { pub enum PatFieldsRest { /// `module::StructName { field, ..}` Rest, + /// `module::StructName { field, syntax error }` + Recovered(ErrorGuaranteed), /// `module::StructName { field }` None, } @@ -941,8 +957,37 @@ impl BinOpKind { matches!(self, BinOpKind::And | BinOpKind::Or) } + pub fn precedence(&self) -> ExprPrecedence { + use BinOpKind::*; + match *self { + Mul | Div | Rem => ExprPrecedence::Product, + Add | Sub => ExprPrecedence::Sum, + Shl | Shr => ExprPrecedence::Shift, + BitAnd => ExprPrecedence::BitAnd, + BitXor => ExprPrecedence::BitXor, + BitOr => ExprPrecedence::BitOr, + Lt | Gt | Le | Ge | Eq | Ne => ExprPrecedence::Compare, + And => ExprPrecedence::LAnd, + Or => ExprPrecedence::LOr, + } + } + + pub fn fixity(&self) -> Fixity { + use BinOpKind::*; + match self { + Eq | Ne | Lt | Le | Gt | Ge => Fixity::None, + Add | Sub | Mul | Div | Rem | And | Or | BitXor | BitAnd | BitOr | Shl | Shr => { + Fixity::Left + } + } + } + pub fn is_comparison(self) -> bool { - crate::util::parser::AssocOp::from_ast_binop(self).is_comparison() + use BinOpKind::*; + match self { + Eq | Ne | Lt | Le | Gt | Ge => true, + Add | Sub | Mul | Div | Rem | And | Or | BitXor | BitAnd | BitOr | Shl | Shr => false, + } } /// Returns `true` if the binary operator takes its arguments by value. @@ -953,6 +998,75 @@ impl BinOpKind { pub type BinOp = Spanned<BinOpKind>; +// Sometimes `BinOpKind` and `AssignOpKind` need the same treatment. The +// operations covered by `AssignOpKind` are a subset of those covered by +// `BinOpKind`, so it makes sense to convert `AssignOpKind` to `BinOpKind`. +impl From<AssignOpKind> for BinOpKind { + fn from(op: AssignOpKind) -> BinOpKind { + match op { + AssignOpKind::AddAssign => BinOpKind::Add, + AssignOpKind::SubAssign => BinOpKind::Sub, + AssignOpKind::MulAssign => BinOpKind::Mul, + AssignOpKind::DivAssign => BinOpKind::Div, + AssignOpKind::RemAssign => BinOpKind::Rem, + AssignOpKind::BitXorAssign => BinOpKind::BitXor, + AssignOpKind::BitAndAssign => BinOpKind::BitAnd, + AssignOpKind::BitOrAssign => BinOpKind::BitOr, + AssignOpKind::ShlAssign => BinOpKind::Shl, + AssignOpKind::ShrAssign => BinOpKind::Shr, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] +pub enum AssignOpKind { + /// The `+=` operator (addition) + AddAssign, + /// The `-=` operator (subtraction) + SubAssign, + /// The `*=` operator (multiplication) + MulAssign, + /// The `/=` operator (division) + DivAssign, + /// The `%=` operator (modulus) + RemAssign, + /// The `^=` operator (bitwise xor) + BitXorAssign, + /// The `&=` operator (bitwise and) + BitAndAssign, + /// The `|=` operator (bitwise or) + BitOrAssign, + /// The `<<=` operator (shift left) + ShlAssign, + /// The `>>=` operator (shift right) + ShrAssign, +} + +impl AssignOpKind { + pub fn as_str(&self) -> &'static str { + use AssignOpKind::*; + match self { + AddAssign => "+=", + SubAssign => "-=", + MulAssign => "*=", + DivAssign => "/=", + RemAssign => "%=", + BitXorAssign => "^=", + BitAndAssign => "&=", + BitOrAssign => "|=", + ShlAssign => "<<=", + ShrAssign => ">>=", + } + } + + /// AssignOps are always by value. + pub fn is_by_value(self) -> bool { + true + } +} + +pub type AssignOp = Spanned<AssignOpKind>; + /// Unary operator. /// /// Note that `&data` is not an operator, it's an `AddrOf` expression. @@ -1072,6 +1186,7 @@ pub enum MacStmtStyle { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Local { pub id: NodeId, + pub super_: Option<Span>, pub pat: P<Pat>, pub ty: Option<P<Ty>>, pub kind: LocalKind, @@ -1181,33 +1296,70 @@ pub struct Expr { } impl Expr { - /// Is this expr either `N`, or `{ N }`. + /// Check if this expression is potentially a trivial const arg, i.e., one that can _potentially_ + /// be represented without an anon const in the HIR. /// - /// If this is not the case, name resolution does not resolve `N` when using - /// `min_const_generics` as more complex expressions are not supported. + /// This will unwrap at most one block level (curly braces). After that, if the expression + /// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`]. + /// See there for more info about `allow_mgca_arg`. /// - /// Does not ensure that the path resolves to a const param, the caller should check this. - pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool { - let this = if strip_identity_block { self.maybe_unwrap_block().1 } else { self }; - - if let ExprKind::Path(None, path) = &this.kind - && path.is_potential_trivial_const_arg() - { - true + /// The only additional thing to note is that when `allow_mgca_arg` is false, this function + /// will only allow paths with no qself, before dispatching to the `Path` function of + /// the same name. + /// + /// Does not ensure that the path resolves to a const param/item, the caller should check this. + /// This also does not consider macros, so it's only correct after macro-expansion. + pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { + let this = self.maybe_unwrap_block(); + if allow_mgca_arg { + matches!(this.kind, ExprKind::Path(..)) } else { - false + if let ExprKind::Path(None, path) = &this.kind + && path.is_potential_trivial_const_arg(allow_mgca_arg) + { + true + } else { + false + } } } /// Returns an expression with (when possible) *one* outter brace removed - pub fn maybe_unwrap_block(&self) -> (bool, &Expr) { + pub fn maybe_unwrap_block(&self) -> &Expr { if let ExprKind::Block(block, None) = &self.kind && let [stmt] = block.stmts.as_slice() && let StmtKind::Expr(expr) = &stmt.kind { - (true, expr) + expr } else { - (false, self) + self + } + } + + /// Determines whether this expression is a macro call optionally wrapped in braces . If + /// `already_stripped_block` is set then we do not attempt to peel off a layer of braces. + /// + /// Returns the [`NodeId`] of the macro call and whether a layer of braces has been peeled + /// either before, or part of, this function. + pub fn optionally_braced_mac_call( + &self, + already_stripped_block: bool, + ) -> Option<(bool, NodeId)> { + match &self.kind { + ExprKind::Block(block, None) + if let [stmt] = &*block.stmts + && !already_stripped_block => + { + match &stmt.kind { + StmtKind::MacCall(_) => Some((true, stmt.id)), + StmtKind::Expr(expr) if let ExprKind::MacCall(_) = &expr.kind => { + Some((true, expr.id)) + } + _ => None, + } + } + ExprKind::MacCall(_) => Some((already_stripped_block, self.id)), + _ => None, } } @@ -1287,52 +1439,77 @@ impl Expr { } pub fn precedence(&self) -> ExprPrecedence { - match self.kind { - ExprKind::Array(_) => ExprPrecedence::Array, - ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock, - ExprKind::Call(..) => ExprPrecedence::Call, - ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, - ExprKind::Tup(_) => ExprPrecedence::Tup, - ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node), - ExprKind::Unary(..) => ExprPrecedence::Unary, - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit, - ExprKind::Cast(..) => ExprPrecedence::Cast, - ExprKind::Let(..) => ExprPrecedence::Let, - ExprKind::If(..) => ExprPrecedence::If, - ExprKind::While(..) => ExprPrecedence::While, - ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop, - ExprKind::Loop(..) => ExprPrecedence::Loop, - ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match, - ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch, - ExprKind::Closure(..) => ExprPrecedence::Closure, - ExprKind::Block(..) => ExprPrecedence::Block, - ExprKind::TryBlock(..) => ExprPrecedence::TryBlock, - ExprKind::Gen(..) => ExprPrecedence::Gen, - ExprKind::Await(..) => ExprPrecedence::Await, - ExprKind::Assign(..) => ExprPrecedence::Assign, - ExprKind::AssignOp(..) => ExprPrecedence::AssignOp, - ExprKind::Field(..) => ExprPrecedence::Field, - ExprKind::Index(..) => ExprPrecedence::Index, + match &self.kind { + ExprKind::Closure(closure) => { + match closure.fn_decl.output { + FnRetTy::Default(_) => ExprPrecedence::Jump, + FnRetTy::Ty(_) => ExprPrecedence::Unambiguous, + } + } + + ExprKind::Break(..) + | ExprKind::Ret(..) + | ExprKind::Yield(..) + | ExprKind::Yeet(..) + | ExprKind::Become(..) => ExprPrecedence::Jump, + + // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to + // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence + // ensures that `pprust` will add parentheses in the right places to get the desired + // parse. ExprKind::Range(..) => ExprPrecedence::Range, - ExprKind::Underscore => ExprPrecedence::Path, - ExprKind::Path(..) => ExprPrecedence::Path, - ExprKind::AddrOf(..) => ExprPrecedence::AddrOf, - ExprKind::Break(..) => ExprPrecedence::Break, - ExprKind::Continue(..) => ExprPrecedence::Continue, - ExprKind::Ret(..) => ExprPrecedence::Ret, - ExprKind::Struct(..) => ExprPrecedence::Struct, - ExprKind::Repeat(..) => ExprPrecedence::Repeat, - ExprKind::Paren(..) => ExprPrecedence::Paren, - ExprKind::Try(..) => ExprPrecedence::Try, - ExprKind::Yield(..) => ExprPrecedence::Yield, - ExprKind::Yeet(..) => ExprPrecedence::Yeet, - ExprKind::Become(..) => ExprPrecedence::Become, - ExprKind::InlineAsm(..) - | ExprKind::Type(..) - | ExprKind::OffsetOf(..) + + // Binop-like expr kinds, handled by `AssocOp`. + ExprKind::Binary(op, ..) => op.node.precedence(), + ExprKind::Cast(..) => ExprPrecedence::Cast, + + ExprKind::Assign(..) | + ExprKind::AssignOp(..) => ExprPrecedence::Assign, + + // Unary, prefix + ExprKind::AddrOf(..) + // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`. + // However, this is not exactly right. When `let _ = a` is the LHS of a binop we + // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b` + // but we need to print `(let _ = a) < b` as-is with parens. + | ExprKind::Let(..) + | ExprKind::Unary(..) => ExprPrecedence::Prefix, + + // Never need parens + ExprKind::Array(_) + | ExprKind::Await(..) + | ExprKind::Use(..) + | ExprKind::Block(..) + | ExprKind::Call(..) + | ExprKind::ConstBlock(_) + | ExprKind::Continue(..) + | ExprKind::Field(..) + | ExprKind::ForLoop { .. } | ExprKind::FormatArgs(..) - | ExprKind::MacCall(..) => ExprPrecedence::Mac, - ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err, + | ExprKind::Gen(..) + | ExprKind::If(..) + | ExprKind::IncludedBytes(..) + | ExprKind::Index(..) + | ExprKind::InlineAsm(..) + | ExprKind::Lit(_) + | ExprKind::Loop(..) + | ExprKind::MacCall(..) + | ExprKind::Match(..) + | ExprKind::MethodCall(..) + | ExprKind::OffsetOf(..) + | ExprKind::Paren(..) + | ExprKind::Path(..) + | ExprKind::Repeat(..) + | ExprKind::Struct(..) + | ExprKind::Try(..) + | ExprKind::TryBlock(..) + | ExprKind::Tup(_) + | ExprKind::Type(..) + | ExprKind::Underscore + | ExprKind::UnsafeBinderCast(..) + | ExprKind::While(..) + | ExprKind::Err(_) + | ExprKind::Dummy => ExprPrecedence::Unambiguous, } } @@ -1376,6 +1553,15 @@ pub enum RangeLimits { Closed, } +impl RangeLimits { + pub fn as_str(&self) -> &'static str { + match self { + RangeLimits::HalfOpen => "..", + RangeLimits::Closed => "..=", + } + } +} + /// A method call (e.g. `x.foo::<Bar, Baz>(a, b, c)`). #[derive(Clone, Encodable, Decodable, Debug)] pub struct MethodCall { @@ -1457,7 +1643,13 @@ pub enum ExprKind { /// `'label: for await? pat in iter { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind }, + ForLoop { + pat: P<Pat>, + iter: P<Expr>, + body: P<Block>, + label: Option<Label>, + kind: ForLoopKind, + }, /// Conditionless loop (can be exited with `break`, `continue`, or `return`). /// /// `'label: loop { block }` @@ -1476,6 +1668,8 @@ pub enum ExprKind { Gen(CaptureBy, P<Block>, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. Await(P<Expr>, Span), + /// A use expression (`x.use`). Span is of use keyword. + Use(P<Expr>, Span), /// A try block (`try { ... }`). TryBlock(P<Block>), @@ -1486,7 +1680,7 @@ pub enum ExprKind { /// An assignment with an operator. /// /// E.g., `a += 1`. - AssignOp(BinOp, P<Expr>, P<Expr>), + AssignOp(AssignOp, P<Expr>, P<Expr>), /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field. Field(P<Expr>, Ident), /// An indexing operation (e.g., `foo[2]`). @@ -1542,7 +1736,7 @@ pub enum ExprKind { Try(P<Expr>), /// A `yield`, with an optional value to be yielded. - Yield(Option<P<Expr>>), + Yield(YieldKind), /// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever), /// with an optional value to be returned. @@ -1557,11 +1751,13 @@ pub enum ExprKind { /// Added for optimization purposes to avoid the need to escape /// large binary blobs - should always behave like [`ExprKind::Lit`] /// with a `ByteStr` literal. - IncludedBytes(Lrc<[u8]>), + IncludedBytes(Arc<[u8]>), /// A `format_args!()` expression. FormatArgs(P<FormatArgs>), + UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>), + /// Placeholder for an expression that wasn't syntactically well formed in some way. Err(ErrorGuaranteed), @@ -1600,6 +1796,16 @@ impl GenBlockKind { } } +/// Whether we're unwrapping or wrapping an unsafe binder +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Encodable, Decodable, HashStable_Generic)] +pub enum UnsafeBinderCastKind { + // e.g. `&i32` -> `unsafe<'a> &'a i32` + Wrap, + // e.g. `unsafe<'a> &'a i32` -> `&i32` + Unwrap, +} + /// The explicit `Self` type in a "qualified path". The actual /// path, including the trait and the associated item, is stored /// separately. `position` represents the index of the associated @@ -1633,8 +1839,17 @@ pub enum CaptureBy { /// The span of the `move` keyword. move_kw: Span, }, - /// `move` keyword was not specified. + /// `move` or `use` keywords were not specified. Ref, + /// `use |x| y + x`. + /// + /// Note that if you have a regular closure like `|| x.use`, this will *not* result + /// in a `Use` capture. Instead, the `ExprUseVisitor` will look at the type + /// of `x` and treat `x.use` as either a copy/clone/move as appropriate. + Use { + /// The span of the `use` keyword. + use_kw: Span, + }, } /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`. @@ -1684,21 +1899,11 @@ pub enum AttrArgs { /// Delimited arguments: `#[attr()/[]/{}]`. Delimited(DelimArgs), /// Arguments of a key-value attribute: `#[attr = "value"]`. - Eq( + Eq { /// Span of the `=` token. - Span, - /// The "value". - AttrArgsEq, - ), -} - -// The RHS of an `AttrArgs::Eq` starts out as an expression. Once macro -// expansion is completed, all cases end up either as a meta item literal, -// which is the form used after lowering to HIR, or as an error. -#[derive(Clone, Encodable, Decodable, Debug)] -pub enum AttrArgsEq { - Ast(P<Expr>), - Hir(MetaItemLit), + eq_span: Span, + expr: P<Expr>, + }, } impl AttrArgs { @@ -1706,10 +1911,7 @@ impl AttrArgs { match self { AttrArgs::Empty => None, AttrArgs::Delimited(args) => Some(args.dspan.entire()), - AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => Some(eq_span.to(expr.span)), - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => { - unreachable!("in literal form when getting span: {:?}", lit); - } + AttrArgs::Eq { eq_span, expr } => Some(eq_span.to(expr.span)), } } @@ -1719,30 +1921,7 @@ impl AttrArgs { match self { AttrArgs::Empty => TokenStream::default(), AttrArgs::Delimited(args) => args.tokens.clone(), - AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => TokenStream::from_ast(expr), - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => { - unreachable!("in literal form when getting inner tokens: {:?}", lit) - } - } - } -} - -impl<CTX> HashStable<CTX> for AttrArgs -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(ctx, hasher); - match self { - AttrArgs::Empty => {} - AttrArgs::Delimited(args) => args.hash_stable(ctx, hasher), - AttrArgs::Eq(_eq_span, AttrArgsEq::Ast(expr)) => { - unreachable!("hash_stable {:?}", expr); - } - AttrArgs::Eq(eq_span, AttrArgsEq::Hir(lit)) => { - eq_span.hash_stable(ctx, hasher); - lit.hash_stable(ctx, hasher); - } + AttrArgs::Eq { expr, .. } => TokenStream::from_ast(expr), } } } @@ -1803,6 +1982,44 @@ pub enum MatchKind { Postfix, } +/// The kind of yield expression +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum YieldKind { + /// yield expr { ... } + Prefix(Option<P<Expr>>), + /// expr.yield { ... } + Postfix(P<Expr>), +} + +impl YieldKind { + /// Returns the expression inside the yield expression, if any. + /// + /// For postfix yields, this is guaranteed to be `Some`. + pub const fn expr(&self) -> Option<&P<Expr>> { + match self { + YieldKind::Prefix(expr) => expr.as_ref(), + YieldKind::Postfix(expr) => Some(expr), + } + } + + /// Returns a mutable reference to the expression being yielded, if any. + pub const fn expr_mut(&mut self) -> Option<&mut P<Expr>> { + match self { + YieldKind::Prefix(expr) => expr.as_mut(), + YieldKind::Postfix(expr) => Some(expr), + } + } + + /// Returns true if both yields are prefix or both are postfix. + pub const fn same_kind(&self, other: &Self) -> bool { + match (self, other) { + (YieldKind::Prefix(_), YieldKind::Prefix(_)) => true, + (YieldKind::Postfix(_), YieldKind::Postfix(_)) => true, + _ => false, + } + } +} + /// A literal in a meta item. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MetaItemLit { @@ -1874,9 +2091,9 @@ pub enum LitKind { Str(Symbol, StrStyle), /// A byte string (`b"foo"`). Not stored as a symbol because it might be /// non-utf8, and symbols only allow utf8 strings. - ByteStr(Lrc<[u8]>, StrStyle), + ByteStr(Arc<[u8]>, StrStyle), /// A C String (`c"foo"`). Guaranteed to only have `\0` at the end. - CStr(Lrc<[u8]>, StrStyle), + CStr(Arc<[u8]>, StrStyle), /// A byte char (`b'f'`). Byte(u8), /// A character literal (`'a'`). @@ -2137,6 +2354,14 @@ impl Ty { } final_ty } + + pub fn is_maybe_parenthesised_infer(&self) -> bool { + match &self.kind { + TyKind::Infer => true, + TyKind::Paren(inner) => inner.ast_deref().is_maybe_parenthesised_infer(), + _ => false, + } + } } #[derive(Clone, Encodable, Decodable, Debug)] @@ -2150,6 +2375,12 @@ pub struct BareFnTy { pub decl_span: Span, } +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct UnsafeBinderTy { + pub generic_params: ThinVec<GenericParam>, + pub inner_ty: P<Ty>, +} + /// The various kinds of type recognized by the compiler. // // Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`. @@ -2169,6 +2400,8 @@ pub enum TyKind { PinnedRef(Option<Lifetime>, MutTy), /// A bare function (e.g., `fn(usize) -> bool`). BareFn(P<BareFnTy>), + /// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`). + UnsafeBinder(P<UnsafeBinderTy>), /// The never type (`!`). Never, /// A tuple (`(A, B, C, D,...)`). @@ -2203,7 +2436,7 @@ pub enum TyKind { CVarArgs, /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero<u32>`, /// just as part of the type system. - Pat(P<Ty>, P<Pat>), + Pat(P<Ty>, P<TyPat>), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. @@ -2231,12 +2464,55 @@ impl TyKind { } } +/// A pattern type pattern. +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct TyPat { + pub id: NodeId, + pub kind: TyPatKind, + pub span: Span, + pub tokens: Option<LazyAttrTokenStream>, +} + +/// All the different flavors of pattern that Rust recognizes. +// +// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`. +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum TyPatKind { + /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). + Range(Option<P<AnonConst>>, Option<P<AnonConst>>, Spanned<RangeEnd>), + + /// Placeholder for a pattern that wasn't syntactically well formed in some way. + Err(ErrorGuaranteed), +} + /// Syntax used to declare a trait object. #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[repr(u8)] pub enum TraitObjectSyntax { - Dyn, - DynStar, - None, + // SAFETY: When adding new variants make sure to update the `Tag` impl. + Dyn = 0, + DynStar = 1, + None = 2, +} + +/// SAFETY: `TraitObjectSyntax` only has 3 data-less variants which means +/// it can be represented with a `u2`. We use `repr(u8)` to guarantee the +/// discriminants of the variants are no greater than `3`. +unsafe impl Tag for TraitObjectSyntax { + const BITS: u32 = 2; + + fn into_usize(self) -> usize { + self as u8 as usize + } + + unsafe fn from_usize(tag: usize) -> Self { + match tag { + 0 => TraitObjectSyntax::Dyn, + 1 => TraitObjectSyntax::DynStar, + 2 => TraitObjectSyntax::None, + _ => unreachable!(), + } + } } #[derive(Clone, Encodable, Decodable, Debug)] @@ -2494,10 +2770,26 @@ pub enum SelfKind { Value(Mutability), /// `&'lt self`, `&'lt mut self` Region(Option<Lifetime>, Mutability), + /// `&'lt pin const self`, `&'lt pin mut self` + Pinned(Option<Lifetime>, Mutability), /// `self: TYPE`, `mut self: TYPE` Explicit(P<Ty>, Mutability), } +impl SelfKind { + pub fn to_ref_suggestion(&self) -> String { + match self { + SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(), + SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()), + SelfKind::Pinned(None, mutbl) => format!("&pin {}", mutbl.ptr_str()), + SelfKind::Pinned(Some(lt), mutbl) => format!("&{lt} pin {}", mutbl.ptr_str()), + SelfKind::Value(_) | SelfKind::Explicit(_, _) => { + unreachable!("if we had an explicit self, we wouldn't be here") + } + } + } +} + pub type ExplicitSelf = Spanned<SelfKind>; impl Param { @@ -2507,11 +2799,13 @@ impl Param { if ident.name == kw::SelfLower { return match self.ty.kind { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), - TyKind::Ref(lt, MutTy { ref ty, mutbl }) - | TyKind::PinnedRef(lt, MutTy { ref ty, mutbl }) + TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => { + Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) + } + TyKind::PinnedRef(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => { - Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) + Some(respan(self.pat.span, SelfKind::Pinned(lt, mutbl))) } _ => Some(respan( self.pat.span.to(self.ty.span), @@ -2553,6 +2847,15 @@ impl Param { tokens: None, }), ), + SelfKind::Pinned(lt, mutbl) => ( + mutbl, + P(Ty { + id: DUMMY_NODE_ID, + kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }), + span, + tokens: None, + }), + ), }; Param { attrs, @@ -2697,7 +3000,7 @@ impl fmt::Debug for ImplPolarity { } /// The polarity of a trait bound. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)] #[derive(HashStable_Generic)] pub enum BoundPolarity { /// `Type: Trait` @@ -2719,7 +3022,7 @@ impl BoundPolarity { } /// The constness of a trait bound. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)] #[derive(HashStable_Generic)] pub enum BoundConstness { /// `Type: Trait` @@ -2792,7 +3095,7 @@ pub enum ModKind { /// or with definition outlined to a separate file `mod foo;` and already loaded from it. /// The inner span is from the first token past `{` to the last token until `}`, /// or from the first to the last token in the loaded file. - Loaded(ThinVec<P<Item>>, Inline, ModSpans), + Loaded(ThinVec<P<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>), /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it. Unloaded, } @@ -2810,6 +3113,8 @@ pub struct ModSpans { /// E.g., `extern { .. }` or `extern "C" { .. }`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct ForeignMod { + /// Span of the `extern` keyword. + pub extern_span: Span, /// `unsafe` keyword accepted syntactically for macro DSLs, but not /// semantically by Rust. pub safety: Safety, @@ -2937,7 +3242,7 @@ impl NormalAttr { } } -#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct AttrItem { pub unsafety: Safety, pub path: Path, @@ -3028,9 +3333,11 @@ pub struct FieldDef { pub id: NodeId, pub span: Span, pub vis: Visibility, + pub safety: Safety, pub ident: Option<Ident>, pub ty: P<Ty>, + pub default: Option<AnonConst>, pub is_placeholder: bool, } @@ -3083,9 +3390,6 @@ pub struct Item<K = ItemKind> { pub id: NodeId, pub span: Span, pub vis: Visibility, - /// The name of the item. - /// It might be a dummy name in case of anonymous items. - pub ident: Ident, pub kind: K, @@ -3107,23 +3411,23 @@ impl Item { pub fn opt_generics(&self) -> Option<&Generics> { match &self.kind { - ItemKind::ExternCrate(_) + ItemKind::ExternCrate(..) | ItemKind::Use(_) - | ItemKind::Mod(_, _) + | ItemKind::Mod(..) | ItemKind::ForeignMod(_) | ItemKind::GlobalAsm(_) | ItemKind::MacCall(_) | ItemKind::Delegation(_) | ItemKind::DelegationMac(_) - | ItemKind::MacroDef(_) => None, + | ItemKind::MacroDef(..) => None, ItemKind::Static(_) => None, ItemKind::Const(i) => Some(&i.generics), ItemKind::Fn(i) => Some(&i.generics), ItemKind::TyAlias(i) => Some(&i.generics), - ItemKind::TraitAlias(generics, _) - | ItemKind::Enum(_, generics) - | ItemKind::Struct(_, generics) - | ItemKind::Union(_, generics) => Some(&generics), + ItemKind::TraitAlias(_, generics, _) + | ItemKind::Enum(_, _, generics) + | ItemKind::Struct(_, _, generics) + | ItemKind::Union(_, _, generics) => Some(&generics), ItemKind::Trait(i) => Some(&i.generics), ItemKind::Impl(i) => Some(&i.generics), } @@ -3141,7 +3445,7 @@ pub enum Extern { /// /// E.g. `extern fn foo() {}`. /// - /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`). + /// This is just `extern "C"` (see `rustc_abi::ExternAbi::FALLBACK`). Implicit(Span), /// An explicit extern keyword was used with an explicit ABI. /// @@ -3200,6 +3504,7 @@ impl Default for FnHeader { pub struct Trait { pub safety: Safety, pub is_auto: IsAuto, + pub ident: Ident, pub generics: Generics, pub bounds: GenericBounds, pub items: ThinVec<P<AssocItem>>, @@ -3245,6 +3550,7 @@ pub struct TyAliasWhereClauses { #[derive(Clone, Encodable, Decodable, Debug)] pub struct TyAlias { pub defaultness: Defaultness, + pub ident: Ident, pub generics: Generics, pub where_clauses: TyAliasWhereClauses, pub bounds: GenericBounds, @@ -3264,11 +3570,20 @@ pub struct Impl { pub items: ThinVec<P<AssocItem>>, } +#[derive(Clone, Encodable, Decodable, Debug, Default)] +pub struct FnContract { + pub requires: Option<P<Expr>>, + pub ensures: Option<P<Expr>>, +} + #[derive(Clone, Encodable, Decodable, Debug)] pub struct Fn { pub defaultness: Defaultness, + pub ident: Ident, pub generics: Generics, pub sig: FnSig, + pub contract: Option<P<FnContract>>, + pub define_opaque: Option<ThinVec<(NodeId, Path)>>, pub body: Option<P<Block>>, } @@ -3278,6 +3593,7 @@ pub struct Delegation { pub id: NodeId, pub qself: Option<P<QSelf>>, pub path: Path, + pub ident: Ident, pub rename: Option<Ident>, pub body: Option<P<Block>>, /// The item was expanded from a glob delegation item. @@ -3295,18 +3611,22 @@ pub struct DelegationMac { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticItem { + pub ident: Ident, pub ty: P<Ty>, pub safety: Safety, pub mutability: Mutability, pub expr: Option<P<Expr>>, + pub define_opaque: Option<ThinVec<(NodeId, Path)>>, } #[derive(Clone, Encodable, Decodable, Debug)] pub struct ConstItem { pub defaultness: Defaultness, + pub ident: Ident, pub generics: Generics, pub ty: P<Ty>, pub expr: Option<P<Expr>>, + pub define_opaque: Option<ThinVec<(NodeId, Path)>>, } // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. @@ -3315,7 +3635,7 @@ pub enum ItemKind { /// An `extern crate` item, with the optional *original* crate name if the crate was renamed. /// /// E.g., `extern crate foo` or `extern crate foo_bar as foo`. - ExternCrate(Option<Symbol>), + ExternCrate(Option<Symbol>, Ident), /// A use declaration item (`use`). /// /// E.g., `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`. @@ -3337,7 +3657,7 @@ pub enum ItemKind { /// E.g., `mod foo;` or `mod foo { .. }`. /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not /// semantically by Rust. - Mod(Safety, ModKind), + Mod(Safety, Ident, ModKind), /// An external module (`extern`). /// /// E.g., `extern {}` or `extern "C" {}`. @@ -3351,15 +3671,15 @@ pub enum ItemKind { /// An enum definition (`enum`). /// /// E.g., `enum Foo<A, B> { C<A>, D<B> }`. - Enum(EnumDef, Generics), + Enum(Ident, EnumDef, Generics), /// A struct definition (`struct`). /// /// E.g., `struct Foo<A> { x: A }`. - Struct(VariantData, Generics), + Struct(Ident, VariantData, Generics), /// A union definition (`union`). /// /// E.g., `union Foo<A, B> { x: A, y: B }`. - Union(VariantData, Generics), + Union(Ident, VariantData, Generics), /// A trait declaration (`trait`). /// /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`. @@ -3367,7 +3687,7 @@ pub enum ItemKind { /// Trait alias. /// /// E.g., `trait Foo = Bar + Quux;`. - TraitAlias(Generics, GenericBounds), + TraitAlias(Ident, Generics, GenericBounds), /// An implementation. /// /// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`. @@ -3378,7 +3698,7 @@ pub enum ItemKind { MacCall(P<MacCall>), /// A macro definition. - MacroDef(MacroDef), + MacroDef(Ident, MacroDef), /// A single delegation item (`reuse`). /// @@ -3390,6 +3710,31 @@ pub enum ItemKind { } impl ItemKind { + pub fn ident(&self) -> Option<Ident> { + match *self { + ItemKind::ExternCrate(_, ident) + | ItemKind::Static(box StaticItem { ident, .. }) + | ItemKind::Const(box ConstItem { ident, .. }) + | ItemKind::Fn(box Fn { ident, .. }) + | ItemKind::Mod(_, ident, _) + | ItemKind::TyAlias(box TyAlias { ident, .. }) + | ItemKind::Enum(ident, ..) + | ItemKind::Struct(ident, ..) + | ItemKind::Union(ident, ..) + | ItemKind::Trait(box Trait { ident, .. }) + | ItemKind::TraitAlias(ident, ..) + | ItemKind::MacroDef(ident, _) + | ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), + + ItemKind::Use(_) + | ItemKind::ForeignMod(_) + | ItemKind::GlobalAsm(_) + | ItemKind::Impl(_) + | ItemKind::MacCall(_) + | ItemKind::DelegationMac(_) => None, + } + } + /// "a" or "an" pub fn article(&self) -> &'static str { use ItemKind::*; @@ -3430,11 +3775,11 @@ impl ItemKind { Self::Fn(box Fn { generics, .. }) | Self::TyAlias(box TyAlias { generics, .. }) | Self::Const(box ConstItem { generics, .. }) - | Self::Enum(_, generics) - | Self::Struct(_, generics) - | Self::Union(_, generics) + | Self::Enum(_, _, generics) + | Self::Struct(_, _, generics) + | Self::Union(_, _, generics) | Self::Trait(box Trait { generics, .. }) - | Self::TraitAlias(generics, _) + | Self::TraitAlias(_, generics, _) | Self::Impl(box Impl { generics, .. }) => Some(generics), _ => None, } @@ -3470,6 +3815,17 @@ pub enum AssocItemKind { } impl AssocItemKind { + pub fn ident(&self) -> Option<Ident> { + match *self { + AssocItemKind::Const(box ConstItem { ident, .. }) + | AssocItemKind::Fn(box Fn { ident, .. }) + | AssocItemKind::Type(box TyAlias { ident, .. }) + | AssocItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), + + AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(_) => None, + } + } + pub fn defaultness(&self) -> Defaultness { match *self { Self::Const(box ConstItem { defaultness, .. }) @@ -3516,14 +3872,26 @@ impl TryFrom<ItemKind> for AssocItemKind { pub enum ForeignItemKind { /// A foreign static item (`static FOO: u8`). Static(Box<StaticItem>), - /// An foreign function. + /// A foreign function. Fn(Box<Fn>), - /// An foreign type. + /// A foreign type. TyAlias(Box<TyAlias>), /// A macro expanding to foreign items. MacCall(P<MacCall>), } +impl ForeignItemKind { + pub fn ident(&self) -> Option<Ident> { + match *self { + ForeignItemKind::Static(box StaticItem { ident, .. }) + | ForeignItemKind::Fn(box Fn { ident, .. }) + | ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => Some(ident), + + ForeignItemKind::MacCall(_) => None, + } + } +} + impl From<ForeignItemKind> for ItemKind { fn from(foreign_item_kind: ForeignItemKind) -> ItemKind { match foreign_item_kind { @@ -3560,23 +3928,23 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(AssocItem, 88); + static_assert_size!(AssocItem, 80); static_assert_size!(AssocItemKind, 16); static_assert_size!(Attribute, 32); static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 160); - static_assert_size!(ForeignItem, 88); + static_assert_size!(Fn, 184); + static_assert_size!(ForeignItem, 80); static_assert_size!(ForeignItemKind, 16); static_assert_size!(GenericArg, 24); static_assert_size!(GenericBound, 88); static_assert_size!(Generics, 40); static_assert_size!(Impl, 136); - static_assert_size!(Item, 136); - static_assert_size!(ItemKind, 64); + static_assert_size!(Item, 144); + static_assert_size!(ItemKind, 80); static_assert_size!(LitKind, 24); - static_assert_size!(Local, 80); + static_assert_size!(Local, 96); static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); static_assert_size!(Pat, 72); diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 60f8c6e10481b..7f98e7ba8a615 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -6,12 +6,11 @@ use std::fmt; use std::marker::PhantomData; use crate::ptr::P; -use crate::token::Nonterminal; use crate::tokenstream::LazyAttrTokenStream; use crate::{ Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField, FieldDef, ForeignItem, GenericParam, Item, NodeId, Param, Pat, PatField, Path, Stmt, StmtKind, - Ty, Variant, Visibility, + Ty, Variant, Visibility, WherePredicate, }; /// A utility trait to reduce boilerplate. @@ -79,6 +78,7 @@ impl_has_node_id!( Stmt, Ty, Variant, + WherePredicate, ); impl<T: AstDeref<Target: HasNodeId>> HasNodeId for T { @@ -127,7 +127,16 @@ macro_rules! impl_has_tokens_none { } impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility); -impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant); +impl_has_tokens_none!( + Arm, + ExprField, + FieldDef, + GenericParam, + Param, + PatField, + Variant, + WherePredicate +); impl<T: AstDeref<Target: HasTokens>> HasTokens for T { fn tokens(&self) -> Option<&LazyAttrTokenStream> { @@ -196,35 +205,6 @@ impl HasTokens for Attribute { } } -impl HasTokens for Nonterminal { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - match self { - Nonterminal::NtItem(item) => item.tokens(), - Nonterminal::NtStmt(stmt) => stmt.tokens(), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), - Nonterminal::NtPat(pat) => pat.tokens(), - Nonterminal::NtTy(ty) => ty.tokens(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens(), - Nonterminal::NtPath(path) => path.tokens(), - Nonterminal::NtVis(vis) => vis.tokens(), - Nonterminal::NtBlock(block) => block.tokens(), - } - } - fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> { - match self { - Nonterminal::NtItem(item) => item.tokens_mut(), - Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), - Nonterminal::NtPat(pat) => pat.tokens_mut(), - Nonterminal::NtTy(ty) => ty.tokens_mut(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), - Nonterminal::NtPath(path) => path.tokens_mut(), - Nonterminal::NtVis(vis) => vis.tokens_mut(), - Nonterminal::NtBlock(block) => block.tokens_mut(), - } - } -} - /// A trait for AST nodes having (or not having) attributes. pub trait HasAttrs { /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner @@ -289,6 +269,7 @@ impl_has_attrs!( Param, PatField, Variant, + WherePredicate, ); impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index b73412a4b1de9..f165c4ddcdd4d 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -1,22 +1,23 @@ //! Functions dealing with attributes and meta items. -use std::iter; +use std::fmt::Debug; use std::sync::atomic::{AtomicU32, Ordering}; use rustc_index::bit_set::GrowableBitSet; -use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; use crate::ast::{ - AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, - NormalAttr, Path, PathSegment, Safety, + AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs, + Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path, + PathSegment, Safety, }; use crate::ptr::P; -use crate::token::{self, CommentKind, Delimiter, Token}; -use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenTree}; +use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token}; +use crate::tokenstream::{ + DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree, +}; use crate::util::comments; use crate::util::literal::escape_string_symbol; @@ -66,11 +67,27 @@ impl Attribute { AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } +} + +impl AttributeExt for Attribute { + fn id(&self) -> AttrId { + self.id + } + + fn value_span(&self) -> Option<Span> { + match &self.kind { + AttrKind::Normal(normal) => match &normal.item.args { + AttrArgs::Eq { expr, .. } => Some(expr.span), + _ => None, + }, + AttrKind::DocComment(..) => None, + } + } /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not /// a doc comment) will return `false`. - pub fn is_doc_comment(&self) -> bool { + fn is_doc_comment(&self) -> bool { match self.kind { AttrKind::Normal(..) => false, AttrKind::DocComment(..) => true, @@ -78,7 +95,7 @@ impl Attribute { } /// For a single-segment attribute, returns its name; otherwise, returns `None`. - pub fn ident(&self) -> Option<Ident> { + fn ident(&self) -> Option<Ident> { match &self.kind { AttrKind::Normal(normal) => { if let [ident] = &*normal.item.path.segments { @@ -91,28 +108,14 @@ impl Attribute { } } - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name - } - - pub fn path(&self) -> SmallVec<[Symbol; 1]> { - match &self.kind { - AttrKind::Normal(normal) => { - normal.item.path.segments.iter().map(|s| s.ident.name).collect() - } - AttrKind::DocComment(..) => smallvec![sym::doc], - } - } - - #[inline] - pub fn has_name(&self, name: Symbol) -> bool { + fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> { match &self.kind { - AttrKind::Normal(normal) => normal.item.path == name, - AttrKind::DocComment(..) => false, + AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()), + AttrKind::DocComment(_, _) => None, } } - pub fn path_matches(&self, name: &[Symbol]) -> bool { + fn path_matches(&self, name: &[Symbol]) -> bool { match &self.kind { AttrKind::Normal(normal) => { normal.item.path.segments.len() == name.len() @@ -128,7 +131,11 @@ impl Attribute { } } - pub fn is_word(&self) -> bool { + fn span(&self) -> Span { + self.span + } + + fn is_word(&self) -> bool { if let AttrKind::Normal(normal) = &self.kind { matches!(normal.item.args, AttrArgs::Empty) } else { @@ -136,14 +143,36 @@ impl Attribute { } } - pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { + /// Returns a list of meta items if the attribute is delimited with parenthesis: + /// + /// ```text + /// #[attr(a, b = "c")] // Returns `Some()`. + /// #[attr = ""] // Returns `None`. + /// #[attr] // Returns `None`. + /// ``` + fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { match &self.kind { AttrKind::Normal(normal) => normal.item.meta_item_list(), AttrKind::DocComment(..) => None, } } - pub fn value_str(&self) -> Option<Symbol> { + /// Returns the string value in: + /// + /// ```text + /// #[attribute = "value"] + /// ^^^^^^^ + /// ``` + /// + /// It returns `None` in any other cases, including doc comments if they + /// are not under the form `#[doc = "..."]`. + /// + /// It also returns `None` for: + /// + /// ```text + /// #[attr("value")] + /// ``` + fn value_str(&self) -> Option<Symbol> { match &self.kind { AttrKind::Normal(normal) => normal.item.value_str(), AttrKind::DocComment(..) => None, @@ -155,7 +184,7 @@ impl Attribute { /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`. /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`. /// * `#[doc(...)]` returns `None`. - pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { match &self.kind { AttrKind::DocComment(kind, data) => Some((*data, *kind)), AttrKind::Normal(normal) if normal.item.path == sym::doc => { @@ -169,7 +198,7 @@ impl Attribute { /// * `///doc` returns `Some("doc")`. /// * `#[doc = "doc"]` returns `Some("doc")`. /// * `#[doc(...)]` returns `None`. - pub fn doc_str(&self) -> Option<Symbol> { + fn doc_str(&self) -> Option<Symbol> { match &self.kind { AttrKind::DocComment(.., data) => Some(*data), AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(), @@ -177,14 +206,14 @@ impl Attribute { } } - pub fn may_have_doc_links(&self) -> bool { - self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str())) + fn style(&self) -> AttrStyle { + self.style } +} - pub fn is_proc_macro_attr(&self) -> bool { - [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] - .iter() - .any(|kind| self.has_name(*kind)) +impl Attribute { + pub fn may_have_doc_links(&self) -> bool { + self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str())) } /// Extracts the MetaItem from inside this Attribute. @@ -223,18 +252,35 @@ impl AttrItem { self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) } - fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { + pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { match &self.args { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) } - AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None, + AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None, } } + /// Returns the string value in: + /// + /// ```text + /// #[attribute = "value"] + /// ^^^^^^^ + /// ``` + /// + /// It returns `None` in any other cases like: + /// + /// ```text + /// #[attr("value")] + /// ``` fn value_str(&self) -> Option<Symbol> { match &self.args { - AttrArgs::Eq(_, args) => args.value_str(), + AttrArgs::Eq { expr, .. } => match expr.kind { + ExprKind::Lit(token_lit) => { + LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str()) + } + _ => None, + }, AttrArgs::Delimited(_) | AttrArgs::Empty => None, } } @@ -253,28 +299,14 @@ impl AttrItem { } } -impl AttrArgsEq { - fn value_str(&self) -> Option<Symbol> { - match self { - AttrArgsEq::Ast(expr) => match expr.kind { - ExprKind::Lit(token_lit) => { - LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str()) - } - _ => None, - }, - AttrArgsEq::Hir(lit) => lit.kind.str(), - } - } -} - impl MetaItem { /// For a single-segment meta item, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option<Ident> { - if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None } + if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None } } - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name + pub fn name(&self) -> Option<Symbol> { + self.ident().map(|ident| ident.name) } pub fn has_name(&self, name: Symbol) -> bool { @@ -315,6 +347,18 @@ impl MetaItem { Some(self.name_value_literal()?.span) } + /// Returns the string value in: + /// + /// ```text + /// #[attribute = "value"] + /// ^^^^^^^ + /// ``` + /// + /// It returns `None` in any other cases like: + /// + /// ```text + /// #[attr("value")] + /// ``` pub fn value_str(&self) -> Option<Symbol> { match &self.kind { MetaItemKind::NameValue(v) => v.kind.str(), @@ -322,12 +366,9 @@ impl MetaItem { } } - fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> - where - I: Iterator<Item = &'a TokenTree>, - { + fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> { // FIXME: Share code with `parse_path`. - let tt = tokens.next().map(|tt| TokenTree::uninterpolate(tt)); + let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt)); let path = match tt.as_deref() { Some(&TokenTree::Token( Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span }, @@ -335,9 +376,9 @@ impl MetaItem { )) => 'arm: { let mut segments = if let &token::Ident(name, _) = kind { if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - tokens.peek() + iter.peek() { - tokens.next(); + iter.next(); thin_vec![PathSegment::from_ident(Ident::new(name, span))] } else { break 'arm Path::from_ident(Ident::new(name, span)); @@ -347,16 +388,16 @@ impl MetaItem { }; loop { if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = - tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() + iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() { segments.push(PathSegment::from_ident(Ident::new(name, span))); } else { return None; } if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - tokens.peek() + iter.peek() { - tokens.next(); + iter.next(); } else { break; } @@ -364,21 +405,24 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments, tokens: None } } - Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt { - token::Nonterminal::NtMeta(item) => return item.meta(item.path.span), - token::Nonterminal::NtPath(path) => (**path).clone(), - _ => return None, - }, - Some(TokenTree::Token( - Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, - _, + Some(TokenTree::Delimited( + _span, + _spacing, + Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Meta { .. } | MetaVarKind::Path, + )), + _stream, )) => { + // This path is currently unreachable in the test suite. + unreachable!() + } + Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => { panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt); } _ => return None, }; - let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi()); - let kind = MetaItemKind::from_tokens(tokens)?; + let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi()); + let kind = MetaItemKind::from_tokens(iter)?; let hi = match &kind { MetaItemKind::NameValue(lit) => lit.span.hi(), MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()), @@ -393,13 +437,14 @@ impl MetaItem { } impl MetaItemKind { - fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> { - let mut tokens = tokens.trees().peekable(); + // public because it can be called in the hir + pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> { + let mut iter = tokens.iter(); let mut result = ThinVec::new(); - while tokens.peek().is_some() { - let item = MetaItemInner::from_tokens(&mut tokens)?; + while iter.peek().is_some() { + let item = MetaItemInner::from_tokens(&mut iter)?; result.push(item); - match tokens.next() { + match iter.next() { None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {} _ => return None, } @@ -407,12 +452,10 @@ impl MetaItemKind { Some(result) } - fn name_value_from_tokens<'a>( - tokens: &mut impl Iterator<Item = &'a TokenTree>, - ) -> Option<MetaItemKind> { - match tokens.next() { - Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => { - MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees()) + fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> { + match iter.next() { + Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => { + MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter()) } Some(TokenTree::Token(token, _)) => { MetaItemLit::from_token(token).map(MetaItemKind::NameValue) @@ -421,19 +464,17 @@ impl MetaItemKind { } } - fn from_tokens<'a>( - tokens: &mut iter::Peekable<impl Iterator<Item = &'a TokenTree>>, - ) -> Option<MetaItemKind> { - match tokens.peek() { + fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> { + match iter.peek() { Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => { let inner_tokens = inner_tokens.clone(); - tokens.next(); + iter.next(); MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List) } Some(TokenTree::Delimited(..)) => None, Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => { - tokens.next(); - MetaItemKind::name_value_from_tokens(tokens) + iter.next(); + MetaItemKind::name_value_from_tokens(iter) } _ => Some(MetaItemKind::Word), } @@ -446,7 +487,7 @@ impl MetaItemKind { MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List) } AttrArgs::Delimited(..) => None, - AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind { + AttrArgs::Eq { expr, .. } => match expr.kind { ExprKind::Lit(token_lit) => { // Turn failures to `None`, we'll get parse errors elsewhere. MetaItemLit::from_token_lit(token_lit, expr.span) @@ -455,7 +496,6 @@ impl MetaItemKind { } _ => None, }, - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())), } } } @@ -468,13 +508,14 @@ impl MetaItemInner { } } - /// For a single-segment meta item, returns its name; otherwise, returns `None`. + /// For a single-segment meta item, returns its identifier; otherwise, returns `None`. pub fn ident(&self) -> Option<Ident> { self.meta_item().and_then(|meta_item| meta_item.ident()) } - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name + /// For a single-segment meta item, returns its name; otherwise, returns `None`. + pub fn name(&self) -> Option<Symbol> { + self.ident().map(|ident| ident.name) } /// Returns `true` if this list item is a MetaItem with a name of `name`. @@ -527,6 +568,14 @@ impl MetaItemInner { } } + /// Returns the bool if `self` is a boolean `MetaItemInner::Literal`. + pub fn boolean_literal(&self) -> Option<bool> { + match self { + MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b), + _ => None, + } + } + /// Returns the `MetaItem` if `self` is a `MetaItemInner::MetaItem` or if it's /// `MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`. pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> { @@ -550,22 +599,19 @@ impl MetaItemInner { self.meta_item().is_some() } - fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemInner> - where - I: Iterator<Item = &'a TokenTree>, - { - match tokens.peek() { + fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> { + match iter.peek() { Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => { - tokens.next(); + iter.next(); return Some(MetaItemInner::Lit(lit)); } - Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => { - tokens.next(); - return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable()); + Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => { + iter.next(); + return MetaItemInner::from_tokens(&mut inner_tokens.iter()); } _ => {} } - MetaItem::from_tokens(tokens).map(MetaItemInner::MetaItem) + MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem) } } @@ -579,7 +625,7 @@ pub fn mk_doc_comment( Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } } -pub fn mk_attr( +fn mk_attr( g: &AttrIdGenerator, style: AttrStyle, unsafety: Safety, @@ -656,26 +702,187 @@ pub fn mk_attr_name_value_str( tokens: None, }); let path = Path::from_ident(Ident::new(name, span)); - let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr)); + let args = AttrArgs::Eq { eq_span: span, expr }; mk_attr(g, style, unsafety, path, args, span) } -pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> { +pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> { attrs.iter().filter(move |attr| attr.has_name(name)) } -pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> { +pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> { filter_by_name(attrs, name).next() } -pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> { +pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> { find_by_name(attrs, name).and_then(|attr| attr.value_str()) } -pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { +pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool { find_by_name(attrs, name).is_some() } pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool { items.iter().any(|item| item.has_name(name)) } + +impl MetaItemLit { + pub fn value_str(&self) -> Option<Symbol> { + LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str()) + } +} + +pub trait AttributeExt: Debug { + fn id(&self) -> AttrId; + + /// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`), + /// return the name of the attribute; otherwise, returns `None`. + fn name(&self) -> Option<Symbol> { + self.ident().map(|ident| ident.name) + } + + /// Get the meta item list, `#[attr(meta item list)]` + fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>; + + /// Gets the value literal, as string, when using `#[attr = value]` + fn value_str(&self) -> Option<Symbol>; + + /// Gets the span of the value literal, as string, when using `#[attr = value]` + fn value_span(&self) -> Option<Span>; + + /// For a single-segment attribute, returns its ident; otherwise, returns `None`. + fn ident(&self) -> Option<Ident>; + + /// Checks whether the path of this attribute matches the name. + /// + /// Matches one segment of the path to each element in `name` + fn path_matches(&self, name: &[Symbol]) -> bool; + + /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). + /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not + /// a doc comment) will return `false`. + fn is_doc_comment(&self) -> bool; + + #[inline] + fn has_name(&self, name: Symbol) -> bool { + self.ident().map(|x| x.name == name).unwrap_or(false) + } + + #[inline] + fn has_any_name(&self, names: &[Symbol]) -> bool { + names.iter().any(|&name| self.has_name(name)) + } + + /// get the span of the entire attribute + fn span(&self) -> Span; + + fn is_word(&self) -> bool; + + fn path(&self) -> SmallVec<[Symbol; 1]> { + self.ident_path() + .map(|i| i.into_iter().map(|i| i.name).collect()) + .unwrap_or(smallvec![sym::doc]) + } + + /// Returns None for doc comments + fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>; + + /// Returns the documentation if this is a doc comment or a sugared doc comment. + /// * `///doc` returns `Some("doc")`. + /// * `#[doc = "doc"]` returns `Some("doc")`. + /// * `#[doc(...)]` returns `None`. + fn doc_str(&self) -> Option<Symbol>; + + fn is_proc_macro_attr(&self) -> bool { + [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] + .iter() + .any(|kind| self.has_name(*kind)) + } + + /// Returns the documentation and its kind if this is a doc comment or a sugared doc comment. + /// * `///doc` returns `Some(("doc", CommentKind::Line))`. + /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`. + /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`. + /// * `#[doc(...)]` returns `None`. + fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>; + + fn style(&self) -> AttrStyle; +} + +// FIXME(fn_delegation): use function delegation instead of manually forwarding + +impl Attribute { + pub fn id(&self) -> AttrId { + AttributeExt::id(self) + } + + pub fn name(&self) -> Option<Symbol> { + AttributeExt::name(self) + } + + pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { + AttributeExt::meta_item_list(self) + } + + pub fn value_str(&self) -> Option<Symbol> { + AttributeExt::value_str(self) + } + + pub fn value_span(&self) -> Option<Span> { + AttributeExt::value_span(self) + } + + pub fn ident(&self) -> Option<Ident> { + AttributeExt::ident(self) + } + + pub fn path_matches(&self, name: &[Symbol]) -> bool { + AttributeExt::path_matches(self, name) + } + + pub fn is_doc_comment(&self) -> bool { + AttributeExt::is_doc_comment(self) + } + + #[inline] + pub fn has_name(&self, name: Symbol) -> bool { + AttributeExt::has_name(self, name) + } + + #[inline] + pub fn has_any_name(&self, names: &[Symbol]) -> bool { + AttributeExt::has_any_name(self, names) + } + + pub fn span(&self) -> Span { + AttributeExt::span(self) + } + + pub fn is_word(&self) -> bool { + AttributeExt::is_word(self) + } + + pub fn path(&self) -> SmallVec<[Symbol; 1]> { + AttributeExt::path(self) + } + + pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> { + AttributeExt::ident_path(self) + } + + pub fn doc_str(&self) -> Option<Symbol> { + AttributeExt::doc_str(self) + } + + pub fn is_proc_macro_attr(&self) -> bool { + AttributeExt::is_proc_macro_attr(self) + } + + pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + AttributeExt::doc_str_and_comment_kind(self) + } + + pub fn style(&self) -> AttrStyle { + AttributeExt::style(self) + } +} diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index 45c4caca6e9ee..12cbb3b2a15f7 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -1,7 +1,6 @@ -use rustc_span::Symbol; -use rustc_span::symbol::sym; +use rustc_span::{Symbol, sym}; -use crate::{Attribute, attr}; +use crate::attr::{self, AttributeExt}; #[derive(Debug)] pub enum EntryPointType { @@ -19,12 +18,6 @@ pub enum EntryPointType { /// fn main() {} /// ``` RustcMainAttr, - /// This is a function with the `#[start]` attribute. - /// ```ignore (clashes with test entrypoint) - /// #[start] - /// fn main() {} - /// ``` - Start, /// This function is **not** an entrypoint but simply named `main` (not at the root). /// This is only used for diagnostics. /// ``` @@ -37,13 +30,11 @@ pub enum EntryPointType { } pub fn entry_point_type( - attrs: &[Attribute], + attrs: &[impl AttributeExt], at_root: bool, name: Option<Symbol>, ) -> EntryPointType { - if attr::contains_name(attrs, sym::start) { - EntryPointType::Start - } else if attr::contains_name(attrs, sym::rustc_main) { + if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else if let Some(name) = name && name == sym::main diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index bee7dfb61da87..dd8d5ae624a3c 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -1,5 +1,5 @@ use rustc_macros::HashStable_Generic; -use rustc_span::symbol::{Symbol, sym}; +use rustc_span::{Symbol, sym}; #[derive(Clone, Debug, Copy, Eq, PartialEq, HashStable_Generic)] pub enum AllocatorKind { diff --git a/compiler/rustc_ast/src/expand/autodiff_attrs.rs b/compiler/rustc_ast/src/expand/autodiff_attrs.rs index 05714731b9d4d..2f918faaf752b 100644 --- a/compiler/rustc_ast/src/expand/autodiff_attrs.rs +++ b/compiler/rustc_ast/src/expand/autodiff_attrs.rs @@ -6,7 +6,6 @@ use std::fmt::{self, Display, Formatter}; use std::str::FromStr; -use crate::expand::typetree::TypeTree; use crate::expand::{Decodable, Encodable, HashStable_Generic}; use crate::ptr::P; use crate::{Ty, TyKind}; @@ -18,7 +17,6 @@ use crate::{Ty, TyKind}; /// functions. The proper solution is to recognize and resolve this DAG of autodiff invocations, /// as it's already done in the C++ and Julia frontend of Enzyme. /// -/// (FIXME) remove *First variants. /// Documentation for using [reverse](https://enzyme.mit.edu/rust/rev.html) and /// [forward](https://enzyme.mit.edu/rust/fwd.html) mode is available online. #[derive(Clone, Copy, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -31,14 +29,6 @@ pub enum DiffMode { Forward, /// The target function, to be created using reverse mode AD. Reverse, - /// The target function, to be created using forward mode AD. - /// This target function will also be used as a source for higher order derivatives, - /// so compute it before all Forward/Reverse targets and optimize it through llvm. - ForwardFirst, - /// The target function, to be created using reverse mode AD. - /// This target function will also be used as a source for higher order derivatives, - /// so compute it before all Forward/Reverse targets and optimize it through llvm. - ReverseFirst, } /// Dual and Duplicated (and their Only variants) are getting lowered to the same Enzyme Activity. @@ -60,8 +50,16 @@ pub enum DiffActivity { /// with it. Dual, /// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument + /// with it. It expects the shadow argument to be `width` times larger than the original + /// input/output. + Dualv, + /// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument /// with it. Drop the code which updates the original input/output for maximum performance. DualOnly, + /// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument + /// with it. Drop the code which updates the original input/output for maximum performance. + /// It expects the shadow argument to be `width` times larger than the original input/output. + DualvOnly, /// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument. Duplicated, /// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument. @@ -69,7 +67,15 @@ pub enum DiffActivity { DuplicatedOnly, /// All Integers must be Const, but these are used to mark the integer which represents the /// length of a slice/vec. This is used for safety checks on slices. - FakeActivitySize, + /// The integer (if given) specifies the size of the slice element in bytes. + FakeActivitySize(Option<u32>), +} + +impl DiffActivity { + pub fn is_dual_or_const(&self) -> bool { + use DiffActivity::*; + matches!(self, |Dual| DualOnly | Dualv | DualvOnly | Const) + } } /// We generate one of these structs for each `#[autodiff(...)]` attribute. #[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -79,27 +85,41 @@ pub struct AutoDiffItem { /// The name of the function being generated pub target: String, pub attrs: AutoDiffAttrs, - /// Describe the memory layout of input types - pub inputs: Vec<TypeTree>, - /// Describe the memory layout of the output type - pub output: TypeTree, } + #[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct AutoDiffAttrs { /// Conceptually either forward or reverse mode AD, as described in various autodiff papers and /// e.g. in the [JAX /// Documentation](https://jax.readthedocs.io/en/latest/_tutorials/advanced-autodiff.html#how-it-s-made-two-foundational-autodiff-functions). pub mode: DiffMode, + /// A user-provided, batching width. If not given, we will default to 1 (no batching). + /// Calling a differentiated, non-batched function through a loop 100 times is equivalent to: + /// - Calling the function 50 times with a batch size of 2 + /// - Calling the function 25 times with a batch size of 4, + /// etc. A batched function takes more (or longer) arguments, and might be able to benefit from + /// cache locality, better re-usal of primal values, and other optimizations. + /// We will (before LLVM's vectorizer runs) just generate most LLVM-IR instructions `width` + /// times, so this massively increases code size. As such, values like 1024 are unlikely to + /// work. We should consider limiting this to u8 or u16, but will leave it at u32 for + /// experiments for now and focus on documenting the implications of a large width. + pub width: u32, pub ret_activity: DiffActivity, pub input_activity: Vec<DiffActivity>, } +impl AutoDiffAttrs { + pub fn has_primal_ret(&self) -> bool { + matches!(self.ret_activity, DiffActivity::Active | DiffActivity::Dual) + } +} + impl DiffMode { pub fn is_rev(&self) -> bool { - matches!(self, DiffMode::Reverse | DiffMode::ReverseFirst) + matches!(self, DiffMode::Reverse) } pub fn is_fwd(&self) -> bool { - matches!(self, DiffMode::Forward | DiffMode::ForwardFirst) + matches!(self, DiffMode::Forward) } } @@ -110,8 +130,6 @@ impl Display for DiffMode { DiffMode::Source => write!(f, "Source"), DiffMode::Forward => write!(f, "Forward"), DiffMode::Reverse => write!(f, "Reverse"), - DiffMode::ForwardFirst => write!(f, "ForwardFirst"), - DiffMode::ReverseFirst => write!(f, "ReverseFirst"), } } } @@ -129,12 +147,8 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool { match mode { DiffMode::Error => false, DiffMode::Source => false, - DiffMode::Forward | DiffMode::ForwardFirst => { - activity == DiffActivity::Dual - || activity == DiffActivity::DualOnly - || activity == DiffActivity::Const - } - DiffMode::Reverse | DiffMode::ReverseFirst => { + DiffMode::Forward => activity.is_dual_or_const(), + DiffMode::Reverse => { activity == DiffActivity::Const || activity == DiffActivity::Active || activity == DiffActivity::ActiveOnly @@ -151,10 +165,8 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool { pub fn valid_ty_for_activity(ty: &P<Ty>, activity: DiffActivity) -> bool { use DiffActivity::*; // It's always allowed to mark something as Const, since we won't compute derivatives wrt. it. - if matches!(activity, Const) { - return true; - } - if matches!(activity, Dual | DualOnly) { + // Dual variants also support all types. + if activity.is_dual_or_const() { return true; } // FIXME(ZuseZ4) We should make this more robust to also @@ -170,10 +182,8 @@ pub fn valid_input_activity(mode: DiffMode, activity: DiffActivity) -> bool { return match mode { DiffMode::Error => false, DiffMode::Source => false, - DiffMode::Forward | DiffMode::ForwardFirst => { - matches!(activity, Dual | DualOnly | Const) - } - DiffMode::Reverse | DiffMode::ReverseFirst => { + DiffMode::Forward => activity.is_dual_or_const(), + DiffMode::Reverse => { matches!(activity, Active | ActiveOnly | Duplicated | DuplicatedOnly | Const) } }; @@ -187,10 +197,12 @@ impl Display for DiffActivity { DiffActivity::Active => write!(f, "Active"), DiffActivity::ActiveOnly => write!(f, "ActiveOnly"), DiffActivity::Dual => write!(f, "Dual"), + DiffActivity::Dualv => write!(f, "Dualv"), DiffActivity::DualOnly => write!(f, "DualOnly"), + DiffActivity::DualvOnly => write!(f, "DualvOnly"), DiffActivity::Duplicated => write!(f, "Duplicated"), DiffActivity::DuplicatedOnly => write!(f, "DuplicatedOnly"), - DiffActivity::FakeActivitySize => write!(f, "FakeActivitySize"), + DiffActivity::FakeActivitySize(s) => write!(f, "FakeActivitySize({:?})", s), } } } @@ -204,8 +216,6 @@ impl FromStr for DiffMode { "Source" => Ok(DiffMode::Source), "Forward" => Ok(DiffMode::Forward), "Reverse" => Ok(DiffMode::Reverse), - "ForwardFirst" => Ok(DiffMode::ForwardFirst), - "ReverseFirst" => Ok(DiffMode::ReverseFirst), _ => Err(()), } } @@ -220,7 +230,9 @@ impl FromStr for DiffActivity { "ActiveOnly" => Ok(DiffActivity::ActiveOnly), "Const" => Ok(DiffActivity::Const), "Dual" => Ok(DiffActivity::Dual), + "Dualv" => Ok(DiffActivity::Dualv), "DualOnly" => Ok(DiffActivity::DualOnly), + "DualvOnly" => Ok(DiffActivity::DualvOnly), "Duplicated" => Ok(DiffActivity::Duplicated), "DuplicatedOnly" => Ok(DiffActivity::DuplicatedOnly), _ => Err(()), @@ -236,9 +248,10 @@ impl AutoDiffAttrs { self.ret_activity == DiffActivity::ActiveOnly } - pub fn error() -> Self { + pub const fn error() -> Self { AutoDiffAttrs { mode: DiffMode::Error, + width: 0, ret_activity: DiffActivity::None, input_activity: Vec::new(), } @@ -246,6 +259,7 @@ impl AutoDiffAttrs { pub fn source() -> Self { AutoDiffAttrs { mode: DiffMode::Source, + width: 0, ret_activity: DiffActivity::None, input_activity: Vec::new(), } @@ -262,22 +276,14 @@ impl AutoDiffAttrs { !matches!(self.mode, DiffMode::Error | DiffMode::Source) } - pub fn into_item( - self, - source: String, - target: String, - inputs: Vec<TypeTree>, - output: TypeTree, - ) -> AutoDiffItem { - AutoDiffItem { source, target, inputs, output, attrs: self } + pub fn into_item(self, source: String, target: String) -> AutoDiffItem { + AutoDiffItem { source, target, attrs: self } } } impl fmt::Display for AutoDiffItem { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Differentiating {} -> {}", self.source, self.target)?; - write!(f, " with attributes: {:?}", self.attrs)?; - write!(f, " with inputs: {:?}", self.inputs)?; - write!(f, " with output: {:?}", self.output) + write!(f, " with attributes: {:?}", self.attrs) } } diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs index d259677e98e3d..323a8fab6d592 100644 --- a/compiler/rustc_ast/src/expand/mod.rs +++ b/compiler/rustc_ast/src/expand/mod.rs @@ -1,8 +1,8 @@ //! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`. use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_span::Ident; use rustc_span::def_id::DefId; -use rustc_span::symbol::Ident; use crate::MetaItem; @@ -13,12 +13,12 @@ pub mod typetree; #[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] pub struct StrippedCfgItem<ModId = DefId> { pub parent_module: ModId, - pub name: Ident, + pub ident: Ident, pub cfg: MetaItem, } impl<ModId> StrippedCfgItem<ModId> { pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> { - StrippedCfgItem { parent_module: f(self.parent_module), name: self.name, cfg: self.cfg } + StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg } } } diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index d5900d83e4d1a..b611ddea1d9f1 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -1,10 +1,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_macros::{Decodable, Encodable}; -use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::{Ident, Span, Symbol}; use crate::Expr; use crate::ptr::P; +use crate::token::LitKind; // Definitions: // @@ -46,6 +46,10 @@ pub struct FormatArgs { pub span: Span, pub template: Vec<FormatArgsPiece>, pub arguments: FormatArguments, + /// The raw, un-split format string literal, with no escaping or processing. + /// + /// Generally only useful for lints that care about the raw bytes the user wrote. + pub uncooked_fmt_str: (LitKind, Symbol), } /// A piece of a format template string. @@ -262,7 +266,7 @@ pub enum FormatAlignment { #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` - Literal(usize), + Literal(u16), /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. Argument(FormatArgPosition), } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 7730d0b4b78df..294c6c9ba7a50 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -19,7 +19,6 @@ #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(stmt_expr_attributes)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod util { @@ -44,20 +43,10 @@ pub mod token; pub mod tokenstream; pub mod visit; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - pub use self::ast::*; pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: rustc_span::HashStableContext { - fn hash_attr(&mut self, _: &ast::Attribute, hasher: &mut StableHasher); -} - -impl<AstCtx: crate::HashStableContext> HashStable<AstCtx> for ast::Attribute { - fn hash_stable(&self, hcx: &mut AstCtx, hasher: &mut StableHasher) { - hcx.hash_attr(self, hasher) - } -} +pub trait HashStableContext: rustc_span::HashStableContext {} diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2afbd979c3023..6aae2e481a59f 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -9,13 +9,12 @@ use std::ops::DerefMut; use std::panic; +use std::sync::Arc; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::Lrc; -use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_span::symbol::Ident; +use rustc_span::{Ident, Span}; use smallvec::{Array, SmallVec, smallvec}; use thin_vec::ThinVec; @@ -23,7 +22,7 @@ use crate::ast::*; use crate::ptr::P; use crate::token::{self, Token}; use crate::tokenstream::*; -use crate::visit::{AssocCtxt, BoundKind}; +use crate::visit::{AssocCtxt, BoundKind, FnCtxt}; pub trait ExpectOne<A: Array> { fn expect_one(self, err: &'static str) -> A::Item; @@ -37,7 +36,15 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> { } pub trait WalkItemKind { - fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor); + type Ctxt; + fn walk( + &mut self, + span: Span, + id: NodeId, + visibility: &mut Visibility, + ctxt: Self::Ctxt, + visitor: &mut impl MutVisitor, + ); } pub trait MutVisitor: Sized { @@ -95,8 +102,16 @@ pub trait MutVisitor: Sized { walk_use_tree(self, use_tree); } + fn visit_foreign_item(&mut self, ni: &mut P<ForeignItem>) { + walk_item(self, ni); + } + fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> { - walk_flat_map_item(self, ni) + walk_flat_map_foreign_item(self, ni) + } + + fn visit_item(&mut self, i: &mut P<Item>) { + walk_item(self, i); } fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> { @@ -107,16 +122,28 @@ pub trait MutVisitor: Sized { walk_fn_header(self, header); } + fn visit_field_def(&mut self, fd: &mut FieldDef) { + walk_field_def(self, fd); + } + fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> { walk_flat_map_field_def(self, fd) } + fn visit_assoc_item(&mut self, i: &mut P<AssocItem>, ctxt: AssocCtxt) { + walk_assoc_item(self, i, ctxt) + } + fn flat_map_assoc_item( &mut self, i: P<AssocItem>, - _ctxt: AssocCtxt, + ctxt: AssocCtxt, ) -> SmallVec<[P<AssocItem>; 1]> { - walk_flat_map_item(self, i) + walk_flat_map_assoc_item(self, i, ctxt) + } + + fn visit_contract(&mut self, c: &mut P<FnContract>) { + walk_contract(self, c); } fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) { @@ -144,6 +171,10 @@ pub trait MutVisitor: Sized { walk_flat_map_stmt(self, s) } + fn visit_arm(&mut self, arm: &mut Arm) { + walk_arm(self, arm); + } + fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { walk_flat_map_arm(self, arm) } @@ -178,6 +209,10 @@ pub trait MutVisitor: Sized { walk_ty(self, t); } + fn visit_ty_pat(&mut self, t: &mut P<TyPat>) { + walk_ty_pat(self, t); + } + fn visit_lifetime(&mut self, l: &mut Lifetime) { walk_lifetime(self, l); } @@ -190,6 +225,10 @@ pub trait MutVisitor: Sized { walk_foreign_mod(self, nm); } + fn visit_variant(&mut self, v: &mut Variant) { + walk_variant(self, v); + } + fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { walk_flat_map_variant(self, v) } @@ -198,6 +237,10 @@ pub trait MutVisitor: Sized { walk_ident(self, i); } + fn visit_modifiers(&mut self, m: &mut TraitBoundModifiers) { + walk_modifiers(self, m); + } + fn visit_path(&mut self, p: &mut Path) { walk_path(self, p); } @@ -242,6 +285,10 @@ pub trait MutVisitor: Sized { walk_attribute(self, at); } + fn visit_param(&mut self, param: &mut Param) { + walk_param(self, param); + } + fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { walk_flat_map_param(self, param) } @@ -262,6 +309,10 @@ pub trait MutVisitor: Sized { walk_variant_data(self, vdata); } + fn visit_generic_param(&mut self, param: &mut GenericParam) { + walk_generic_param(self, param) + } + fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { walk_flat_map_generic_param(self, param) } @@ -278,6 +329,10 @@ pub trait MutVisitor: Sized { walk_mt(self, mt); } + fn visit_expr_field(&mut self, f: &mut ExprField) { + walk_expr_field(self, f); + } + fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> { walk_flat_map_expr_field(self, f) } @@ -286,8 +341,15 @@ pub trait MutVisitor: Sized { walk_where_clause(self, where_clause); } - fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) { - walk_where_predicate(self, where_predicate); + fn flat_map_where_predicate( + &mut self, + where_predicate: WherePredicate, + ) -> SmallVec<[WherePredicate; 1]> { + walk_flat_map_where_predicate(self, where_predicate) + } + + fn visit_where_predicate_kind(&mut self, kind: &mut WherePredicateKind) { + walk_where_predicate_kind(self, kind) } fn visit_vis(&mut self, vis: &mut Visibility) { @@ -302,6 +364,10 @@ pub trait MutVisitor: Sized { // Do nothing. } + fn visit_pat_field(&mut self, fp: &mut PatField) { + walk_pat_field(self, fp) + } + fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> { walk_flat_map_pat_field(self, fp) } @@ -321,6 +387,10 @@ pub trait MutVisitor: Sized { fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) { walk_capture_by(self, capture_by) } + + fn visit_fn_ret_ty(&mut self, fn_ret_ty: &mut FnRetTy) { + walk_fn_ret_ty(self, fn_ret_ty) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -394,13 +464,10 @@ fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) { match args { AttrArgs::Empty => {} AttrArgs::Delimited(args) => visit_delim_args(vis, args), - AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => { + AttrArgs::Eq { eq_span, expr } => { vis.visit_expr(expr); vis.visit_span(eq_span); } - AttrArgs::Eq(_eq_span, AttrArgsEq::Hir(lit)) => { - unreachable!("in literal form when visiting mac args eq: {:?}", lit) - } } } @@ -416,16 +483,20 @@ pub fn visit_delim_span<T: MutVisitor>(vis: &mut T, DelimSpan { open, close }: & vis.visit_span(close); } -pub fn walk_flat_map_pat_field<T: MutVisitor>( - vis: &mut T, - mut fp: PatField, -) -> SmallVec<[PatField; 1]> { - let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp; +pub fn walk_pat_field<T: MutVisitor>(vis: &mut T, fp: &mut PatField) { + let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = fp; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_ident(ident); vis.visit_pat(pat); vis.visit_span(span); +} + +pub fn walk_flat_map_pat_field<T: MutVisitor>( + vis: &mut T, + mut fp: PatField, +) -> SmallVec<[PatField; 1]> { + vis.visit_pat_field(&mut fp); smallvec![fp] } @@ -446,14 +517,18 @@ fn walk_use_tree<T: MutVisitor>(vis: &mut T, use_tree: &mut UseTree) { vis.visit_span(span); } -pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> { - let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm; +pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) { + let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_pat(pat); visit_opt(guard, |guard| vis.visit_expr(guard)); visit_opt(body, |body| vis.visit_expr(body)); vis.visit_span(span); +} + +pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> { + vis.visit_arm(&mut arm); smallvec![arm] } @@ -496,11 +571,16 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) { vis.visit_fn_decl(decl); vis.visit_span(decl_span); } + TyKind::UnsafeBinder(binder) => { + let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut(); + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); + vis.visit_ty(inner_ty); + } TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)), TyKind::Paren(ty) => vis.visit_ty(ty), TyKind::Pat(ty, pat) => { vis.visit_ty(ty); - vis.visit_pat(pat); + vis.visit_ty_pat(pat); } TyKind::Path(qself, path) => { vis.visit_qself(qself); @@ -524,17 +604,28 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) { vis.visit_span(span); } +pub fn walk_ty_pat<T: MutVisitor>(vis: &mut T, ty: &mut P<TyPat>) { + let TyPat { id, kind, span, tokens } = ty.deref_mut(); + vis.visit_id(id); + match kind { + TyPatKind::Range(start, end, _include_end) => { + visit_opt(start, |c| vis.visit_anon_const(c)); + visit_opt(end, |c| vis.visit_anon_const(c)); + } + TyPatKind::Err(_) => {} + } + visit_lazy_tts(vis, tokens); + vis.visit_span(span); +} + fn walk_foreign_mod<T: MutVisitor>(vis: &mut T, foreign_mod: &mut ForeignMod) { - let ForeignMod { safety, abi: _, items } = foreign_mod; + let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; visit_safety(vis, safety); items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } -pub fn walk_flat_map_variant<T: MutVisitor>( - visitor: &mut T, - mut variant: Variant, -) -> SmallVec<[Variant; 1]> { - let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant; +pub fn walk_variant<T: MutVisitor>(visitor: &mut T, variant: &mut Variant) { + let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant; visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); @@ -542,6 +633,13 @@ pub fn walk_flat_map_variant<T: MutVisitor>( visitor.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr)); visitor.visit_span(span); +} + +pub fn walk_flat_map_variant<T: MutVisitor>( + vis: &mut T, + mut variant: Variant, +) -> SmallVec<[Variant; 1]> { + vis.visit_variant(&mut variant); smallvec![variant] } @@ -600,13 +698,14 @@ fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut An fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) { let ParenthesizedArgs { inputs, output, span, inputs_span } = args; visit_thin_vec(inputs, |input| vis.visit_ty(input)); - walk_fn_ret_ty(vis, output); + vis.visit_fn_ret_ty(output); vis.visit_span(span); vis.visit_span(inputs_span); } fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut P<Local>) { - let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut(); + let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut(); + visit_opt(super_, |sp| vis.visit_span(sp)); vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_pat(pat); @@ -672,13 +771,17 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) { vis.visit_span(span); } -pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> { - let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param; +pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) { + let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_pat(pat); vis.visit_ty(ty); vis.visit_span(span); +} + +pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> { + vis.visit_param(&mut param); smallvec![param] } @@ -715,14 +818,14 @@ fn visit_tt<T: MutVisitor>(vis: &mut T, tt: &mut TokenTree) { // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_tts<T: MutVisitor>(vis: &mut T, TokenStream(tts): &mut TokenStream) { if T::VISIT_TOKENS && !tts.is_empty() { - let tts = Lrc::make_mut(tts); + let tts = Arc::make_mut(tts); visit_vec(tts, |tree| visit_tt(vis, tree)); } } fn visit_attr_tts<T: MutVisitor>(vis: &mut T, AttrTokenStream(tts): &mut AttrTokenStream) { if T::VISIT_TOKENS && !tts.is_empty() { - let tts = Lrc::make_mut(tts); + let tts = Arc::make_mut(tts); visit_vec(tts, |tree| visit_attr_tt(vis, tree)); } } @@ -741,9 +844,9 @@ fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrToke visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut()); } -/// Applies ident visitor if it's an ident; applies other visits to interpolated nodes. -/// In practice the ident part is not actually used by specific visitors right now, -/// but there's a test below checking that it works. +/// Applies ident visitor if it's an ident. In practice this is not actually +/// used by specific visitors right now, but there's a test below checking that +/// it works. // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) { let Token { kind, span } = t; @@ -761,69 +864,11 @@ pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) { token::NtLifetime(ident, _is_raw) => { vis.visit_ident(ident); } - token::Interpolated(nt) => { - let nt = Lrc::make_mut(nt); - visit_nonterminal(vis, nt); - } _ => {} } vis.visit_span(span); } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -/// Applies the visitor to elements of interpolated nodes. -// -// N.B., this can occur only when applying a visitor to partially expanded -// code, where parsed pieces have gotten implanted ito *other* macro -// invocations. This is relevant for macro hygiene, but possibly not elsewhere. -// -// One problem here occurs because the types for flat_map_item, flat_map_stmt, -// etc., allow the visitor to return *multiple* items; this is a problem for the -// nodes here, because they insist on having exactly one piece. One solution -// would be to mangle the MutVisitor trait to include one-to-many and -// one-to-one versions of these entry points, but that would probably confuse a -// lot of people and help very few. Instead, I'm just going to put in dynamic -// checks. I think the performance impact of this will be pretty much -// nonexistent. The danger is that someone will apply a `MutVisitor` to a -// partially expanded node, and will be confused by the fact that their -// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt` -// nodes. Hopefully they'll wind up reading this comment, and doing something -// appropriate. -// -// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to -// contain multiple items, but decided against it when I looked at -// `parse_item_or_view_item` and tried to figure out what I would do with -// multiple items there.... -fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) { - match nt { - token::NtItem(item) => visit_clobber(item, |item| { - // This is probably okay, because the only visitors likely to - // peek inside interpolated nodes will be renamings/markings, - // which map single items to single items. - vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item") - }), - token::NtBlock(block) => vis.visit_block(block), - token::NtStmt(stmt) => visit_clobber(stmt, |stmt| { - // See reasoning above. - stmt.map(|stmt| { - vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item") - }) - }), - token::NtPat(pat) => vis.visit_pat(pat), - token::NtExpr(expr) => vis.visit_expr(expr), - token::NtTy(ty) => vis.visit_ty(ty), - token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(item) => { - let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); - vis.visit_path(path); - visit_attr_args(vis, args); - visit_lazy_tts(vis, tokens); - } - token::NtPath(path) => vis.visit_path(path), - token::NtVis(visib) => vis.visit_vis(visib), - } -} - // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_defaultness<T: MutVisitor>(vis: &mut T, defaultness: &mut Defaultness) { match defaultness { @@ -880,28 +925,58 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) { match kind { - FnKind::Fn(FnSig { header, decl, span }, generics, body) => { - // Identifier and visibility are visited as a part of the item. + FnKind::Fn( + _ctxt, + _vis, + Fn { + defaultness, + ident, + generics, + contract, + body, + sig: FnSig { header, decl, span }, + define_opaque, + }, + ) => { + // Visibility is visited as a part of the item. + visit_defaultness(vis, defaultness); + vis.visit_ident(ident); vis.visit_fn_header(header); vis.visit_generics(generics); vis.visit_fn_decl(decl); + if let Some(contract) = contract { + vis.visit_contract(contract); + } if let Some(body) = body { vis.visit_block(body); } vis.visit_span(span); + + walk_define_opaques(vis, define_opaque); } - FnKind::Closure(binder, decl, body) => { + FnKind::Closure(binder, coroutine_kind, decl, body) => { vis.visit_closure_binder(binder); + coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); vis.visit_fn_decl(decl); vis.visit_expr(body); } } } +fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut P<FnContract>) { + let FnContract { requires, ensures } = contract.deref_mut(); + if let Some(pred) = requires { + vis.visit_expr(pred); + } + if let Some(pred) = ensures { + vis.visit_expr(pred); + } +} + fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) { let FnDecl { inputs, output } = decl.deref_mut(); inputs.flat_map_in_place(|param| vis.flat_map_param(param)); - walk_fn_ret_ty(vis, output); + vis.visit_fn_ret_ty(output); } fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) { @@ -936,11 +1011,8 @@ fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCaptu } } -pub fn walk_flat_map_generic_param<T: MutVisitor>( - vis: &mut T, - mut param: GenericParam, -) -> SmallVec<[GenericParam; 1]> { - let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param; +pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) { + let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_ident(ident); @@ -958,6 +1030,13 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>( if let Some(colon_span) = colon_span { vis.visit_span(colon_span); } +} + +pub fn walk_flat_map_generic_param<T: MutVisitor>( + vis: &mut T, + mut param: GenericParam, +) -> SmallVec<[GenericParam; 1]> { + vis.visit_generic_param(&mut param); smallvec![param] } @@ -987,30 +1066,39 @@ fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWh fn walk_where_clause<T: MutVisitor>(vis: &mut T, wc: &mut WhereClause) { let WhereClause { has_where_token: _, predicates, span } = wc; - visit_thin_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); + predicates.flat_map_in_place(|predicate| vis.flat_map_where_predicate(predicate)); + vis.visit_span(span); +} + +pub fn walk_flat_map_where_predicate<T: MutVisitor>( + vis: &mut T, + mut pred: WherePredicate, +) -> SmallVec<[WherePredicate; 1]> { + let WherePredicate { attrs, kind, id, span, is_placeholder: _ } = &mut pred; + vis.visit_id(id); + visit_attrs(vis, attrs); + vis.visit_where_predicate_kind(kind); vis.visit_span(span); + smallvec![pred] } -fn walk_where_predicate<T: MutVisitor>(vis: &mut T, pred: &mut WherePredicate) { - match pred { - WherePredicate::BoundPredicate(bp) => { - let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; +pub fn walk_where_predicate_kind<T: MutVisitor>(vis: &mut T, kind: &mut WherePredicateKind) { + match kind { + WherePredicateKind::BoundPredicate(bp) => { + let WhereBoundPredicate { bound_generic_params, bounded_ty, bounds } = bp; bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_ty(bounded_ty); visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound)); - vis.visit_span(span); } - WherePredicate::RegionPredicate(rp) => { - let WhereRegionPredicate { span, lifetime, bounds } = rp; + WherePredicateKind::RegionPredicate(rp) => { + let WhereRegionPredicate { lifetime, bounds } = rp; vis.visit_lifetime(lifetime); visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound)); - vis.visit_span(span); } - WherePredicate::EqPredicate(ep) => { - let WhereEqPredicate { span, lhs_ty, rhs_ty } = ep; + WherePredicateKind::EqPredicate(ep) => { + let WhereEqPredicate { lhs_ty, rhs_ty } = ep; vis.visit_ty(lhs_ty); vis.visit_ty(rhs_ty); - vis.visit_span(span); } } } @@ -1034,36 +1122,63 @@ fn walk_trait_ref<T: MutVisitor>(vis: &mut T, TraitRef { path, ref_id }: &mut Tr } fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) { - let PolyTraitRef { bound_generic_params, modifiers: _, trait_ref, span } = p; + let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; + vis.visit_modifiers(modifiers); bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_trait_ref(trait_ref); vis.visit_span(span); } -pub fn walk_flat_map_field_def<T: MutVisitor>( - visitor: &mut T, - mut fd: FieldDef, -) -> SmallVec<[FieldDef; 1]> { - let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd; +fn walk_modifiers<V: MutVisitor>(vis: &mut V, m: &mut TraitBoundModifiers) { + let TraitBoundModifiers { constness, asyncness, polarity } = m; + match constness { + BoundConstness::Never => {} + BoundConstness::Always(span) | BoundConstness::Maybe(span) => vis.visit_span(span), + } + match asyncness { + BoundAsyncness::Normal => {} + BoundAsyncness::Async(span) => vis.visit_span(span), + } + match polarity { + BoundPolarity::Positive => {} + BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => vis.visit_span(span), + } +} + +pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) { + let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd; visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); + visit_safety(visitor, safety); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_ty(ty); + visit_opt(default, |default| visitor.visit_anon_const(default)); visitor.visit_span(span); - smallvec![fd] } -pub fn walk_flat_map_expr_field<T: MutVisitor>( +pub fn walk_flat_map_field_def<T: MutVisitor>( vis: &mut T, - mut f: ExprField, -) -> SmallVec<[ExprField; 1]> { - let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f; + mut fd: FieldDef, +) -> SmallVec<[FieldDef; 1]> { + vis.visit_field_def(&mut fd); + smallvec![fd] +} + +pub fn walk_expr_field<T: MutVisitor>(vis: &mut T, f: &mut ExprField) { + let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = f; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_ident(ident); vis.visit_expr(expr); vis.visit_span(span); +} + +pub fn walk_flat_map_expr_field<T: MutVisitor>( + vis: &mut T, + mut f: ExprField, +) -> SmallVec<[ExprField; 1]> { + vis.visit_expr_field(&mut f); smallvec![f] } @@ -1072,42 +1187,66 @@ fn walk_mt<T: MutVisitor>(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) { } pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) { - let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut(); + let Block { id, stmts, rules: _, span, tokens } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); visit_lazy_tts(vis, tokens); vis.visit_span(span); } -pub fn walk_item_kind( - kind: &mut impl WalkItemKind, +pub fn walk_item_kind<K: WalkItemKind>( + kind: &mut K, span: Span, id: NodeId, + visibility: &mut Visibility, + ctxt: K::Ctxt, vis: &mut impl MutVisitor, ) { - kind.walk(span, id, vis) + kind.walk(span, id, visibility, ctxt, vis) } impl WalkItemKind for ItemKind { - fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) { + type Ctxt = (); + fn walk( + &mut self, + span: Span, + id: NodeId, + visibility: &mut Visibility, + _ctxt: Self::Ctxt, + vis: &mut impl MutVisitor, + ) { match self { - ItemKind::ExternCrate(_orig_name) => {} + ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident), ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ident, + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { + vis.visit_ident(ident); vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); + walk_define_opaques(vis, define_opaque); } ItemKind::Const(item) => { - visit_const_item(item, vis); + walk_const_item(vis, item); } - ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(vis, defaultness); - vis.visit_fn(FnKind::Fn(sig, generics, body), span, id); + ItemKind::Fn(func) => { + vis.visit_fn(FnKind::Fn(FnCtxt::Free, visibility, &mut *func), span, id); } - ItemKind::Mod(safety, mod_kind) => { + ItemKind::Mod(safety, ident, mod_kind) => { visit_safety(vis, safety); + vis.visit_ident(ident); match mod_kind { - ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => { + ModKind::Loaded( + items, + _inline, + ModSpans { inner_span, inject_use_span }, + _, + ) => { items.flat_map_in_place(|item| vis.flat_map_item(item)); vis.visit_span(inner_span); vis.visit_span(inject_use_span); @@ -1117,18 +1256,29 @@ impl WalkItemKind for ItemKind { } ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), - ItemKind::TyAlias(box TyAlias { defaultness, generics, where_clauses, bounds, ty }) => { + ItemKind::TyAlias(box TyAlias { + defaultness, + ident, + generics, + where_clauses, + bounds, + ty, + }) => { visit_defaultness(vis, defaultness); + vis.visit_ident(ident); vis.visit_generics(generics); visit_bounds(vis, bounds, BoundKind::Bound); visit_opt(ty, |ty| vis.visit_ty(ty)); walk_ty_alias_where_clauses(vis, where_clauses); } - ItemKind::Enum(EnumDef { variants }, generics) => { + ItemKind::Enum(ident, EnumDef { variants }, generics) => { + vis.visit_ident(ident); vis.visit_generics(generics); variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); } - ItemKind::Struct(variant_data, generics) | ItemKind::Union(variant_data, generics) => { + ItemKind::Struct(ident, variant_data, generics) + | ItemKind::Union(ident, variant_data, generics) => { + vis.visit_ident(ident); vis.visit_generics(generics); vis.visit_variant_data(variant_data); } @@ -1149,24 +1299,32 @@ impl WalkItemKind for ItemKind { visit_polarity(vis, polarity); visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref)); vis.visit_ty(self_ty); - items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Impl)); + items.flat_map_in_place(|item| { + vis.flat_map_assoc_item(item, AssocCtxt::Impl { of_trait: of_trait.is_some() }) + }); } - ItemKind::Trait(box Trait { safety, is_auto: _, generics, bounds, items }) => { + ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { visit_safety(vis, safety); + vis.visit_ident(ident); vis.visit_generics(generics); visit_bounds(vis, bounds, BoundKind::Bound); items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Trait)); } - ItemKind::TraitAlias(generics, bounds) => { + ItemKind::TraitAlias(ident, generics, bounds) => { + vis.visit_ident(ident); vis.visit_generics(generics); visit_bounds(vis, bounds, BoundKind::Bound); } ItemKind::MacCall(m) => vis.visit_mac_call(m), - ItemKind::MacroDef(def) => vis.visit_macro_def(def), + ItemKind::MacroDef(ident, def) => { + vis.visit_ident(ident); + vis.visit_macro_def(def) + } ItemKind::Delegation(box Delegation { id, qself, path, + ident, rename, body, from_glob: _, @@ -1174,6 +1332,7 @@ impl WalkItemKind for ItemKind { vis.visit_id(id); vis.visit_qself(qself); vis.visit_path(path); + vis.visit_ident(ident); if let Some(rename) = rename { vis.visit_ident(rename); } @@ -1201,23 +1360,32 @@ impl WalkItemKind for ItemKind { } impl WalkItemKind for AssocItemKind { - fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) { + type Ctxt = AssocCtxt; + fn walk( + &mut self, + span: Span, + id: NodeId, + visibility: &mut Visibility, + ctxt: Self::Ctxt, + visitor: &mut impl MutVisitor, + ) { match self { AssocItemKind::Const(item) => { - visit_const_item(item, visitor); + walk_const_item(visitor, item); } - AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(visitor, defaultness); - visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id); + AssocItemKind::Fn(func) => { + visitor.visit_fn(FnKind::Fn(FnCtxt::Assoc(ctxt), visibility, &mut *func), span, id); } AssocItemKind::Type(box TyAlias { defaultness, + ident, generics, where_clauses, bounds, ty, }) => { visit_defaultness(visitor, defaultness); + visitor.visit_ident(ident); visitor.visit_generics(generics); visit_bounds(visitor, bounds, BoundKind::Bound); visit_opt(ty, |ty| visitor.visit_ty(ty)); @@ -1228,6 +1396,7 @@ impl WalkItemKind for AssocItemKind { id, qself, path, + ident, rename, body, from_glob: _, @@ -1235,6 +1404,7 @@ impl WalkItemKind for AssocItemKind { visitor.visit_id(id); visitor.visit_qself(qself); visitor.visit_path(path); + visitor.visit_ident(ident); if let Some(rename) = rename { visitor.visit_ident(rename); } @@ -1261,14 +1431,14 @@ impl WalkItemKind for AssocItemKind { } } -fn visit_const_item<T: MutVisitor>( - ConstItem { defaultness, generics, ty, expr }: &mut ConstItem, - visitor: &mut T, -) { - visit_defaultness(visitor, defaultness); - visitor.visit_generics(generics); - visitor.visit_ty(ty); - visit_opt(expr, |expr| visitor.visit_expr(expr)); +fn walk_const_item<T: MutVisitor>(vis: &mut T, item: &mut ConstItem) { + let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; + visit_defaultness(vis, defaultness); + vis.visit_ident(ident); + vis.visit_generics(generics); + vis.visit_ty(ty); + visit_opt(expr, |expr| vis.visit_expr(expr)); + walk_define_opaques(vis, define_opaque); } fn walk_fn_header<T: MutVisitor>(vis: &mut T, header: &mut FnHeader) { @@ -1288,41 +1458,87 @@ pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) { vis.visit_span(inject_use_span); } -/// Mutates one item, returning the item again. -pub fn walk_flat_map_item<K: WalkItemKind>( +pub fn walk_item(visitor: &mut impl MutVisitor, item: &mut P<Item<impl WalkItemKind<Ctxt = ()>>>) { + walk_item_ctxt(visitor, item, ()) +} + +pub fn walk_assoc_item(visitor: &mut impl MutVisitor, item: &mut P<AssocItem>, ctxt: AssocCtxt) { + walk_item_ctxt(visitor, item, ctxt) +} + +fn walk_item_ctxt<K: WalkItemKind>( visitor: &mut impl MutVisitor, - mut item: P<Item<K>>, -) -> SmallVec<[P<Item<K>>; 1]> { - let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut(); + item: &mut P<Item<K>>, + ctxt: K::Ctxt, +) { + let Item { attrs, id, kind, vis, span, tokens } = item.deref_mut(); visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); - visitor.visit_ident(ident); - kind.walk(*span, *id, visitor); + kind.walk(*span, *id, vis, ctxt, visitor); visit_lazy_tts(visitor, tokens); visitor.visit_span(span); +} + +pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P<Item>) -> SmallVec<[P<Item>; 1]> { + vis.visit_item(&mut item); + smallvec![item] +} + +pub fn walk_flat_map_foreign_item( + vis: &mut impl MutVisitor, + mut item: P<ForeignItem>, +) -> SmallVec<[P<ForeignItem>; 1]> { + vis.visit_foreign_item(&mut item); + smallvec![item] +} + +pub fn walk_flat_map_assoc_item( + vis: &mut impl MutVisitor, + mut item: P<AssocItem>, + ctxt: AssocCtxt, +) -> SmallVec<[P<AssocItem>; 1]> { + vis.visit_assoc_item(&mut item, ctxt); smallvec![item] } impl WalkItemKind for ForeignItemKind { - fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) { + type Ctxt = (); + fn walk( + &mut self, + span: Span, + id: NodeId, + visibility: &mut Visibility, + _ctxt: Self::Ctxt, + visitor: &mut impl MutVisitor, + ) { match self { - ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { + ForeignItemKind::Static(box StaticItem { + ident, + ty, + mutability: _, + expr, + safety: _, + define_opaque, + }) => { + visitor.visit_ident(ident); visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); + walk_define_opaques(visitor, define_opaque); } - ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(visitor, defaultness); - visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id); + ForeignItemKind::Fn(func) => { + visitor.visit_fn(FnKind::Fn(FnCtxt::Foreign, visibility, &mut *func), span, id); } ForeignItemKind::TyAlias(box TyAlias { defaultness, + ident, generics, where_clauses, bounds, ty, }) => { visit_defaultness(visitor, defaultness); + visitor.visit_ident(ident); visitor.visit_generics(generics); visit_bounds(visitor, bounds, BoundKind::Bound); visit_opt(ty, |ty| visitor.visit_ty(ty)); @@ -1338,12 +1554,12 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) { vis.visit_id(id); match kind { PatKind::Err(_guar) => {} - PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); } - PatKind::Lit(e) => vis.visit_expr(e), + PatKind::Expr(e) => vis.visit_expr(e), PatKind::TupleStruct(qself, path, elems) => { vis.visit_qself(qself); vis.visit_path(path); @@ -1366,6 +1582,10 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) { visit_opt(e2, |e| vis.visit_expr(e)); vis.visit_span(span); } + PatKind::Guard(p, e) => { + vis.visit_pat(p); + vis.visit_expr(e); + } PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { visit_thin_vec(elems, |elem| vis.visit_pat(elem)) } @@ -1423,7 +1643,7 @@ fn walk_inline_asm_sym<T: MutVisitor>( fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) { // FIXME: visit the template exhaustively. - let FormatArgs { span, template: _, arguments } = fmt; + let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt; for FormatArgument { kind, expr } in arguments.all_args_mut() { match kind { FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { @@ -1466,9 +1686,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token visit_thin_exprs(vis, call_args); vis.visit_span(span); } - ExprKind::Binary(_binop, lhs, rhs) => { + ExprKind::Binary(binop, lhs, rhs) => { vis.visit_expr(lhs); vis.visit_expr(rhs); + vis.visit_span(&mut binop.span); } ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs), ExprKind::Cast(expr, ty) => { @@ -1522,9 +1743,8 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token fn_arg_span, }) => { visit_constness(vis, constness); - coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); vis.visit_capture_by(capture_clause); - vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id); + vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id); vis.visit_span(fn_decl_span); vis.visit_span(fn_arg_span); } @@ -1540,6 +1760,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_expr(expr); vis.visit_span(await_kw_span); } + ExprKind::Use(expr, use_kw_span) => { + vis.visit_expr(expr); + vis.visit_span(use_kw_span); + } ExprKind::Assign(el, er, span) => { vis.visit_expr(el); vis.visit_expr(er); @@ -1604,13 +1828,22 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token ExprKind::Paren(expr) => { vis.visit_expr(expr); } - ExprKind::Yield(expr) => { - visit_opt(expr, |expr| vis.visit_expr(expr)); + ExprKind::Yield(kind) => { + let expr = kind.expr_mut(); + if let Some(expr) = expr { + vis.visit_expr(expr); + } } ExprKind::Try(expr) => vis.visit_expr(expr), ExprKind::TryBlock(body) => vis.visit_block(body), ExprKind::Lit(_token) => {} ExprKind::IncludedBytes(_bytes) => {} + ExprKind::UnsafeBinderCast(_kind, expr, ty) => { + vis.visit_expr(expr); + if let Some(ty) = ty { + vis.visit_ty(ty); + } + } ExprKind::Err(_guar) => {} ExprKind::Dummy => {} } @@ -1627,20 +1860,21 @@ pub fn noop_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Optio pub fn walk_flat_map_stmt<T: MutVisitor>( vis: &mut T, - Stmt { kind, mut span, mut id }: Stmt, + Stmt { kind, span, mut id }: Stmt, ) -> SmallVec<[Stmt; 1]> { vis.visit_id(&mut id); - let stmts: SmallVec<_> = walk_flat_map_stmt_kind(vis, kind) + let mut stmts: SmallVec<[Stmt; 1]> = walk_flat_map_stmt_kind(vis, kind) .into_iter() .map(|kind| Stmt { id, kind, span }) .collect(); - if stmts.len() > 1 { - panic!( + match &mut stmts[..] { + [] => {} + [stmt] => vis.visit_span(&mut stmt.span), + _ => panic!( "cloning statement `NodeId`s is prohibited by default, \ the visitor should implement custom statement visiting" - ); + ), } - vis.visit_span(&mut span); stmts } @@ -1683,6 +1917,21 @@ fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) { CaptureBy::Value { move_kw } => { vis.visit_span(move_kw); } + CaptureBy::Use { use_kw } => { + vis.visit_span(use_kw); + } + } +} + +fn walk_define_opaques<T: MutVisitor>( + vis: &mut T, + define_opaque: &mut Option<ThinVec<(NodeId, Path)>>, +) { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + vis.visit_id(id); + vis.visit_path(path) + } } } @@ -1717,8 +1966,7 @@ impl DummyAstNode for Item { span: Default::default(), tokens: Default::default(), }, - ident: Ident::empty(), - kind: ItemKind::ExternCrate(None), + kind: ItemKind::ExternCrate(None, Ident::dummy()), tokens: Default::default(), } } @@ -1785,8 +2033,13 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo #[derive(Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option<P<Block>>), + Fn(FnCtxt, &'a mut Visibility, &'a mut Fn), /// E.g., `|x, y| body`. - Closure(&'a mut ClosureBinder, &'a mut P<FnDecl>, &'a mut P<Expr>), + Closure( + &'a mut ClosureBinder, + &'a mut Option<CoroutineKind>, + &'a mut P<FnDecl>, + &'a mut P<Expr>, + ), } diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 97c714df8fd2f..dd923305cdfd9 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -158,9 +158,9 @@ impl<T> From<Vec<T>> for P<[T]> { } } -impl<T> Into<Vec<T>> for P<[T]> { - fn into(self) -> Vec<T> { - self.into_vec() +impl<T> From<P<[T]>> for Vec<T> { + fn from(val: P<[T]>) -> Self { + val.into_vec() } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 1d6abbef06c95..54781e8235e2f 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1,24 +1,18 @@ use std::borrow::Cow; use std::fmt; -pub use BinOpToken::*; pub use LitKind::*; -pub use Nonterminal::*; pub use NtExprKind::*; pub use NtPatKind::*; pub use TokenKind::*; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lrc; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym}; #[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint. #[allow(hidden_glob_reexports)] -use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::symbol::{kw, sym}; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; +use rustc_span::{Ident, Symbol}; use crate::ast; -use crate::ptr::P; use crate::util::case::Case; #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -27,26 +21,99 @@ pub enum CommentKind { Block, } -#[derive(Clone, PartialEq, Encodable, Decodable, Hash, Debug, Copy)] -#[derive(HashStable_Generic)] -pub enum BinOpToken { - Plus, - Minus, - Star, - Slash, - Percent, - Caret, - And, - Or, - Shl, - Shr, +// This type must not implement `Hash` due to the unusual `PartialEq` impl below. +#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)] +pub enum InvisibleOrigin { + // From the expansion of a metavariable in a declarative macro. + MetaVar(MetaVarKind), + + // Converted from `proc_macro::Delimiter` in + // `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro. + ProcMacro, +} + +impl InvisibleOrigin { + // Should the parser skip these invisible delimiters? Ideally this function + // will eventually disappear and no invisible delimiters will be skipped. + #[inline] + pub fn skip(&self) -> bool { + match self { + InvisibleOrigin::MetaVar(_) => false, + InvisibleOrigin::ProcMacro => true, + } + } +} + +impl PartialEq for InvisibleOrigin { + #[inline] + fn eq(&self, _other: &InvisibleOrigin) -> bool { + // When we had AST-based nonterminals we couldn't compare them, and the + // old `Nonterminal` type had an `eq` that always returned false, + // resulting in this restriction: + // https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment + // This `eq` emulates that behaviour. We could consider lifting this + // restriction now but there are still cases involving invisible + // delimiters that make it harder than it first appears. + false + } +} + +/// Annoyingly similar to `NonterminalKind`, but the slight differences are important. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] +pub enum MetaVarKind { + Item, + Block, + Stmt, + Pat(NtPatKind), + Expr { + kind: NtExprKind, + // This field is needed for `Token::can_begin_literal_maybe_minus`. + can_begin_literal_maybe_minus: bool, + // This field is needed for `Token::can_begin_string_literal`. + can_begin_string_literal: bool, + }, + Ty { + is_path: bool, + }, + Ident, + Lifetime, + Literal, + Meta { + /// Will `AttrItem::meta` succeed on this, if reparsed? + has_meta_form: bool, + }, + Path, + Vis, + TT, +} + +impl fmt::Display for MetaVarKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let sym = match self { + MetaVarKind::Item => sym::item, + MetaVarKind::Block => sym::block, + MetaVarKind::Stmt => sym::stmt, + MetaVarKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat, + MetaVarKind::Pat(PatParam { inferred: false }) => sym::pat_param, + MetaVarKind::Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr, + MetaVarKind::Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021, + MetaVarKind::Ty { .. } => sym::ty, + MetaVarKind::Ident => sym::ident, + MetaVarKind::Lifetime => sym::lifetime, + MetaVarKind::Literal => sym::literal, + MetaVarKind::Meta { .. } => sym::meta, + MetaVarKind::Path => sym::path, + MetaVarKind::Vis => sym::vis, + MetaVarKind::TT => sym::tt, + }; + write!(f, "{sym}") + } } /// Describes how a sequence of token trees is delimited. /// Cannot use `proc_macro::Delimiter` directly because this /// structure should implement some additional traits. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[derive(Encodable, Decodable, Hash, HashStable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] pub enum Delimiter { /// `( ... )` Parenthesis, @@ -59,7 +126,49 @@ pub enum Delimiter { /// "macro variable" `$var`. It is important to preserve operator priorities in cases like /// `$var * 3` where `$var` is `1 + 2`. /// Invisible delimiters might not survive roundtrip of a token stream through a string. - Invisible, + Invisible(InvisibleOrigin), +} + +impl Delimiter { + // Should the parser skip these delimiters? Only happens for certain kinds + // of invisible delimiters. Ideally this function will eventually disappear + // and no invisible delimiters will be skipped. + #[inline] + pub fn skip(&self) -> bool { + match self { + Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false, + Delimiter::Invisible(origin) => origin.skip(), + } + } + + // This exists because `InvisibleOrigin`s should be compared. It is only used for assertions. + pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool { + match (self, other) { + (Delimiter::Parenthesis, Delimiter::Parenthesis) => true, + (Delimiter::Brace, Delimiter::Brace) => true, + (Delimiter::Bracket, Delimiter::Bracket) => true, + (Delimiter::Invisible(_), Delimiter::Invisible(_)) => true, + _ => false, + } + } + + pub fn as_open_token_kind(&self) -> TokenKind { + match *self { + Delimiter::Parenthesis => OpenParen, + Delimiter::Brace => OpenBrace, + Delimiter::Bracket => OpenBracket, + Delimiter::Invisible(origin) => OpenInvisible(origin), + } + } + + pub fn as_close_token_kind(&self) -> TokenKind { + match *self { + Delimiter::Parenthesis => CloseParen, + Delimiter::Brace => CloseBrace, + Delimiter::Bracket => CloseBracket, + Delimiter::Invisible(origin) => CloseInvisible(origin), + } + } } // Note that the suffix is *not* considered when deciding the `LitKind` in this @@ -108,16 +217,17 @@ impl Lit { } } - /// Keep this in sync with `Token::can_begin_literal_maybe_minus` excluding unary negation. + /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and + /// `Parser::eat_token_lit` (excluding unary negation). pub fn from_token(token: &Token) -> Option<Lit> { match token.uninterpolate().kind { Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), Literal(token_lit) => Some(token_lit), - Interpolated(ref nt) - if let NtExpr(expr) | NtLiteral(expr) = &**nt - && let ast::ExprKind::Lit(token_lit) = expr.kind => - { - Some(token_lit) + OpenInvisible(InvisibleOrigin::MetaVar( + MetaVarKind::Literal | MetaVarKind::Expr { .. }, + )) => { + // Unreachable with the current test suite. + panic!("from_token metavar"); } _ => None, } @@ -246,9 +356,7 @@ impl From<IdentIsRaw> for bool { } } -// SAFETY: due to the `Clone` impl below, all fields of all variants other than -// `Interpolated` must impl `Copy`. -#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ /// `=` @@ -270,11 +378,49 @@ pub enum TokenKind { /// `||` OrOr, /// `!` - Not, + Bang, /// `~` Tilde, - BinOp(BinOpToken), - BinOpEq(BinOpToken), + // `+` + Plus, + // `-` + Minus, + // `*` + Star, + // `/` + Slash, + // `%` + Percent, + // `^` + Caret, + // `&` + And, + // `|` + Or, + // `<<` + Shl, + // `>>` + Shr, + // `+=` + PlusEq, + // `-=` + MinusEq, + // `*=` + StarEq, + // `/=` + SlashEq, + // `%=` + PercentEq, + // `^=` + CaretEq, + // `&=` + AndEq, + // `|=` + OrEq, + // `<<=` + ShlEq, + // `>>=` + ShrEq, /* Structural symbols */ /// `@` @@ -309,18 +455,31 @@ pub enum TokenKind { Question, /// Used by proc macros for representing lifetimes, not generated by lexer right now. SingleQuote, - /// An opening delimiter (e.g., `{`). - OpenDelim(Delimiter), - /// A closing delimiter (e.g., `}`). - CloseDelim(Delimiter), + /// `(` + OpenParen, + /// `)` + CloseParen, + /// `{` + OpenBrace, + /// `}` + CloseBrace, + /// `[` + OpenBracket, + /// `]` + CloseBracket, + /// Invisible opening delimiter, produced by a macro. + OpenInvisible(InvisibleOrigin), + /// Invisible closing delimiter, produced by a macro. + CloseInvisible(InvisibleOrigin), /* Literals */ Literal(Lit), /// Identifier token. /// Do not forget about `NtIdent` when you want to match on identifiers. - /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to - /// treat regular and interpolated identifiers in the same way. + /// It's recommended to use `Token::{ident,uninterpolate}` and + /// `Parser::token_uninterpolated_span` to treat regular and interpolated + /// identifiers in the same way. Ident(Symbol, IdentIsRaw), /// This identifier (and its span) is the identifier passed to the /// declarative macro. The span in the surrounding `Token` is the span of @@ -329,29 +488,15 @@ pub enum TokenKind { /// Lifetime identifier token. /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. - /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to - /// treat regular and interpolated lifetime identifiers in the same way. + /// It's recommended to use `Token::{ident,uninterpolate}` and + /// `Parser::token_uninterpolated_span` to treat regular and interpolated + /// identifiers in the same way. Lifetime(Symbol, IdentIsRaw), /// This identifier (and its span) is the lifetime passed to the /// declarative macro. The span in the surrounding `Token` is the span of /// the `lifetime` metavariable in the macro's RHS. NtLifetime(Ident, IdentIsRaw), - /// An embedded AST node, as produced by a macro. This only exists for - /// historical reasons. We'd like to get rid of it, for multiple reasons. - /// - It's conceptually very strange. Saying a token can contain an AST - /// node is like saying, in natural language, that a word can contain a - /// sentence. - /// - It requires special handling in a bunch of places in the parser. - /// - It prevents `Token` from implementing `Copy`. - /// It adds complexity and likely slows things down. Please don't add new - /// occurrences of this token kind! - /// - /// The span in the surrounding `Token` is that of the metavariable in the - /// macro's RHS. The span within the Nonterminal is that of the fragment - /// passed to the macro at the call site. - Interpolated(Lrc<Nonterminal>), - /// A doc comment token. /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc) /// similarly to symbols in string literal tokens. @@ -361,20 +506,7 @@ pub enum TokenKind { Eof, } -impl Clone for TokenKind { - fn clone(&self) -> Self { - // `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So - // for all other variants, this implementation of `clone` is just like - // a copy. This is faster than the `derive(Clone)` version which has a - // separate path for every variant. - match self { - Interpolated(nt) => Interpolated(nt.clone()), - _ => unsafe { std::ptr::read(self) }, - } - } -} - -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, pub span: Span, @@ -394,31 +526,31 @@ impl TokenKind { Some(match (self, n) { (Le, 1) => (Lt, Eq), (EqEq, 1) => (Eq, Eq), - (Ne, 1) => (Not, Eq), + (Ne, 1) => (Bang, Eq), (Ge, 1) => (Gt, Eq), - (AndAnd, 1) => (BinOp(And), BinOp(And)), - (OrOr, 1) => (BinOp(Or), BinOp(Or)), - (BinOp(Shl), 1) => (Lt, Lt), - (BinOp(Shr), 1) => (Gt, Gt), - (BinOpEq(Plus), 1) => (BinOp(Plus), Eq), - (BinOpEq(Minus), 1) => (BinOp(Minus), Eq), - (BinOpEq(Star), 1) => (BinOp(Star), Eq), - (BinOpEq(Slash), 1) => (BinOp(Slash), Eq), - (BinOpEq(Percent), 1) => (BinOp(Percent), Eq), - (BinOpEq(Caret), 1) => (BinOp(Caret), Eq), - (BinOpEq(And), 1) => (BinOp(And), Eq), - (BinOpEq(Or), 1) => (BinOp(Or), Eq), - (BinOpEq(Shl), 1) => (Lt, Le), // `<` + `<=` - (BinOpEq(Shl), 2) => (BinOp(Shl), Eq), // `<<` + `=` - (BinOpEq(Shr), 1) => (Gt, Ge), // `>` + `>=` - (BinOpEq(Shr), 2) => (BinOp(Shr), Eq), // `>>` + `=` + (AndAnd, 1) => (And, And), + (OrOr, 1) => (Or, Or), + (Shl, 1) => (Lt, Lt), + (Shr, 1) => (Gt, Gt), + (PlusEq, 1) => (Plus, Eq), + (MinusEq, 1) => (Minus, Eq), + (StarEq, 1) => (Star, Eq), + (SlashEq, 1) => (Slash, Eq), + (PercentEq, 1) => (Percent, Eq), + (CaretEq, 1) => (Caret, Eq), + (AndEq, 1) => (And, Eq), + (OrEq, 1) => (Or, Eq), + (ShlEq, 1) => (Lt, Le), // `<` + `<=` + (ShlEq, 2) => (Shl, Eq), // `<<` + `=` + (ShrEq, 1) => (Gt, Ge), // `>` + `>=` + (ShrEq, 2) => (Shr, Eq), // `>>` + `=` (DotDot, 1) => (Dot, Dot), (DotDotDot, 1) => (Dot, DotDot), // `.` + `..` (DotDotDot, 2) => (DotDot, Dot), // `..` + `.` (DotDotEq, 2) => (DotDot, Eq), (PathSep, 1) => (Colon, Colon), - (RArrow, 1) => (BinOp(Minus), Gt), - (LArrow, 1) => (Lt, BinOp(Minus)), + (RArrow, 1) => (Minus, Gt), + (LArrow, 1) => (Lt, Minus), (FatArrow, 1) => (Eq, Gt), _ => return None, }) @@ -426,18 +558,49 @@ impl TokenKind { /// Returns tokens that are likely to be typed accidentally instead of the current token. /// Enables better error recovery when the wrong token is found. - pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> { + pub fn similar_tokens(&self) -> &[TokenKind] { + match self { + Comma => &[Dot, Lt, Semi], + Semi => &[Colon, Comma], + Colon => &[Semi], + FatArrow => &[Eq, RArrow, Ge, Gt], + _ => &[], + } + } + + pub fn should_end_const_arg(&self) -> bool { + matches!(self, Gt | Ge | Shr | ShrEq) + } + + pub fn is_delim(&self) -> bool { + self.open_delim().is_some() || self.close_delim().is_some() + } + + pub fn open_delim(&self) -> Option<Delimiter> { match *self { - Comma => Some(vec![Dot, Lt, Semi]), - Semi => Some(vec![Colon, Comma]), - Colon => Some(vec![Semi]), - FatArrow => Some(vec![Eq, RArrow, Ge, Gt]), + OpenParen => Some(Delimiter::Parenthesis), + OpenBrace => Some(Delimiter::Brace), + OpenBracket => Some(Delimiter::Bracket), + OpenInvisible(origin) => Some(Delimiter::Invisible(origin)), _ => None, } } - pub fn should_end_const_arg(&self) -> bool { - matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr)) + pub fn close_delim(&self) -> Option<Delimiter> { + match *self { + CloseParen => Some(Delimiter::Parenthesis), + CloseBrace => Some(Delimiter::Brace), + CloseBracket => Some(Delimiter::Bracket), + CloseInvisible(origin) => Some(Delimiter::Invisible(origin)), + _ => None, + } + } + + pub fn is_close_delim_or_eof(&self) -> bool { + match self { + CloseParen | CloseBrace | CloseBracket | CloseInvisible(_) | Eof => true, + _ => false, + } } } @@ -456,39 +619,26 @@ impl Token { Token::new(Ident(ident.name, ident.is_raw_guess().into()), ident.span) } - /// For interpolated tokens, returns a span of the fragment to which the interpolated - /// token refers. For all other tokens this is just a regular span. - /// It is particularly important to use this for identifiers and lifetimes - /// for which spans affect name resolution and edition checks. - /// Note that keywords are also identifiers, so they should use this - /// if they keep spans or perform edition checks. - pub fn uninterpolated_span(&self) -> Span { - match self.kind { - NtIdent(ident, _) | NtLifetime(ident, _) => ident.span, - Interpolated(ref nt) => nt.use_span(), - _ => self.span, - } - } - pub fn is_range_separator(&self) -> bool { [DotDot, DotDotDot, DotDotEq].contains(&self.kind) } pub fn is_punct(&self) -> bool { match self.kind { - Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_) - | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon - | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => { - true - } - - OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false, + Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Bang | Tilde | Plus | Minus + | Star | Slash | Percent | Caret | And | Or | Shl | Shr | PlusEq | MinusEq | StarEq + | SlashEq | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | Dot | DotDot + | DotDotDot | DotDotEq | Comma | Semi | Colon | PathSep | RArrow | LArrow + | FatArrow | Pound | Dollar | Question | SingleQuote => true, + + OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket + | OpenInvisible(_) | CloseInvisible(_) | Literal(..) | DocComment(..) | Ident(..) + | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false, } } pub fn is_like_plus(&self) -> bool { - matches!(self.kind, BinOp(Plus) | BinOpEq(Plus)) + matches!(self.kind, Plus | PlusEq) } /// Returns `true` if the token can appear at the start of an expression. @@ -499,27 +649,28 @@ impl Token { match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_expr(name, self.span, is_raw), // value name or keyword - OpenDelim(..) | // tuple, array or block + OpenParen | // tuple + OpenBrace | // block + OpenBracket | // array Literal(..) | // literal - Not | // operator not - BinOp(Minus) | // unary minus - BinOp(Star) | // dereference - BinOp(Or) | OrOr | // closure - BinOp(And) | // reference + Bang | // operator not + Minus | // unary minus + Star | // dereference + Or | OrOr | // closure + And | // reference AndAnd | // double reference // DotDotDot is no longer supported, but we need some way to display the error DotDot | DotDotDot | DotDotEq | // range notation - Lt | BinOp(Shl) | // associated path - PathSep | // global path + Lt | Shl | // associated path + PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => - matches!(&**nt, - NtBlock(..) | - NtExpr(..) | - NtLiteral(..) | - NtPath(..) - ), + OpenInvisible(InvisibleOrigin::MetaVar( + MetaVarKind::Block | + MetaVarKind::Expr { .. } | + MetaVarKind::Literal | + MetaVarKind::Path + )) => true, _ => false, } } @@ -531,28 +682,26 @@ impl Token { match &self.uninterpolate().kind { // box, ref, mut, and other identifiers (can stricten) Ident(..) | NtIdent(..) | - OpenDelim(Delimiter::Parenthesis) | // tuple pattern - OpenDelim(Delimiter::Bracket) | // slice pattern - BinOp(And) | // reference - BinOp(Minus) | // negative literal - AndAnd | // double reference - Literal(_) | // literal - DotDot | // range pattern (future compat) - DotDotDot | // range pattern (future compat) - PathSep | // path - Lt | // path (UFCS constant) - BinOp(Shl) => true, // path (double UFCS) - // leading vert `|` or-pattern - BinOp(Or) => matches!(pat_kind, PatWithOr), - Interpolated(nt) => - matches!(&**nt, - | NtExpr(..) - | NtLiteral(..) - | NtMeta(..) - | NtPat(..) - | NtPath(..) - | NtTy(..) - ), + OpenParen | // tuple pattern + OpenBracket | // slice pattern + And | // reference + Minus | // negative literal + AndAnd | // double reference + Literal(_) | // literal + DotDot | // range pattern (future compat) + DotDotDot | // range pattern (future compat) + PathSep | // path + Lt | // path (UFCS constant) + Shl => true, // path (double UFCS) + Or => matches!(pat_kind, PatWithOr), // leading vert `|` or-pattern + OpenInvisible(InvisibleOrigin::MetaVar( + MetaVarKind::Expr { .. } | + MetaVarKind::Literal | + MetaVarKind::Meta { .. } | + MetaVarKind::Pat(_) | + MetaVarKind::Path | + MetaVarKind::Ty { .. } + )) => true, _ => false, } } @@ -560,19 +709,22 @@ impl Token { /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { match self.uninterpolate().kind { - Ident(name, is_raw) => + Ident(name, is_raw) => ident_can_begin_type(name, self.span, is_raw), // type name or keyword - OpenDelim(Delimiter::Parenthesis) | // tuple - OpenDelim(Delimiter::Bracket) | // array - Not | // never - BinOp(Star) | // raw pointer - BinOp(And) | // reference - AndAnd | // double reference - Question | // maybe bound in trait object - Lifetime(..) | // lifetime bound in trait object - Lt | BinOp(Shl) | // associated path - PathSep => true, // global path - Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)), + OpenParen | // tuple + OpenBracket | // array + Bang | // never + Star | // raw pointer + And | // reference + AndAnd | // double reference + Question | // maybe bound in trait object + Lifetime(..) | // lifetime bound in trait object + Lt | Shl | // associated path + PathSep => true, // global path + OpenInvisible(InvisibleOrigin::MetaVar( + MetaVarKind::Ty { .. } | + MetaVarKind::Path + )) => true, // For anonymous structs or unions, which only appear in specific positions // (type of struct fields or union fields), we don't consider them as regular types _ => false, @@ -582,9 +734,11 @@ impl Token { /// Returns `true` if the token can appear at the start of a const param. pub fn can_begin_const_arg(&self) -> bool { match self.kind { - OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true, + OpenBrace | Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), + OpenInvisible(InvisibleOrigin::MetaVar( + MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal, + )) => true, _ => false, } } @@ -625,20 +779,17 @@ impl Token { /// /// In other words, would this token be a valid start of `parse_literal_maybe_minus`? /// - /// Keep this in sync with and `Lit::from_token`, excluding unary negation. + /// Keep this in sync with `Lit::from_token` and `Parser::eat_token_lit` + /// (excluding unary negation). pub fn can_begin_literal_maybe_minus(&self) -> bool { match self.uninterpolate().kind { - Literal(..) | BinOp(Minus) => true, + Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => match &**nt { - NtLiteral(_) => true, - NtExpr(e) => match &e.kind { - ast::ExprKind::Lit(_) => true, - ast::ExprKind::Unary(ast::UnOp::Neg, e) => { - matches!(&e.kind, ast::ExprKind::Lit(_)) - } - _ => false, - }, + OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) => match mv_kind { + MetaVarKind::Literal => true, + MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => { + can_begin_literal_maybe_minus + } _ => false, }, _ => false, @@ -648,12 +799,9 @@ impl Token { pub fn can_begin_string_literal(&self) -> bool { match self.uninterpolate().kind { Literal(..) => true, - Interpolated(ref nt) => match &**nt { - NtLiteral(_) => true, - NtExpr(e) => match &e.kind { - ast::ExprKind::Lit(_) => true, - _ => false, - }, + OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) => match mv_kind { + MetaVarKind::Literal => true, + MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal, _ => false, }, _ => false, @@ -712,38 +860,23 @@ impl Token { self.ident().is_some_and(|(ident, _)| ident.name == name) } - /// Returns `true` if the token is an interpolated path. - fn is_whole_path(&self) -> bool { - if let Interpolated(nt) = &self.kind - && let NtPath(..) = &**nt - { - return true; - } - - false - } - /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? - pub fn is_whole_expr(&self) -> bool { - if let Interpolated(nt) = &self.kind - && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt - { - return true; - } - - false + pub fn is_metavar_expr(&self) -> bool { + matches!( + self.is_metavar_seq(), + Some( + MetaVarKind::Expr { .. } + | MetaVarKind::Literal + | MetaVarKind::Path + | MetaVarKind::Block + ) + ) } - /// Is the token an interpolated block (`$b:block`)? - pub fn is_whole_block(&self) -> bool { - if let Interpolated(nt) = &self.kind - && let NtBlock(..) = &**nt - { - return true; - } - - false + /// Are we at a block from a metavar (`$b:block`)? + pub fn is_metavar_block(&self) -> bool { + matches!(self.is_metavar_seq(), Some(MetaVarKind::Block)) } /// Returns `true` if the token is either the `mut` or `const` keyword. @@ -752,13 +885,13 @@ impl Token { } pub fn is_qpath_start(&self) -> bool { - self == &Lt || self == &BinOp(Shl) + self == &Lt || self == &Shl } pub fn is_path_start(&self) -> bool { self == &PathSep || self.is_qpath_start() - || self.is_whole_path() + || matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) || self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident() } @@ -768,12 +901,14 @@ impl Token { self.is_non_raw_ident_where(|id| id.name == kw) } - /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case. + /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this + /// token is an identifier equal to `kw` ignoring the case. pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool { self.is_keyword(kw) || (case == Case::Insensitive && self.is_non_raw_ident_where(|id| { - id.name.as_str().to_lowercase() == kw.as_str().to_lowercase() + // Do an ASCII case-insensitive match, because all keywords are ASCII. + id.name.as_str().eq_ignore_ascii_case(kw.as_str()) })) } @@ -827,60 +962,93 @@ impl Token { } } + /// Is this an invisible open delimiter at the start of a token sequence + /// from an expanded metavar? + pub fn is_metavar_seq(&self) -> Option<MetaVarKind> { + match self.kind { + OpenInvisible(InvisibleOrigin::MetaVar(kind)) => Some(kind), + _ => None, + } + } + pub fn glue(&self, joint: &Token) -> Option<Token> { - let kind = match self.kind { - Eq => match joint.kind { - Eq => EqEq, - Gt => FatArrow, - _ => return None, - }, - Lt => match joint.kind { - Eq => Le, - Lt => BinOp(Shl), - Le => BinOpEq(Shl), - BinOp(Minus) => LArrow, - _ => return None, - }, - Gt => match joint.kind { - Eq => Ge, - Gt => BinOp(Shr), - Ge => BinOpEq(Shr), - _ => return None, - }, - Not => match joint.kind { - Eq => Ne, - _ => return None, - }, - BinOp(op) => match joint.kind { - Eq => BinOpEq(op), - BinOp(And) if op == And => AndAnd, - BinOp(Or) if op == Or => OrOr, - Gt if op == Minus => RArrow, - _ => return None, - }, - Dot => match joint.kind { - Dot => DotDot, - DotDot => DotDotDot, - _ => return None, - }, - DotDot => match joint.kind { - Dot => DotDotDot, - Eq => DotDotEq, - _ => return None, - }, - Colon => match joint.kind { - Colon => PathSep, - _ => return None, - }, - SingleQuote => match joint.kind { - Ident(name, is_raw) => Lifetime(Symbol::intern(&format!("'{name}")), is_raw), - _ => return None, - }, + let kind = match (&self.kind, &joint.kind) { + (Eq, Eq) => EqEq, + (Eq, Gt) => FatArrow, + (Eq, _) => return None, + + (Lt, Eq) => Le, + (Lt, Lt) => Shl, + (Lt, Le) => ShlEq, + (Lt, Minus) => LArrow, + (Lt, _) => return None, + + (Gt, Eq) => Ge, + (Gt, Gt) => Shr, + (Gt, Ge) => ShrEq, + (Gt, _) => return None, + + (Bang, Eq) => Ne, + (Bang, _) => return None, + + (Plus, Eq) => PlusEq, + (Plus, _) => return None, + + (Minus, Eq) => MinusEq, + (Minus, Gt) => RArrow, + (Minus, _) => return None, + + (Star, Eq) => StarEq, + (Star, _) => return None, + + (Slash, Eq) => SlashEq, + (Slash, _) => return None, + + (Percent, Eq) => PercentEq, + (Percent, _) => return None, + + (Caret, Eq) => CaretEq, + (Caret, _) => return None, + + (And, Eq) => AndEq, + (And, And) => AndAnd, + (And, _) => return None, - Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot - | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar - | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..) - | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof => { + (Or, Eq) => OrEq, + (Or, Or) => OrOr, + (Or, _) => return None, + + (Shl, Eq) => ShlEq, + (Shl, _) => return None, + + (Shr, Eq) => ShrEq, + (Shr, _) => return None, + + (Dot, Dot) => DotDot, + (Dot, DotDot) => DotDotDot, + (Dot, _) => return None, + + (DotDot, Dot) => DotDotDot, + (DotDot, Eq) => DotDotEq, + (DotDot, _) => return None, + + (Colon, Colon) => PathSep, + (Colon, _) => return None, + + (SingleQuote, Ident(name, is_raw)) => { + Lifetime(Symbol::intern(&format!("'{name}")), *is_raw) + } + (SingleQuote, _) => return None, + + ( + Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | PlusEq | MinusEq | StarEq | SlashEq + | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq + | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question + | OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket + | OpenInvisible(_) | CloseInvisible(_) | Literal(..) | Ident(..) | NtIdent(..) + | Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof, + _, + ) => { return None; } }; @@ -896,7 +1064,7 @@ impl PartialEq<TokenKind> for Token { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NtPatKind { // Matches or-patterns. Was written using `pat` in edition 2021 or later. PatWithOr, @@ -906,7 +1074,7 @@ pub enum NtPatKind { PatParam { inferred: bool }, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NtExprKind { // Matches expressions using the post-edition 2024. Was written using // `expr` in edition 2024 or later. @@ -917,23 +1085,7 @@ pub enum NtExprKind { Expr2021 { inferred: bool }, } -#[derive(Clone, Encodable, Decodable)] -/// For interpolation during macro expansion. -pub enum Nonterminal { - NtItem(P<ast::Item>), - NtBlock(P<ast::Block>), - NtStmt(P<ast::Stmt>), - NtPat(P<ast::Pat>), - NtExpr(P<ast::Expr>), - NtTy(P<ast::Ty>), - NtLiteral(P<ast::Expr>), - /// Stuff inside brackets for attributes - NtMeta(P<ast::AttrItem>), - NtPath(P<ast::Path>), - NtVis(P<ast::Visibility>), -} - -#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NonterminalKind { Item, Block, @@ -1016,73 +1168,6 @@ impl fmt::Display for NonterminalKind { } } -impl Nonterminal { - pub fn use_span(&self) -> Span { - match self { - NtItem(item) => item.span, - NtBlock(block) => block.span, - NtStmt(stmt) => stmt.span, - NtPat(pat) => pat.span, - NtExpr(expr) | NtLiteral(expr) => expr.span, - NtTy(ty) => ty.span, - NtMeta(attr_item) => attr_item.span(), - NtPath(path) => path.span, - NtVis(vis) => vis.span, - } - } - - pub fn descr(&self) -> &'static str { - match self { - NtItem(..) => "item", - NtBlock(..) => "block", - NtStmt(..) => "statement", - NtPat(..) => "pattern", - NtExpr(..) => "expression", - NtLiteral(..) => "literal", - NtTy(..) => "type", - NtMeta(..) => "attribute", - NtPath(..) => "path", - NtVis(..) => "visibility", - } - } -} - -impl PartialEq for Nonterminal { - fn eq(&self, _rhs: &Self) -> bool { - // FIXME: Assume that all nonterminals are not equal, we can't compare them - // correctly based on data from AST. This will prevent them from matching each other - // in macros. The comparison will become possible only when each nonterminal has an - // attached token stream from which it was parsed. - false - } -} - -impl fmt::Debug for Nonterminal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - NtItem(..) => f.pad("NtItem(..)"), - NtBlock(..) => f.pad("NtBlock(..)"), - NtStmt(..) => f.pad("NtStmt(..)"), - NtPat(..) => f.pad("NtPat(..)"), - NtExpr(..) => f.pad("NtExpr(..)"), - NtTy(..) => f.pad("NtTy(..)"), - NtLiteral(..) => f.pad("NtLiteral(..)"), - NtMeta(..) => f.pad("NtMeta(..)"), - NtPath(..) => f.pad("NtPath(..)"), - NtVis(..) => f.pad("NtVis(..)"), - } - } -} - -impl<CTX> HashStable<CTX> for Nonterminal -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) { - panic!("interpolated tokens should not be present in the HIR") - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { @@ -1092,7 +1177,6 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(Lit, 12); static_assert_size!(LitKind, 2); - static_assert_size!(Nonterminal, 16); static_assert_size!(Token, 24); static_assert_size!(TokenKind, 16); // tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index d5c2bc1c7f63c..43d25d180750e 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -14,17 +14,18 @@ //! ownership of the original. use std::borrow::Cow; +use std::sync::Arc; use std::{cmp, fmt, iter}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{self, Lrc}; +use rustc_data_structures::sync; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym}; -use crate::ast::{AttrStyle, StmtKind}; +use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; -use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; +use crate::token::{self, Delimiter, Token, TokenKind}; use crate::{AttrVec, Attribute}; /// Part of a `TokenStream`. @@ -38,7 +39,6 @@ pub enum TokenTree { } // Ensure all fields of `TokenTree` are `DynSend` and `DynSync`. -#[cfg(parallel_compiler)] fn _dummy() where Token: sync::DynSend + sync::DynSync, @@ -100,7 +100,7 @@ where CTX: crate::HashStableContext, { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - for sub_tt in self.trees() { + for sub_tt in self.iter() { sub_tt.hash_stable(hcx, hasher); } } @@ -120,11 +120,11 @@ impl ToAttrTokenStream for AttrTokenStream { /// of an actual `TokenStream` until it is needed. /// `Box` is here only to reduce the structure size. #[derive(Clone)] -pub struct LazyAttrTokenStream(Lrc<Box<dyn ToAttrTokenStream>>); +pub struct LazyAttrTokenStream(Arc<Box<dyn ToAttrTokenStream>>); impl LazyAttrTokenStream { pub fn new(inner: impl ToAttrTokenStream + 'static) -> LazyAttrTokenStream { - LazyAttrTokenStream(Lrc::new(Box::new(inner))) + LazyAttrTokenStream(Arc::new(Box::new(inner))) } pub fn to_attr_token_stream(&self) -> AttrTokenStream { @@ -161,7 +161,7 @@ impl<CTX> HashStable<CTX> for LazyAttrTokenStream { /// during expansion to perform early cfg-expansion, and to process attributes /// during proc-macro invocations. #[derive(Clone, Debug, Default, Encodable, Decodable)] -pub struct AttrTokenStream(pub Lrc<Vec<AttrTokenTree>>); +pub struct AttrTokenStream(pub Arc<Vec<AttrTokenTree>>); /// Like `TokenTree`, but for `AttrTokenStream`. #[derive(Clone, Debug, Encodable, Decodable)] @@ -176,7 +176,7 @@ pub enum AttrTokenTree { impl AttrTokenStream { pub fn new(tokens: Vec<AttrTokenTree>) -> AttrTokenStream { - AttrTokenStream(Lrc::new(tokens)) + AttrTokenStream(Arc::new(tokens)) } /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`. During @@ -233,35 +233,52 @@ fn attrs_and_tokens_to_token_trees( // Insert inner attribute tokens. if !inner_attrs.is_empty() { - let mut found = false; - // Check the last two trees (to account for a trailing semi) - for tree in res.iter_mut().rev().take(2) { - if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree { - // Inner attributes are only supported on extern blocks, functions, - // impls, and modules. All of these have their inner attributes - // placed at the beginning of the rightmost outermost braced group: - // e.g. fn foo() { #![my_attr] } - // - // Therefore, we can insert them back into the right location - // without needing to do any extra position tracking. - // - // Note: Outline modules are an exception - they can - // have attributes like `#![my_attr]` at the start of a file. - // Support for custom attributes in this position is not - // properly implemented - we always synthesize fake tokens, - // so we never reach this code. + let found = insert_inner_attrs(inner_attrs, res); + assert!(found, "Failed to find trailing delimited group in: {res:?}"); + } + + // Inner attributes are only supported on blocks, functions, impls, and + // modules. All of these have their inner attributes placed at the + // beginning of the rightmost outermost braced group: + // e.g. `fn foo() { #![my_attr] }`. (Note: the braces may be within + // invisible delimiters.) + // + // Therefore, we can insert them back into the right location without + // needing to do any extra position tracking. + // + // Note: Outline modules are an exception - they can have attributes like + // `#![my_attr]` at the start of a file. Support for custom attributes in + // this position is not properly implemented - we always synthesize fake + // tokens, so we never reach this code. + fn insert_inner_attrs(inner_attrs: &[Attribute], tts: &mut Vec<TokenTree>) -> bool { + for tree in tts.iter_mut().rev() { + if let TokenTree::Delimited(span, spacing, Delimiter::Brace, stream) = tree { + // Found it: the rightmost, outermost braced group. let mut tts = vec![]; for inner_attr in inner_attrs { tts.extend(inner_attr.token_trees()); } - tts.extend(delim_tokens.0.iter().cloned()); + tts.extend(stream.0.iter().cloned()); let stream = TokenStream::new(tts); - *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); - found = true; - break; + *tree = TokenTree::Delimited(*span, *spacing, Delimiter::Brace, stream); + return true; + } else if let TokenTree::Delimited(span, spacing, Delimiter::Invisible(src), stream) = + tree + { + // Recurse inside invisible delimiters. + let mut vec: Vec<_> = stream.iter().cloned().collect(); + if insert_inner_attrs(inner_attrs, &mut vec) { + *tree = TokenTree::Delimited( + *span, + *spacing, + Delimiter::Invisible(*src), + TokenStream::new(vec), + ); + return true; + } } } - assert!(found, "Failed to find trailing delimited group in: {res:?}"); + false } } @@ -288,13 +305,8 @@ pub struct AttrsTarget { } /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. -/// -/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s -/// instead of a representation of the abstract syntax tree. -/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for -/// backwards compatibility. #[derive(Clone, Debug, Default, Encodable, Decodable)] -pub struct TokenStream(pub(crate) Lrc<Vec<TokenTree>>); +pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>); /// Indicates whether a token can join with the following token to form a /// compound token. Used for conversions to `proc_macro::Spacing`. Also used to @@ -407,13 +419,13 @@ impl Eq for TokenStream {} impl PartialEq<TokenStream> for TokenStream { fn eq(&self, other: &TokenStream) -> bool { - self.trees().eq(other.trees()) + self.iter().eq(other.iter()) } } impl TokenStream { pub fn new(tts: Vec<TokenTree>) -> TokenStream { - TokenStream(Lrc::new(tts)) + TokenStream(Arc::new(tts)) } pub fn is_empty(&self) -> bool { @@ -424,24 +436,24 @@ impl TokenStream { self.0.len() } - pub fn trees(&self) -> RefTokenTreeCursor<'_> { - RefTokenTreeCursor::new(self) + pub fn get(&self, index: usize) -> Option<&TokenTree> { + self.0.get(index) } - pub fn into_trees(self) -> TokenTreeCursor { - TokenTreeCursor::new(self) + pub fn iter(&self) -> TokenStreamIter<'_> { + TokenStreamIter::new(self) } /// Compares two `TokenStream`s, checking equality without regarding span information. pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - let mut t1 = self.trees(); - let mut t2 = other.trees(); - for (t1, t2) in iter::zip(&mut t1, &mut t2) { - if !t1.eq_unspanned(t2) { + let mut iter1 = self.iter(); + let mut iter2 = other.iter(); + for (tt1, tt2) in iter::zip(&mut iter1, &mut iter2) { + if !tt1.eq_unspanned(tt2) { return false; } } - t1.next().is_none() && t2.next().is_none() + iter1.next().is_none() && iter2.next().is_none() } /// Create a token stream containing a single token with alone spacing. The @@ -459,73 +471,6 @@ impl TokenStream { TokenStream::new(tts) } - pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { - match nt { - Nonterminal::NtItem(item) => TokenStream::from_ast(item), - Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => { - // FIXME: Properly collect tokens for empty statements. - TokenStream::token_alone(token::Semi, stmt.span) - } - Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), - Nonterminal::NtPat(pat) => TokenStream::from_ast(pat), - Nonterminal::NtTy(ty) => TokenStream::from_ast(ty), - Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), - Nonterminal::NtPath(path) => TokenStream::from_ast(path), - Nonterminal::NtVis(vis) => TokenStream::from_ast(vis), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), - } - } - - fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree { - match token.kind { - token::NtIdent(ident, is_raw) => { - TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing) - } - token::NtLifetime(ident, is_raw) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible, - TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), - ), - token::Interpolated(ref nt) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible, - TokenStream::from_nonterminal_ast(&nt).flattened(), - ), - _ => TokenTree::Token(token.clone(), spacing), - } - } - - fn flatten_token_tree(tree: &TokenTree) -> TokenTree { - match tree { - TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing), - TokenTree::Delimited(span, spacing, delim, tts) => { - TokenTree::Delimited(*span, *spacing, *delim, tts.flattened()) - } - } - } - - #[must_use] - pub fn flattened(&self) -> TokenStream { - fn can_skip(stream: &TokenStream) -> bool { - stream.trees().all(|tree| match tree { - TokenTree::Token(token, _) => !matches!( - token.kind, - token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..) - ), - TokenTree::Delimited(.., inner) => can_skip(inner), - }) - } - - if can_skip(self) { - return self.clone(); - } - - self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect() - } - // If `vec` is not empty, try to glue `tt` onto its last token. The return // value indicates if gluing took place. fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool { @@ -545,7 +490,7 @@ impl TokenStream { /// Push `tt` onto the end of the stream, possibly gluing it to the last /// token. Uses `make_mut` to maximize efficiency. pub fn push_tree(&mut self, tt: TokenTree) { - let vec_mut = Lrc::make_mut(&mut self.0); + let vec_mut = Arc::make_mut(&mut self.0); if Self::try_glue_to_last(vec_mut, &tt) { // nothing else to do @@ -558,7 +503,7 @@ impl TokenStream { /// token tree to the last token. (No other token trees will be glued.) /// Uses `make_mut` to maximize efficiency. pub fn push_stream(&mut self, stream: TokenStream) { - let vec_mut = Lrc::make_mut(&mut self.0); + let vec_mut = Arc::make_mut(&mut self.0); let stream_iter = stream.0.iter().cloned(); @@ -578,7 +523,7 @@ impl TokenStream { } /// Desugar doc comments like `/// foo` in the stream into `#[doc = - /// r"foo"]`. Modifies the `TokenStream` via `Lrc::make_mut`, but as little + /// r"foo"]`. Modifies the `TokenStream` via `Arc::make_mut`, but as little /// as possible. pub fn desugar_doc_comments(&mut self) { if let Some(desugared_stream) = desugar_inner(self.clone()) { @@ -597,7 +542,7 @@ impl TokenStream { ) => { let desugared = desugared_tts(attr_style, data, span); let desugared_len = desugared.len(); - Lrc::make_mut(&mut stream.0).splice(i..i + 1, desugared); + Arc::make_mut(&mut stream.0).splice(i..i + 1, desugared); modified = true; i += desugared_len; } @@ -608,7 +553,7 @@ impl TokenStream { if let Some(desugared_delim_stream) = desugar_inner(delim_stream.clone()) { let new_tt = TokenTree::Delimited(sp, spacing, delim, desugared_delim_stream); - Lrc::make_mut(&mut stream.0)[i] = new_tt; + Arc::make_mut(&mut stream.0)[i] = new_tt; modified = true; } i += 1; @@ -656,7 +601,7 @@ impl TokenStream { if attr_style == AttrStyle::Inner { vec![ TokenTree::token_joint(token::Pound, span), - TokenTree::token_joint_hidden(token::Not, span), + TokenTree::token_joint_hidden(token::Bang, span), body, ] } else { @@ -666,25 +611,26 @@ impl TokenStream { } } -/// By-reference iterator over a [`TokenStream`], that produces `&TokenTree` -/// items. #[derive(Clone)] -pub struct RefTokenTreeCursor<'t> { +pub struct TokenStreamIter<'t> { stream: &'t TokenStream, index: usize, } -impl<'t> RefTokenTreeCursor<'t> { +impl<'t> TokenStreamIter<'t> { fn new(stream: &'t TokenStream) -> Self { - RefTokenTreeCursor { stream, index: 0 } + TokenStreamIter { stream, index: 0 } } - pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { - self.stream.0.get(self.index + n) + // Peeking could be done via `Peekable`, but most iterators need peeking, + // and this is simple and avoids the need to use `peekable` and `Peekable` + // at all the use sites. + pub fn peek(&self) -> Option<&'t TokenTree> { + self.stream.0.get(self.index) } } -impl<'t> Iterator for RefTokenTreeCursor<'t> { +impl<'t> Iterator for TokenStreamIter<'t> { type Item = &'t TokenTree; fn next(&mut self) -> Option<&'t TokenTree> { @@ -695,39 +641,6 @@ impl<'t> Iterator for RefTokenTreeCursor<'t> { } } -/// Owning by-value iterator over a [`TokenStream`], that produces `&TokenTree` -/// items. -/// -/// Doesn't impl `Iterator` because Rust doesn't permit an owning iterator to -/// return `&T` from `next`; the need for an explicit lifetime in the `Item` -/// associated type gets in the way. Instead, use `next_ref` (which doesn't -/// involve associated types) for getting individual elements, or -/// `RefTokenTreeCursor` if you really want an `Iterator`, e.g. in a `for` -/// loop. -#[derive(Clone, Debug)] -pub struct TokenTreeCursor { - pub stream: TokenStream, - index: usize, -} - -impl TokenTreeCursor { - fn new(stream: TokenStream) -> Self { - TokenTreeCursor { stream, index: 0 } - } - - #[inline] - pub fn next_ref(&mut self) -> Option<&TokenTree> { - self.stream.0.get(self.index).map(|tree| { - self.index += 1; - tree - }) - } - - pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { - self.stream.0.get(self.index + n) - } -} - #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)] pub struct DelimSpan { pub open: Span, diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index ae1ca36a3ba93..989ebe14bf8fc 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -108,6 +108,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool { Assign(e, _, _) | AssignOp(_, e, _) | Await(e, _) + | Use(e, _) | Binary(_, e, _) | Call(e, _) | Cast(e, _) @@ -152,6 +153,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool { | Underscore | Yeet(..) | Yield(..) + | UnsafeBinderCast(..) | Err(..) | Dummy => return false, } @@ -180,11 +182,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> { | Range(_, Some(e), _) | Ret(Some(e)) | Unary(_, e) - | Yield(Some(e)) | Yeet(Some(e)) | Become(e) => { expr = e; } + Yield(kind) => match kind.expr() { + Some(e) => expr = e, + None => break None, + }, Closure(closure) => { expr = &closure.body; } @@ -215,7 +220,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> { Break(_, None) | Range(_, None, _) | Ret(None) - | Yield(None) | Array(_) | Call(_, _) | MethodCall(_) @@ -223,6 +227,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> { | Lit(_) | Type(_, _) | Await(_, _) + | Use(_, _) | Field(_, _) | Index(_, _, _) | Underscore @@ -232,8 +237,11 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> { | Paren(_) | Try(_) | Yeet(None) + | UnsafeBinderCast(..) | Err(_) - | Dummy => break None, + | Dummy => { + break None; + } } } } @@ -253,6 +261,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { ty = &mut_ty.ty; } + ast::TyKind::UnsafeBinder(binder) => { + ty = &binder.inner_ty; + } + ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output { ast::FnRetTy::Default(_) => break None, ast::FnRetTy::Ty(ret) => ty = ret, diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index f39142f08ba52..e12818623d8ec 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -39,7 +39,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol { let mut i = 0; let mut j = lines.len(); // first line of all-stars should be omitted - if !lines.is_empty() && lines[0].chars().all(|c| c == '*') { + if lines.first().is_some_and(|line| line.chars().all(|c| c == '*')) { i += 1; } @@ -97,7 +97,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol { return None; } } - if lines.is_empty() { None } else { Some(lines[0][..i].into()) } + Some(lines.first()?[..i].to_string()) } let data_s = data.as_str(); diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs index 61bb2468e79b9..7a87ccea62a7e 100644 --- a/compiler/rustc_ast/src/util/comments/tests.rs +++ b/compiler/rustc_ast/src/util/comments/tests.rs @@ -1,3 +1,5 @@ +#![allow(rustc::symbol_intern_string_literal)] + use rustc_span::create_default_session_globals_then; use super::*; diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 498df5a71441b..b8526cf9d9529 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -2,11 +2,10 @@ use std::{ascii, fmt, str}; -use rustc_lexer::unescape::{ +use rustc_literal_escaper::{ MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, }; -use rustc_span::Span; -use rustc_span::symbol::{Symbol, kw, sym}; +use rustc_span::{Span, Symbol, kw, sym}; use tracing::debug; use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; @@ -122,7 +121,7 @@ impl LitKind { } token::ByteStrRaw(n) => { // Raw strings have no escapes so we can convert the symbol - // directly to a `Lrc<u8>`. + // directly to a `Arc<u8>`. let buf = symbol.as_str().to_owned().into_bytes(); LitKind::ByteStr(buf.into(), StrStyle::Raw(n)) } @@ -143,7 +142,7 @@ impl LitKind { } token::CStrRaw(n) => { // Raw strings have no escapes so we can convert the symbol - // directly to a `Lrc<u8>` after appending the terminating NUL + // directly to a `Arc<u8>` after appending the terminating NUL // char. let mut buf = symbol.as_str().to_owned().into_bytes(); buf.push(0); diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index d8dad4550c0c5..1e5f414fae1c7 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -1,59 +1,21 @@ -use rustc_span::symbol::kw; +use rustc_span::kw; -use crate::ast::{self, BinOpKind}; -use crate::token::{self, BinOpToken, Token}; +use crate::ast::{self, AssignOpKind, BinOpKind, RangeLimits}; +use crate::token::{self, Token}; -/// Associative operator with precedence. -/// -/// This is the enum which specifies operator precedence and fixity to the parser. +/// Associative operator. #[derive(Copy, Clone, PartialEq, Debug)] pub enum AssocOp { - /// `+` - Add, - /// `-` - Subtract, - /// `*` - Multiply, - /// `/` - Divide, - /// `%` - Modulus, - /// `&&` - LAnd, - /// `||` - LOr, - /// `^` - BitXor, - /// `&` - BitAnd, - /// `|` - BitOr, - /// `<<` - ShiftLeft, - /// `>>` - ShiftRight, - /// `==` - Equal, - /// `<` - Less, - /// `<=` - LessEqual, - /// `!=` - NotEqual, - /// `>` - Greater, - /// `>=` - GreaterEqual, + /// A binary op. + Binary(BinOpKind), + /// `?=` where ? is one of the assignable BinOps + AssignOp(AssignOpKind), /// `=` Assign, - /// `?=` where ? is one of the BinOpToken - AssignOp(BinOpToken), /// `as` - As, - /// `..` range - DotDot, - /// `..=` range - DotDotEq, + Cast, + /// `..` or `..=` range + Range(RangeLimits), } #[derive(PartialEq, Debug)] @@ -67,82 +29,57 @@ pub enum Fixity { } impl AssocOp { - /// Creates a new AssocOP from a token + /// Creates a new AssocOp from a token. pub fn from_token(t: &Token) -> Option<AssocOp> { use AssocOp::*; match t.kind { - token::BinOpEq(k) => Some(AssignOp(k)), token::Eq => Some(Assign), - token::BinOp(BinOpToken::Star) => Some(Multiply), - token::BinOp(BinOpToken::Slash) => Some(Divide), - token::BinOp(BinOpToken::Percent) => Some(Modulus), - token::BinOp(BinOpToken::Plus) => Some(Add), - token::BinOp(BinOpToken::Minus) => Some(Subtract), - token::BinOp(BinOpToken::Shl) => Some(ShiftLeft), - token::BinOp(BinOpToken::Shr) => Some(ShiftRight), - token::BinOp(BinOpToken::And) => Some(BitAnd), - token::BinOp(BinOpToken::Caret) => Some(BitXor), - token::BinOp(BinOpToken::Or) => Some(BitOr), - token::Lt => Some(Less), - token::Le => Some(LessEqual), - token::Ge => Some(GreaterEqual), - token::Gt => Some(Greater), - token::EqEq => Some(Equal), - token::Ne => Some(NotEqual), - token::AndAnd => Some(LAnd), - token::OrOr => Some(LOr), - token::DotDot => Some(DotDot), - token::DotDotEq => Some(DotDotEq), + token::Plus => Some(Binary(BinOpKind::Add)), + token::Minus => Some(Binary(BinOpKind::Sub)), + token::Star => Some(Binary(BinOpKind::Mul)), + token::Slash => Some(Binary(BinOpKind::Div)), + token::Percent => Some(Binary(BinOpKind::Rem)), + token::Caret => Some(Binary(BinOpKind::BitXor)), + token::And => Some(Binary(BinOpKind::BitAnd)), + token::Or => Some(Binary(BinOpKind::BitOr)), + token::Shl => Some(Binary(BinOpKind::Shl)), + token::Shr => Some(Binary(BinOpKind::Shr)), + token::PlusEq => Some(AssignOp(AssignOpKind::AddAssign)), + token::MinusEq => Some(AssignOp(AssignOpKind::SubAssign)), + token::StarEq => Some(AssignOp(AssignOpKind::MulAssign)), + token::SlashEq => Some(AssignOp(AssignOpKind::DivAssign)), + token::PercentEq => Some(AssignOp(AssignOpKind::RemAssign)), + token::CaretEq => Some(AssignOp(AssignOpKind::BitXorAssign)), + token::AndEq => Some(AssignOp(AssignOpKind::BitAndAssign)), + token::OrEq => Some(AssignOp(AssignOpKind::BitOrAssign)), + token::ShlEq => Some(AssignOp(AssignOpKind::ShlAssign)), + token::ShrEq => Some(AssignOp(AssignOpKind::ShrAssign)), + token::Lt => Some(Binary(BinOpKind::Lt)), + token::Le => Some(Binary(BinOpKind::Le)), + token::Ge => Some(Binary(BinOpKind::Ge)), + token::Gt => Some(Binary(BinOpKind::Gt)), + token::EqEq => Some(Binary(BinOpKind::Eq)), + token::Ne => Some(Binary(BinOpKind::Ne)), + token::AndAnd => Some(Binary(BinOpKind::And)), + token::OrOr => Some(Binary(BinOpKind::Or)), + token::DotDot => Some(Range(RangeLimits::HalfOpen)), // DotDotDot is no longer supported, but we need some way to display the error - token::DotDotDot => Some(DotDotEq), + token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)), // `<-` should probably be `< -` - token::LArrow => Some(Less), - _ if t.is_keyword(kw::As) => Some(As), + token::LArrow => Some(Binary(BinOpKind::Lt)), + _ if t.is_keyword(kw::As) => Some(Cast), _ => None, } } - /// Creates a new AssocOp from ast::BinOpKind. - pub fn from_ast_binop(op: BinOpKind) -> Self { - use AssocOp::*; - match op { - BinOpKind::Lt => Less, - BinOpKind::Gt => Greater, - BinOpKind::Le => LessEqual, - BinOpKind::Ge => GreaterEqual, - BinOpKind::Eq => Equal, - BinOpKind::Ne => NotEqual, - BinOpKind::Mul => Multiply, - BinOpKind::Div => Divide, - BinOpKind::Rem => Modulus, - BinOpKind::Add => Add, - BinOpKind::Sub => Subtract, - BinOpKind::Shl => ShiftLeft, - BinOpKind::Shr => ShiftRight, - BinOpKind::BitAnd => BitAnd, - BinOpKind::BitXor => BitXor, - BinOpKind::BitOr => BitOr, - BinOpKind::And => LAnd, - BinOpKind::Or => LOr, - } - } - /// Gets the precedence of this operator - pub fn precedence(&self) -> usize { + pub fn precedence(&self) -> ExprPrecedence { use AssocOp::*; match *self { - As => 14, - Multiply | Divide | Modulus => 13, - Add | Subtract => 12, - ShiftLeft | ShiftRight => 11, - BitAnd => 10, - BitXor => 9, - BitOr => 8, - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7, - LAnd => 6, - LOr => 5, - DotDot | DotDotEq => 4, - Assign | AssignOp(_) => 2, + Cast => ExprPrecedence::Cast, + Binary(bin_op) => bin_op.precedence(), + Range(_) => ExprPrecedence::Range, + Assign | AssignOp(_) => ExprPrecedence::Assign, } } @@ -152,21 +89,17 @@ impl AssocOp { // NOTE: it is a bug to have an operators that has same precedence but different fixities! match *self { Assign | AssignOp(_) => Fixity::Right, - As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd - | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual - | LAnd | LOr => Fixity::Left, - DotDot | DotDotEq => Fixity::None, + Binary(binop) => binop.fixity(), + Cast => Fixity::Left, + Range(_) => Fixity::None, } } pub fn is_comparison(&self) -> bool { use AssocOp::*; match *self { - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, - Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract - | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq => { - false - } + Binary(binop) => binop.is_comparison(), + Assign | AssignOp(_) | Cast | Range(_) => false, } } @@ -174,34 +107,7 @@ impl AssocOp { use AssocOp::*; match *self { Assign | AssignOp(_) => true, - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply - | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor - | BitOr | LAnd | LOr | DotDot | DotDotEq => false, - } - } - - pub fn to_ast_binop(&self) -> Option<BinOpKind> { - use AssocOp::*; - match *self { - Less => Some(BinOpKind::Lt), - Greater => Some(BinOpKind::Gt), - LessEqual => Some(BinOpKind::Le), - GreaterEqual => Some(BinOpKind::Ge), - Equal => Some(BinOpKind::Eq), - NotEqual => Some(BinOpKind::Ne), - Multiply => Some(BinOpKind::Mul), - Divide => Some(BinOpKind::Div), - Modulus => Some(BinOpKind::Rem), - Add => Some(BinOpKind::Add), - Subtract => Some(BinOpKind::Sub), - ShiftLeft => Some(BinOpKind::Shl), - ShiftRight => Some(BinOpKind::Shr), - BitAnd => Some(BinOpKind::BitAnd), - BitXor => Some(BinOpKind::BitXor), - BitOr => Some(BinOpKind::BitOr), - LAnd => Some(BinOpKind::And), - LOr => Some(BinOpKind::Or), - Assign | AssignOp(_) | As | DotDot | DotDotEq => None, + Cast | Binary(_) | Range(_) => false, } } @@ -211,150 +117,64 @@ impl AssocOp { /// parentheses while having a high degree of confidence on the correctness of the suggestion. pub fn can_continue_expr_unambiguously(&self) -> bool { use AssocOp::*; + use BinOpKind::*; matches!( self, - BitXor | // `{ 42 } ^ 3` Assign | // `{ 42 } = { 42 }` - Divide | // `{ 42 } / 42` - Modulus | // `{ 42 } % 2` - ShiftRight | // `{ 42 } >> 2` - LessEqual | // `{ 42 } <= 3` - Greater | // `{ 42 } > 3` - GreaterEqual | // `{ 42 } >= 3` + Binary( + BitXor | // `{ 42 } ^ 3` + Div | // `{ 42 } / 42` + Rem | // `{ 42 } % 2` + Shr | // `{ 42 } >> 2` + Le | // `{ 42 } <= 3` + Gt | // `{ 42 } > 3` + Ge // `{ 42 } >= 3` + ) | AssignOp(_) | // `{ 42 } +=` // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery. - As // `{ 42 } as usize` + Cast // `{ 42 } as usize` ) } } -pub const PREC_CLOSURE: i8 = -40; -pub const PREC_JUMP: i8 = -30; -pub const PREC_RANGE: i8 = -10; -// The range 2..=14 is reserved for AssocOp binary operator precedences. -pub const PREC_PREFIX: i8 = 50; -pub const PREC_UNAMBIGUOUS: i8 = 60; -pub const PREC_FORCE_PAREN: i8 = 100; - -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy, PartialEq, PartialOrd)] pub enum ExprPrecedence { - Closure, - Break, - Continue, - Ret, - Yield, - Yeet, - Become, - + // return, break, yield, closures + Jump, + // = += -= *= /= %= &= |= ^= <<= >>= + Assign, + // .. ..= Range, - - Binary(BinOpKind), - + // || + LOr, + // && + LAnd, + // == != < > <= >= + Compare, + // | + BitOr, + // ^ + BitXor, + // & + BitAnd, + // << >> + Shift, + // + - + Sum, + // * / % + Product, + // as Cast, - - Assign, - AssignOp, - - AddrOf, - Let, - Unary, - - Call, - MethodCall, - Field, - Index, - Try, - Mac, - - Array, - Repeat, - Tup, - Lit, - Path, - Paren, - If, - While, - ForLoop, - Loop, - Match, - PostfixMatch, - ConstBlock, - Block, - TryBlock, - Struct, - Gen, - Await, - Err, -} - -impl ExprPrecedence { - pub fn order(self) -> i8 { - match self { - ExprPrecedence::Closure => PREC_CLOSURE, - - ExprPrecedence::Break - | ExprPrecedence::Continue - | ExprPrecedence::Ret - | ExprPrecedence::Yield - | ExprPrecedence::Yeet - | ExprPrecedence::Become => PREC_JUMP, - - // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to - // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence - // ensures that `pprust` will add parentheses in the right places to get the desired - // parse. - ExprPrecedence::Range => PREC_RANGE, - - // Binop-like expr kinds, handled by `AssocOp`. - ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8, - ExprPrecedence::Cast => AssocOp::As.precedence() as i8, - - ExprPrecedence::Assign | - ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8, - - // Unary, prefix - ExprPrecedence::AddrOf - // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`. - // However, this is not exactly right. When `let _ = a` is the LHS of a binop we - // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b` - // but we need to print `(let _ = a) < b` as-is with parens. - | ExprPrecedence::Let - | ExprPrecedence::Unary => PREC_PREFIX, - - // Never need parens - ExprPrecedence::Array - | ExprPrecedence::Await - | ExprPrecedence::Block - | ExprPrecedence::Call - | ExprPrecedence::ConstBlock - | ExprPrecedence::Field - | ExprPrecedence::ForLoop - | ExprPrecedence::Gen - | ExprPrecedence::If - | ExprPrecedence::Index - | ExprPrecedence::Lit - | ExprPrecedence::Loop - | ExprPrecedence::Mac - | ExprPrecedence::Match - | ExprPrecedence::MethodCall - | ExprPrecedence::Paren - | ExprPrecedence::Path - | ExprPrecedence::PostfixMatch - | ExprPrecedence::Repeat - | ExprPrecedence::Struct - | ExprPrecedence::Try - | ExprPrecedence::TryBlock - | ExprPrecedence::Tup - | ExprPrecedence::While - | ExprPrecedence::Err => PREC_UNAMBIGUOUS, - } - } + // unary - * ! & &mut + Prefix, + // paths, loops, function calls, array indexing, field expressions, method calls + Unambiguous, } /// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`. -pub fn prec_let_scrutinee_needs_par() -> usize { - AssocOp::LAnd.precedence() +pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence { + ExprPrecedence::LAnd } /// Suppose we have `let _ = e` and the `order` of `e`. @@ -362,8 +182,8 @@ pub fn prec_let_scrutinee_needs_par() -> usize { /// /// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`. /// Can we print this as `let _ = a OP b`? -pub fn needs_par_as_let_scrutinee(order: i8) -> bool { - order <= prec_let_scrutinee_needs_par() as i8 +pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool { + order <= prec_let_scrutinee_needs_par() } /// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 207ec71065051..79193fcec63a4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -15,8 +15,8 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; -use rustc_span::Span; -use rustc_span::symbol::Ident; +use rustc_span::{Ident, Span}; +use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; @@ -24,7 +24,7 @@ use crate::ptr::P; #[derive(Copy, Clone, Debug, PartialEq)] pub enum AssocCtxt { Trait, - Impl, + Impl { of_trait: bool }, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -66,7 +66,7 @@ impl BoundKind { #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>), + Fn(FnCtxt, &'a Visibility, &'a Fn), /// E.g., `|x, y| body`. Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr), @@ -75,21 +75,21 @@ pub enum FnKind<'a> { impl<'a> FnKind<'a> { pub fn header(&self) -> Option<&'a FnHeader> { match *self { - FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header), + FnKind::Fn(_, _, Fn { sig, .. }) => Some(&sig.header), FnKind::Closure(..) => None, } } pub fn ident(&self) -> Option<&Ident> { match self { - FnKind::Fn(_, ident, ..) => Some(ident), + FnKind::Fn(_, _, Fn { ident, .. }) => Some(ident), _ => None, } } pub fn decl(&self) -> &'a FnDecl { match self { - FnKind::Fn(_, _, sig, _, _, _) => &sig.decl, + FnKind::Fn(_, _, Fn { sig, .. }) => &sig.decl, FnKind::Closure(_, _, decl, _) => decl, } } @@ -112,11 +112,14 @@ pub enum LifetimeCtxt { GenericArg, } -pub trait WalkItemKind: Sized { +pub trait WalkItemKind { + type Ctxt; fn walk<'a, V: Visitor<'a>>( &'a self, - item: &'a Item<Self>, - ctxt: AssocCtxt, + span: Span, + id: NodeId, + visibility: &'a Visibility, + ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result; } @@ -135,7 +138,7 @@ pub trait Visitor<'ast>: Sized { /// or `ControlFlow<T>`. type Result: VisitorResult = (); - fn visit_ident(&mut self, _ident: Ident) -> Self::Result { + fn visit_ident(&mut self, _ident: &'ast Ident) -> Self::Result { Self::Result::output() } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result { @@ -173,12 +176,12 @@ pub trait Visitor<'ast>: Sized { fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) -> Self::Result { self.visit_expr(ex) } - fn visit_expr_post(&mut self, _ex: &'ast Expr) -> Self::Result { - Self::Result::output() - } fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result { walk_ty(self, t) } + fn visit_ty_pat(&mut self, t: &'ast TyPat) -> Self::Result { + walk_ty_pat(self, t) + } fn visit_generic_param(&mut self, param: &'ast GenericParam) -> Self::Result { walk_generic_param(self, param) } @@ -188,9 +191,15 @@ pub trait Visitor<'ast>: Sized { fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) -> Self::Result { walk_closure_binder(self, b) } + fn visit_contract(&mut self, c: &'ast FnContract) -> Self::Result { + walk_contract(self, c) + } fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result { walk_where_predicate(self, p) } + fn visit_where_predicate_kind(&mut self, k: &'ast WherePredicateKind) -> Self::Result { + walk_where_predicate_kind(self, k) + } fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) -> Self::Result { walk_fn(self, fk) } @@ -203,8 +212,8 @@ pub trait Visitor<'ast>: Sized { fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result { walk_param_bound(self, bounds) } - fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) { - walk_precise_capturing_arg(self, arg); + fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) -> Self::Result { + walk_precise_capturing_arg(self, arg) } fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result { walk_poly_trait_ref(self, t) @@ -271,8 +280,8 @@ pub trait Visitor<'ast>: Sized { fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result { walk_fn_ret_ty(self, ret_ty) } - fn visit_fn_header(&mut self, _header: &'ast FnHeader) -> Self::Result { - Self::Result::output() + fn visit_fn_header(&mut self, header: &'ast FnHeader) -> Self::Result { + walk_fn_header(self, header) } fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result { walk_expr_field(self, f) @@ -295,6 +304,15 @@ pub trait Visitor<'ast>: Sized { fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result { Self::Result::output() } + fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result { + Self::Result::output() + } + fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result { + walk_fn_decl(self, fn_decl) + } + fn visit_qself(&mut self, qs: &'ast Option<P<QSelf>>) -> Self::Result { + walk_qself(self, qs) + } } pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { @@ -305,7 +323,7 @@ pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::R } pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result { - let Local { id: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local; + let Local { id: _, super_: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_pat(pat)); visit_opt!(visitor, visit_ty, ty); @@ -317,12 +335,12 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::R } pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result { - visitor.visit_ident(*ident) + visitor.visit_ident(ident) } pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result { let Lifetime { id: _, ident } = lifetime; - visitor.visit_ident(*ident) + visitor.visit_ident(ident) } pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result @@ -340,51 +358,77 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR } impl WalkItemKind for ItemKind { + type Ctxt = (); fn walk<'a, V: Visitor<'a>>( &'a self, - item: &'a Item<Self>, - _ctxt: AssocCtxt, + span: Span, + id: NodeId, + vis: &'a Visibility, + _ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result { - let Item { id, span, vis, ident, .. } = item; match self { - ItemKind::ExternCrate(_rename) => {} - ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, *id, false)), - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::ExternCrate(_rename, ident) => try_visit!(visitor.visit_ident(ident)), + ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)), + ItemKind::Static(box StaticItem { + ident, + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } - ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + ItemKind::Const(box ConstItem { + defaultness: _, + ident, + generics, + ty, + expr, + define_opaque, + }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } - ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref()); - try_visit!(visitor.visit_fn(kind, *span, *id)); + ItemKind::Fn(func) => { + let kind = FnKind::Fn(FnCtxt::Free, vis, &*func); + try_visit!(visitor.visit_fn(kind, span, id)); } - ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { - ModKind::Loaded(items, _inline, _inner_span) => { - walk_list!(visitor, visit_item, items); + ItemKind::Mod(_unsafety, ident, mod_kind) => { + try_visit!(visitor.visit_ident(ident)); + match mod_kind { + ModKind::Loaded(items, _inline, _inner_span, _) => { + walk_list!(visitor, visit_item, items); + } + ModKind::Unloaded => {} } - ModKind::Unloaded => {} - }, - ItemKind::ForeignMod(ForeignMod { safety: _, abi: _, items }) => { + } + ItemKind::ForeignMod(ForeignMod { extern_span: _, safety: _, abi: _, items }) => { walk_list!(visitor, visit_foreign_item, items); } ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), ItemKind::TyAlias(box TyAlias { generics, + ident, bounds, ty, defaultness: _, where_clauses: _, }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); } - ItemKind::Enum(enum_definition, generics) => { + ItemKind::Enum(ident, enum_definition, generics) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_enum_def(enum_definition)); } @@ -401,45 +445,65 @@ impl WalkItemKind for ItemKind { try_visit!(visitor.visit_generics(generics)); visit_opt!(visitor, visit_trait_ref, of_trait); try_visit!(visitor.visit_ty(self_ty)); - walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl); + walk_list!( + visitor, + visit_assoc_item, + items, + AssocCtxt::Impl { of_trait: of_trait.is_some() } + ); } - ItemKind::Struct(struct_definition, generics) - | ItemKind::Union(struct_definition, generics) => { + ItemKind::Struct(ident, struct_definition, generics) + | ItemKind::Union(ident, struct_definition, generics) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_variant_data(struct_definition)); } - ItemKind::Trait(box Trait { safety: _, is_auto: _, generics, bounds, items }) => { + ItemKind::Trait(box Trait { + safety: _, + is_auto: _, + ident, + generics, + bounds, + items, + }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits); walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); } - ItemKind::TraitAlias(generics, bounds) => { + ItemKind::TraitAlias(ident, generics, bounds) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, *id)), + ItemKind::MacroDef(ident, ts) => { + try_visit!(visitor.visit_ident(ident)); + try_visit!(visitor.visit_mac_def(ts, id)) + } ItemKind::Delegation(box Delegation { id, qself, path, + ident, rename, body, from_glob: _, }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); - visit_opt!(visitor, visit_ident, *rename); + try_visit!(visitor.visit_ident(ident)); + visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - try_visit!(walk_qself(visitor, qself)); - try_visit!(visitor.visit_path(prefix, *id)); + try_visit!(visitor.visit_qself(qself)); + try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { - visitor.visit_ident(*ident); + visitor.visit_ident(ident); if let Some(rename) = rename { - visitor.visit_ident(*rename); + visitor.visit_ident(rename); } } } @@ -450,13 +514,6 @@ impl WalkItemKind for ItemKind { } } -pub fn walk_item<'a, V: Visitor<'a>>( - visitor: &mut V, - item: &'a Item<impl WalkItemKind>, -) -> V::Result { - walk_assoc_item(visitor, item, AssocCtxt::Trait /*ignored*/) -} - pub fn walk_enum_def<'a, V: Visitor<'a>>( visitor: &mut V, EnumDef { variants }: &'a EnumDef, @@ -472,7 +529,7 @@ where let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_variant_data(data)); visit_opt!(visitor, visit_variant_discr, disr_expr); V::Result::output() @@ -481,7 +538,7 @@ where pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result { let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_expr(expr)); V::Result::output() } @@ -489,7 +546,7 @@ pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result { let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_pat(pat)); V::Result::output() } @@ -511,15 +568,19 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } = &**function_declaration; walk_list!(visitor, visit_generic_param, generic_params); - try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_fn_decl(decl)); + } + TyKind::UnsafeBinder(binder) => { + walk_list!(visitor, visit_generic_param, &binder.generic_params); + try_visit!(visitor.visit_ty(&binder.inner_ty)); } TyKind::Path(maybe_qself, path) => { - try_visit!(walk_qself(visitor, maybe_qself)); + try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_path(path, *id)); } TyKind::Pat(ty, pat) => { try_visit!(visitor.visit_ty(ty)); - try_visit!(visitor.visit_pat(pat)); + try_visit!(visitor.visit_ty_pat(pat)); } TyKind::Array(ty, length) => { try_visit!(visitor.visit_ty(ty)); @@ -540,6 +601,18 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { V::Result::output() } +pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Result { + let TyPat { id: _, kind, span: _, tokens: _ } = tp; + match kind { + TyPatKind::Range(start, end, _include_end) => { + visit_opt!(visitor, visit_anon_const, start); + visit_opt!(visitor, visit_anon_const, end); + } + TyPatKind::Err(_) => {} + } + V::Result::output() +} + fn walk_qself<'a, V: Visitor<'a>>(visitor: &mut V, qself: &'a Option<P<QSelf>>) -> V::Result { if let Some(qself) = qself { let QSelf { ty, path_span: _, position: _ } = &**qself; @@ -564,10 +637,10 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( match kind { UseTreeKind::Simple(rename) => { // The extra IDs are handled during AST lowering. - visit_opt!(visitor, visit_ident, *rename); + visit_opt!(visitor, visit_ident, rename); } UseTreeKind::Glob => {} - UseTreeKind::Nested { ref items, span: _ } => { + UseTreeKind::Nested { items, span: _ } => { for &(ref nested_tree, nested_id) in items { try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true)); } @@ -581,7 +654,7 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>( segment: &'a PathSegment, ) -> V::Result { let PathSegment { ident, id: _, args } = segment; - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_generic_args, args); V::Result::output() } @@ -627,7 +700,7 @@ pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>( constraint: &'a AssocItemConstraint, ) -> V::Result { let AssocItemConstraint { id: _, ident, gen_args, kind, span: _ } = constraint; - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_generic_args, gen_args); match kind { AssocItemConstraintKind::Equality { term } => match term { @@ -645,16 +718,16 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res let Pat { id, kind, span: _, tokens: _ } = pattern; match kind { PatKind::TupleStruct(opt_qself, path, elems) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_pat, elems); } PatKind::Path(opt_qself, path) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)) } PatKind::Struct(opt_qself, path, fields, _rest) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_pat_field, fields); } @@ -665,15 +738,19 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res try_visit!(visitor.visit_pat(subpattern)); } PatKind::Ident(_bmode, ident, optional_subpattern) => { - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_pat, optional_subpattern); } - PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)), + PatKind::Expr(expression) => try_visit!(visitor.visit_expr(expression)), PatKind::Range(lower_bound, upper_bound, _end) => { visit_opt!(visitor, visit_expr, lower_bound); visit_opt!(visitor, visit_expr, upper_bound); } - PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Guard(subpattern, guard_condition) => { + try_visit!(visitor.visit_pat(subpattern)); + try_visit!(visitor.visit_expr(guard_condition)); + } + PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Err(_guar) => {} PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { walk_list!(visitor, visit_pat, elems); @@ -684,29 +761,42 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res } impl WalkItemKind for ForeignItemKind { + type Ctxt = (); fn walk<'a, V: Visitor<'a>>( &'a self, - item: &'a Item<Self>, - _ctxt: AssocCtxt, + span: Span, + id: NodeId, + vis: &'a Visibility, + _ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result { - let &Item { id, span, ident, ref vis, .. } = item; match self { - ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { + ForeignItemKind::Static(box StaticItem { + ident, + ty, + mutability: _, + expr, + safety: _, + define_opaque, + }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } - ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref()); + ForeignItemKind::Fn(func) => { + let kind = FnKind::Fn(FnCtxt::Foreign, vis, &*func); try_visit!(visitor.visit_fn(kind, span, id)); } ForeignItemKind::TyAlias(box TyAlias { generics, + ident, bounds, ty, defaultness: _, where_clauses: _, }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); @@ -733,14 +823,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>( visitor: &mut V, arg: &'a PreciseCapturingArg, -) { +) -> V::Result { match arg { - PreciseCapturingArg::Lifetime(lt) => { - visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg); - } - PreciseCapturingArg::Arg(path, id) => { - visitor.visit_path(path, *id); - } + PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg), + PreciseCapturingArg::Arg(path, id) => visitor.visit_path(path, *id), } } @@ -751,7 +837,7 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>( let GenericParam { id: _, ident, attrs, bounds, is_placeholder: _, kind, colon_span: _ } = param; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); match kind { GenericParamKind::Lifetime => (), @@ -785,26 +871,45 @@ pub fn walk_closure_binder<'a, V: Visitor<'a>>( V::Result::output() } +pub fn walk_contract<'a, V: Visitor<'a>>(visitor: &mut V, c: &'a FnContract) -> V::Result { + let FnContract { requires, ensures } = c; + if let Some(pred) = requires { + visitor.visit_expr(pred); + } + if let Some(pred) = ensures { + visitor.visit_expr(pred); + } + V::Result::output() +} + pub fn walk_where_predicate<'a, V: Visitor<'a>>( visitor: &mut V, predicate: &'a WherePredicate, ) -> V::Result { - match predicate { - WherePredicate::BoundPredicate(WhereBoundPredicate { + let WherePredicate { attrs, kind, id: _, span: _, is_placeholder: _ } = predicate; + walk_list!(visitor, visit_attribute, attrs); + visitor.visit_where_predicate_kind(kind) +} + +pub fn walk_where_predicate_kind<'a, V: Visitor<'a>>( + visitor: &mut V, + kind: &'a WherePredicateKind, +) -> V::Result { + match kind { + WherePredicateKind::BoundPredicate(WhereBoundPredicate { bounded_ty, bounds, bound_generic_params, - span: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); try_visit!(visitor.visit_ty(bounded_ty)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } - WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span: _ }) => { + WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { try_visit!(visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } - WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span: _ }) => { + WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => { try_visit!(visitor.visit_ty(lhs_ty)); try_visit!(visitor.visit_ty(rhs_ty)); } @@ -820,6 +925,12 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) V::Result::output() } +pub fn walk_fn_header<'a, V: Visitor<'a>>(visitor: &mut V, fn_header: &'a FnHeader) -> V::Result { + let FnHeader { safety: _, coroutine_kind, constness: _, ext: _ } = fn_header; + visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); + V::Result::output() +} + pub fn walk_fn_decl<'a, V: Visitor<'a>>( visitor: &mut V, FnDecl { inputs, output }: &'a FnDecl, @@ -830,16 +941,32 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>( pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result { match kind { - FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body) => { - // Identifier and visibility are visited as a part of the item. + FnKind::Fn( + _ctxt, + _vis, + Fn { + defaultness: _, + ident, + sig: FnSig { header, decl, span: _ }, + generics, + contract, + body, + define_opaque, + }, + ) => { + // Visibility is visited as a part of the item. + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_fn_header(header)); try_visit!(visitor.visit_generics(generics)); - try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_fn_decl(decl)); + visit_opt!(visitor, visit_contract, contract); visit_opt!(visitor, visit_block, body); + try_visit!(walk_define_opaques(visitor, define_opaque)); } - FnKind::Closure(binder, _coroutine_kind, decl, body) => { + FnKind::Closure(binder, coroutine_kind, decl, body) => { try_visit!(visitor.visit_closure_binder(binder)); - try_visit!(walk_fn_decl(visitor, decl)); + visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); + try_visit!(visitor.visit_fn_decl(decl)); try_visit!(visitor.visit_expr(body)); } } @@ -847,32 +974,44 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu } impl WalkItemKind for AssocItemKind { + type Ctxt = AssocCtxt; fn walk<'a, V: Visitor<'a>>( &'a self, - item: &'a Item<Self>, - ctxt: AssocCtxt, + span: Span, + id: NodeId, + vis: &'a Visibility, + ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result { - let &Item { id, span, ident, ref vis, .. } = item; match self { - AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + AssocItemKind::Const(box ConstItem { + defaultness: _, + ident, + generics, + ty, + expr, + define_opaque, + }) => { + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } - AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = - FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref()); + AssocItemKind::Fn(func) => { + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), vis, &*func); try_visit!(visitor.visit_fn(kind, span, id)); } AssocItemKind::Type(box TyAlias { generics, + ident, bounds, ty, defaultness: _, where_clauses: _, }) => { try_visit!(visitor.visit_generics(generics)); + try_visit!(visitor.visit_ident(ident)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); visit_opt!(visitor, visit_ty, ty); } @@ -883,23 +1022,25 @@ impl WalkItemKind for AssocItemKind { id, qself, path, + ident, rename, body, from_glob: _, }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); - visit_opt!(visitor, visit_ident, *rename); + try_visit!(visitor.visit_ident(ident)); + visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { - visitor.visit_ident(*ident); + visitor.visit_ident(ident); if let Some(rename) = rename { - visitor.visit_ident(*rename); + visitor.visit_ident(rename); } } } @@ -910,16 +1051,30 @@ impl WalkItemKind for AssocItemKind { } } +pub fn walk_item<'a, V: Visitor<'a>>( + visitor: &mut V, + item: &'a Item<impl WalkItemKind<Ctxt = ()>>, +) -> V::Result { + walk_item_ctxt(visitor, item, ()) +} + pub fn walk_assoc_item<'a, V: Visitor<'a>>( visitor: &mut V, - item: &'a Item<impl WalkItemKind>, + item: &'a AssocItem, ctxt: AssocCtxt, ) -> V::Result { - let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item; + walk_item_ctxt(visitor, item, ctxt) +} + +fn walk_item_ctxt<'a, V: Visitor<'a>, K: WalkItemKind>( + visitor: &mut V, + item: &'a Item<K>, + ctxt: K::Ctxt, +) -> V::Result { + let Item { id, span, vis, attrs, kind, tokens: _ } = item; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(ident)); - try_visit!(kind.walk(item, ctxt, visitor)); + try_visit!(kind.walk(*span, *id, vis, ctxt, visitor)); V::Result::output() } @@ -932,16 +1087,18 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>( } pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result { - let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field; + let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _, default } = + field; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); - visit_opt!(visitor, visit_ident, *ident); + visit_opt!(visitor, visit_ident, ident); try_visit!(visitor.visit_ty(ty)); + visit_opt!(visitor, visit_anon_const, &*default); V::Result::output() } pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result { - let Block { stmts, id: _, rules: _, span: _, tokens: _, could_be_bare_literal: _ } = block; + let Block { stmts, id: _, rules: _, span: _, tokens: _ } = block; walk_list!(visitor, visit_stmt, stmts); V::Result::output() } @@ -1008,16 +1165,16 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>( visitor: &mut V, InlineAsmSym { id, qself, path }: &'a InlineAsmSym, ) -> V::Result { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); visitor.visit_path(path, *id) } pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) -> V::Result { - let FormatArgs { span: _, template: _, arguments } = fmt; + let FormatArgs { span: _, template: _, arguments, uncooked_fmt_str: _ } = fmt; for FormatArgument { kind, expr } in arguments.all_args() { match kind { FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { - try_visit!(visitor.visit_ident(*ident)) + try_visit!(visitor.visit_ident(ident)) } FormatArgumentKind::Normal => {} } @@ -1040,7 +1197,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Struct(se) => { let StructExpr { qself, path, fields, rest } = &**se; - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_expr_field, fields); match rest { @@ -1119,7 +1276,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id - )) + )); } ExprKind::Block(block, opt_label) => { visit_opt!(visitor, visit_label, opt_label); @@ -1127,6 +1284,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)), ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)), + ExprKind::Use(expr, _span) => try_visit!(visitor.visit_expr(expr)), ExprKind::Assign(lhs, rhs, _span) => { try_visit!(visitor.visit_expr(lhs)); try_visit!(visitor.visit_expr(rhs)); @@ -1137,7 +1295,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Field(subexpression, ident) => { try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); } ExprKind::Index(main_expression, index_expression, _span) => { try_visit!(visitor.visit_expr(main_expression)); @@ -1149,7 +1307,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Underscore => {} ExprKind::Path(maybe_qself, path) => { - try_visit!(walk_qself(visitor, maybe_qself)); + try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_path(path, *id)); } ExprKind::Break(opt_label, opt_expr) => { @@ -1172,20 +1330,24 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::FormatArgs(f) => try_visit!(visitor.visit_format_args(f)), ExprKind::OffsetOf(container, fields) => { try_visit!(visitor.visit_ty(container)); - walk_list!(visitor, visit_ident, fields.iter().copied()); + walk_list!(visitor, visit_ident, fields.iter()); } - ExprKind::Yield(optional_expression) => { - visit_opt!(visitor, visit_expr, optional_expression); + ExprKind::Yield(kind) => { + visit_opt!(visitor, visit_expr, kind.expr()); } ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), ExprKind::Lit(_token) => {} ExprKind::IncludedBytes(_bytes) => {} + ExprKind::UnsafeBinderCast(_kind, expr, ty) => { + try_visit!(visitor.visit_expr(expr)); + visit_opt!(visitor, visit_ty, ty); + } ExprKind::Err(_guar) => {} ExprKind::Dummy => {} } - visitor.visit_expr_post(expression) + V::Result::output() } pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) -> V::Result { @@ -1234,9 +1396,18 @@ pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) - match args { AttrArgs::Empty => {} AttrArgs::Delimited(_args) => {} - AttrArgs::Eq(_eq_span, AttrArgsEq::Ast(expr)) => try_visit!(visitor.visit_expr(expr)), - AttrArgs::Eq(_eq_span, AttrArgsEq::Hir(lit)) => { - unreachable!("in literal form when walking mac args eq: {:?}", lit) + AttrArgs::Eq { expr, .. } => try_visit!(visitor.visit_expr(expr)), + } + V::Result::output() +} + +fn walk_define_opaques<'a, V: Visitor<'a>>( + visitor: &mut V, + define_opaque: &'a Option<ThinVec<(NodeId, Path)>>, +) -> V::Result { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + try_visit!(visitor.visit_path(path, *id)); } } V::Result::output() diff --git a/compiler/rustc_ast_ir/Cargo.toml b/compiler/rustc_ast_ir/Cargo.toml index 1905574073f13..76bdd9f7eb6d3 100644 --- a/compiler/rustc_ast_ir/Cargo.toml +++ b/compiler/rustc_ast_ir/Cargo.toml @@ -1,14 +1,13 @@ [package] name = "rustc_ast_ir" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } -rustc_span = { path = "../rustc_span", optional = true } # tidy-alphabetical-end [features] @@ -17,5 +16,4 @@ nightly = [ "dep:rustc_serialize", "dep:rustc_data_structures", "dep:rustc_macros", - "dep:rustc_span", ] diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index ff9d940ce9f28..0898433a74c53 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -1,19 +1,28 @@ +//! Common utilities shared by both `rustc_ast` and `rustc_type_ir`. +//! +//! Don't depend on this crate directly; both of those crates should re-export +//! the functionality. Additionally, if you're in scope of `rustc_middle`, then +//! prefer imports via that too, to avoid needing to directly depend on (e.g.) +//! `rustc_type_ir` for a single import. + // tidy-alphabetical-start #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(never_type))] #![cfg_attr(feature = "nightly", feature(rustc_attrs))] -#![warn(unreachable_pub)] // tidy-alphabetical-end #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable, HashStable_NoContext}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; pub mod visit; /// The movability of a coroutine / closure literal: /// whether a coroutine contains self-references, causing it to be `!Unpin`. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum Movability { /// May contain self-references, `!Unpin`. Static, @@ -22,7 +31,10 @@ pub enum Movability { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum Mutability { // N.B. Order is deliberate, so that Not < Mut Not, @@ -81,7 +93,10 @@ impl Mutability { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum Pinnedness { Not, Pinned, diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 8cc4521e0a78d..6ac258155fe94 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -1,17 +1,20 @@ [package] name = "rustc_ast_lowering" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] doctest = false [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index a5ee6713be8ed..5ef76fb64aaf2 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -37,18 +37,14 @@ ast_lowering_bad_return_type_notation_inputs = .suggestion = remove the input types ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..` - .suggestion = add `..` + .suggestion = use the correct syntax by adding `..` to the arguments ast_lowering_bad_return_type_notation_output = return type not allowed with return type notation - .suggestion = remove the return type +ast_lowering_bad_return_type_notation_output_suggestion = use the right argument notation and remove the return type ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet -ast_lowering_base_expression_double_dot = - base expression required after `..` - .suggestion = add a base expression here - ast_lowering_clobber_abi_not_supported = `clobber_abi` is not supported on this target @@ -57,6 +53,9 @@ ast_lowering_closure_cannot_be_static = closures cannot be static ast_lowering_coroutine_too_many_parameters = too many parameters for a coroutine (expected 0 or 1 parameters) +ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs + .label = default fields are only supported on structs + ast_lowering_does_not_support_modifiers = the `{$class_name}` register class does not support template modifiers @@ -89,7 +88,7 @@ ast_lowering_invalid_abi_clobber_abi = invalid ABI for `clobber_abi` .note = the following ABIs are supported on this target: {$supported_abis} -ast_lowering_invalid_abi_suggestion = did you mean +ast_lowering_invalid_abi_suggestion = there's a similarly named valid ABI `{$suggestion}` ast_lowering_invalid_asm_template_modifier_const = asm template modifiers are not allowed for `const` arguments @@ -103,11 +102,18 @@ ast_lowering_invalid_asm_template_modifier_reg_class = ast_lowering_invalid_asm_template_modifier_sym = asm template modifiers are not allowed for `sym` arguments +ast_lowering_invalid_legacy_const_generic_arg = + invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + +ast_lowering_invalid_legacy_const_generic_arg_suggestion = + try using a const generic argument instead + ast_lowering_invalid_register = invalid register `{$reg}`: {$error} ast_lowering_invalid_register_class = - invalid register class `{$reg_class}`: {$error} + invalid register class `{$reg_class}`: unknown register class + .note = the following register classes are supported on this target: {$supported_register_classes} ast_lowering_match_arm_with_no_body = `match` arm with no body @@ -135,9 +141,6 @@ ast_lowering_never_pattern_with_guard = ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` -ast_lowering_no_precise_captures_on_rpitit = `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - .note = currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - ast_lowering_previously_used_here = previously used here ast_lowering_register1 = register `{$reg1_name}` @@ -146,6 +149,8 @@ ast_lowering_register2 = register `{$reg2_name}` ast_lowering_register_class_only_clobber = register class `{$reg_class_name}` can only be used as a clobber, not as an input or output +ast_lowering_register_class_only_clobber_stable = + register class `{$reg_class_name}` can only be used as a clobber in stable ast_lowering_register_conflict = register `{$reg1_name}` conflicts with register `{$reg2_name}` @@ -175,8 +180,8 @@ ast_lowering_underscore_expr_lhs_assign = .label = `_` not allowed here ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture -ast_lowering_unstable_inline_assembly_label_operands = - label operands for inline assembly are unstable +ast_lowering_unstable_inline_assembly_label_operand_with_outputs = + using both label and output operands for inline assembly is unstable ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable ast_lowering_use_angle_brackets = use angle brackets instead diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 88cdb2ec36397..af279e07acc6e 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -1,13 +1,11 @@ use std::collections::hash_map::Entry; use std::fmt::Write; -use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_session::parse::feature_err; -use rustc_span::symbol::kw; use rustc_span::{Span, sym}; use rustc_target::asm; @@ -17,7 +15,8 @@ use super::errors::{ InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister, - InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict, + InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable, + RegisterConflict, }; use crate::{ AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, @@ -39,17 +38,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } if let Some(asm_arch) = asm_arch { // Inline assembly is currently only stable for these architectures. + // (See also compiletest's `has_asm_support`.) let is_stable = matches!( asm_arch, asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64 | asm::InlineAsmArch::Arm | asm::InlineAsmArch::AArch64 + | asm::InlineAsmArch::Arm64EC | asm::InlineAsmArch::RiscV32 | asm::InlineAsmArch::RiscV64 | asm::InlineAsmArch::LoongArch64 + | asm::InlineAsmArch::S390x ); - if !is_stable && !self.tcx.features().asm_experimental_arch { + if !is_stable && !self.tcx.features().asm_experimental_arch() { feature_err( &self.tcx.sess, sym::asm_experimental_arch, @@ -59,13 +61,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .emit(); } } + let allow_experimental_reg = self.tcx.features().asm_experimental_reg(); if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64)) && !self.tcx.sess.opts.actually_rustdoc { self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp }); } - if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind { + if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind() { feature_err( &self.tcx.sess, sym::asm_unwind, @@ -78,7 +81,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut clobber_abis = FxIndexMap::default(); if let Some(asm_arch) = asm_arch { for (abi_name, abi_span) in &asm.clobber_abis { - match asm::InlineAsmClobberAbi::parse(asm_arch, &self.tcx.sess.target, *abi_name) { + match asm::InlineAsmClobberAbi::parse( + asm_arch, + &self.tcx.sess.target, + &self.tcx.sess.unstable_target_features, + *abi_name, + ) { Ok(abi) => { // If the abi was already in the list, emit an error match clobber_abis.get(&abi) { @@ -144,11 +152,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { InlineAsmRegOrRegClass::RegClass(reg_class) => { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else( - |error| { + |supported_register_classes| { + let mut register_classes = + format!("`{}`", supported_register_classes[0]); + for m in &supported_register_classes[1..] { + let _ = write!(register_classes, ", `{m}`"); + } self.dcx().emit_err(InvalidRegisterClass { op_span: *op_sp, reg_class, - error, + supported_register_classes: register_classes, }); asm::InlineAsmRegClass::Err }, @@ -183,7 +196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } InlineAsmOperand::Const { anon_const } => hir::InlineAsmOperand::Const { - anon_const: self.lower_anon_const_to_anon_const(anon_const), + anon_const: self.lower_const_block(anon_const), }, InlineAsmOperand::Sym { sym } => { let static_def_id = self @@ -217,35 +230,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { tokens: None, }; - // Wrap the expression in an AnonConst. - let parent_def_id = self.current_def_id_parent; - let node_id = self.next_node_id(); - // HACK(min_generic_const_args): see lower_anon_const - if !expr.is_potential_trivial_const_arg(true) { - self.create_def( - parent_def_id, - node_id, - kw::Empty, - DefKind::AnonConst, - *op_sp, - ); - } - let anon_const = AnonConst { id: node_id, value: P(expr) }; - hir::InlineAsmOperand::SymFn { - anon_const: self.lower_anon_const_to_anon_const(&anon_const), - } + hir::InlineAsmOperand::SymFn { expr: self.lower_expr(&expr) } } } InlineAsmOperand::Label { block } => { - if !self.tcx.features().asm_goto { - feature_err( - sess, - sym::asm_goto, - *op_sp, - fluent::ast_lowering_unstable_inline_assembly_label_operands, - ) - .emit(); - } hir::InlineAsmOperand::Label { block: self.lower_block(block, false) } } }; @@ -331,11 +319,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // means that we disallow passing a value in/out of the asm and // require that the operand name an explicit register, not a // register class. - if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() { - self.dcx().emit_err(RegisterClassOnlyClobber { - op_span: op_sp, - reg_class_name: reg_class.name(), - }); + if reg_class.is_clobber_only(asm_arch.unwrap(), allow_experimental_reg) + && !op.is_clobber() + { + if allow_experimental_reg || reg_class.is_clobber_only(asm_arch.unwrap(), true) + { + // always clobber-only + self.dcx().emit_err(RegisterClassOnlyClobber { + op_span: op_sp, + reg_class_name: reg_class.name(), + }); + } else { + // clobber-only in stable + self.tcx + .sess + .create_feature_err( + RegisterClassOnlyClobberStable { + op_span: op_sp, + reg_class_name: reg_class.name(), + }, + sym::asm_experimental_reg, + ) + .emit(); + } continue; } @@ -464,6 +470,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + // Feature gate checking for `asm_goto_with_outputs`. + if let Some((_, op_sp)) = + operands.iter().find(|(op, _)| matches!(op, hir::InlineAsmOperand::Label { .. })) + { + // Check if an output operand is used. + let output_operand_used = operands.iter().any(|(op, _)| { + matches!( + op, + hir::InlineAsmOperand::Out { expr: Some(_), .. } + | hir::InlineAsmOperand::InOut { .. } + | hir::InlineAsmOperand::SplitInOut { out_expr: Some(_), .. } + ) + }); + if output_operand_used && !self.tcx.features().asm_goto_with_outputs() { + feature_err( + sess, + sym::asm_goto_with_outputs, + *op_sp, + fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs, + ) + .emit(); + } + } + let operands = self.arena.alloc_from_iter(operands); let template = self.arena.alloc_from_iter(asm.template.iter().cloned()); let template_strs = self.arena.alloc_from_iter( diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 9d2b5690c23d9..c3222b79e55c9 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -1,5 +1,6 @@ use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind}; use rustc_hir as hir; +use rustc_span::sym; use smallvec::SmallVec; use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext}; @@ -10,17 +11,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { b: &Block, targeted_by_break: bool, ) -> &'hir hir::Block<'hir> { - self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break)) + let hir_id = self.lower_node_id(b.id); + self.arena.alloc(self.lower_block_noalloc(hir_id, b, targeted_by_break)) } pub(super) fn lower_block_noalloc( &mut self, + hir_id: hir::HirId, b: &Block, targeted_by_break: bool, ) -> hir::Block<'hir> { let (stmts, expr) = self.lower_stmts(&b.stmts); let rules = self.lower_block_check_mode(&b.rules); - let hir_id = self.lower_node_id(b.id); hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break } } @@ -81,11 +83,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (self.arena.alloc_from_iter(stmts), expr) } + /// Return an `ImplTraitContext` that allows impl trait in bindings if + /// the feature gate is enabled, or issues a feature error if it is not. + fn impl_trait_in_bindings_ctxt(&self, position: ImplTraitPosition) -> ImplTraitContext { + if self.tcx.features().impl_trait_in_bindings() { + ImplTraitContext::InBinding + } else { + ImplTraitContext::FeatureGated(position, sym::impl_trait_in_bindings) + } + } + fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> { - let ty = l - .ty - .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); + // Let statements are allowed to have impl trait in bindings. + let super_ = l.super_; + let ty = l.ty.as_ref().map(|t| { + self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) + }); let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); let pat = self.lower_pat(&l.pat); @@ -96,8 +109,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs); - self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source }) + self.lower_attrs(hir_id, &l.attrs, l.span); + self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode { diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 3b85f1737bdd9..93c627f64c967 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -41,14 +41,13 @@ use std::iter; use ast::visit::Visitor; use hir::def::{DefKind, PartialRes, Res}; use hir::{BodyId, HirId}; +use rustc_abi::ExternAbi; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_middle::ty::{Asyncness, ResolverAstLowering}; -use rustc_span::Span; -use rustc_span::symbol::Ident; -use rustc_target::spec::abi; +use rustc_span::{Ident, Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; @@ -57,29 +56,38 @@ use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt}; pub(crate) struct DelegationResults<'hir> { pub body_id: hir::BodyId, pub sig: hir::FnSig<'hir>, + pub ident: Ident, pub generics: &'hir hir::Generics<'hir>, } impl<'hir> LoweringContext<'_, 'hir> { - pub(crate) fn delegation_has_self(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool { - let sig_id = self.get_delegation_sig_id(item_id, path_id, span); + /// Defines whether the delegatee is an associated function whose first parameter is `self`. + pub(crate) fn delegatee_is_method( + &self, + item_id: NodeId, + path_id: NodeId, + span: Span, + is_in_trait_impl: bool, + ) -> bool { + let sig_id = self.get_delegation_sig_id(item_id, path_id, span, is_in_trait_impl); let Ok(sig_id) = sig_id else { return false; }; - self.has_self(sig_id, span) + self.is_method(sig_id, span) } - fn has_self(&self, def_id: DefId, span: Span) -> bool { - if let Some(local_sig_id) = def_id.as_local() { - // The value may be missing due to recursive delegation. - // Error will be emitted later during HIR ty lowering. - self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self) - } else { - match self.tcx.def_kind(def_id) { - DefKind::Fn => false, - DefKind::AssocFn => self.tcx.associated_item(def_id).fn_has_self_parameter, - _ => span_bug!(span, "unexpected DefKind for delegation item"), - } + fn is_method(&self, def_id: DefId, span: Span) -> bool { + match self.tcx.def_kind(def_id) { + DefKind::Fn => false, + DefKind::AssocFn => match def_id.as_local() { + Some(local_def_id) => self + .resolver + .delegation_fn_sigs + .get(&local_def_id) + .is_some_and(|sig| sig.has_self), + None => self.tcx.associated_item(def_id).is_method(), + }, + _ => span_bug!(span, "unexpected DefKind for delegation item"), } } @@ -87,18 +95,19 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, delegation: &Delegation, item_id: NodeId, + is_in_trait_impl: bool, ) -> DelegationResults<'hir> { let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); - let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span); + let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl); match sig_id { Ok(sig_id) => { let (param_count, c_variadic) = self.param_count(sig_id); let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span); let sig = self.lower_delegation_sig(sig_id, decl, span); let body_id = self.lower_delegation_body(delegation, param_count, span); - + let ident = self.lower_ident(delegation.ident); let generics = self.lower_delegation_generics(span); - DelegationResults { body_id, sig, generics } + DelegationResults { body_id, sig, ident, generics } } Err(err) => self.generate_delegation_error(err, span), } @@ -109,8 +118,9 @@ impl<'hir> LoweringContext<'_, 'hir> { item_id: NodeId, path_id: NodeId, span: Span, + is_in_trait_impl: bool, ) -> Result<DefId, ErrorGuaranteed> { - let sig_id = if self.is_in_trait_impl { item_id } else { path_id }; + let sig_id = if is_in_trait_impl { item_id } else { path_id }; self.get_resolution_id(sig_id, span) } @@ -189,7 +199,19 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FnSig<'hir> { let header = if let Some(local_sig_id) = sig_id.as_local() { match self.resolver.delegation_fn_sigs.get(&local_sig_id) { - Some(sig) => self.lower_fn_header(sig.header, hir::Safety::Safe), + Some(sig) => { + let parent = self.tcx.parent(sig_id); + // HACK: we override the default safety instead of generating attributes from the ether. + // We are not forwarding the attributes, as the delegation fn sigs are collected on the ast, + // and here we need the hir attributes. + let default_safety = + if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod { + hir::Safety::Unsafe + } else { + hir::Safety::Safe + }; + self.lower_fn_header(sig.header, default_safety, &[]) + } None => self.generate_header_error(), } } else { @@ -199,7 +221,11 @@ impl<'hir> LoweringContext<'_, 'hir> { Asyncness::No => hir::IsAsync::NotAsync, }; hir::FnHeader { - safety: sig.safety, + safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features { + hir::HeaderSafety::SafeTargetFeatures + } else { + hir::HeaderSafety::Normal(sig.safety) + }, constness: self.tcx.constness(sig_id), asyncness, abi: sig.abi, @@ -208,12 +234,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::FnSig { decl, header, span } } - fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) { + fn generate_param(&mut self, idx: usize, span: Span) -> (hir::Param<'hir>, NodeId) { let pat_node_id = self.next_node_id(); let pat_id = self.lower_node_id(pat_node_id); + let ident = Ident::with_dummy_span(Symbol::intern(&format!("arg{idx}"))); let pat = self.arena.alloc(hir::Pat { hir_id: pat_id, - kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, Ident::empty(), None), + kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None), span, default_binding_modes: false, }); @@ -221,9 +248,9 @@ impl<'hir> LoweringContext<'_, 'hir> { (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id) } - fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> { + fn generate_arg(&mut self, idx: usize, param_id: HirId, span: Span) -> hir::Expr<'hir> { let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment { - ident: Ident::empty(), + ident: Ident::with_dummy_span(Symbol::intern(&format!("arg{idx}"))), hir_id: self.next_id(), res: Res::Local(param_id), args: None, @@ -247,7 +274,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count); for idx in 0..param_count { - let (param, pat_node_id) = this.generate_param(span); + let (param, pat_node_id) = this.generate_param(idx, span); parameters.push(param); let arg = if let Some(block) = block @@ -259,10 +286,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self_param_id: pat_node_id, }; self_resolver.visit_block(block); + // Target expr needs to lower `self` path. + this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id); this.lower_target_expr(&block) } else { - let pat_hir_id = this.lower_node_id(pat_node_id); - this.generate_arg(pat_hir_id, span) + this.generate_arg(idx, param.pat.hir_id, span) }; args.push(arg); } @@ -313,10 +341,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let call = if self .get_resolution_id(delegation.id, span) - .and_then(|def_id| Ok(self.has_self(def_id, span))) + .and_then(|def_id| Ok(self.is_method(def_id, span))) .unwrap_or_default() && delegation.qself.is_none() && !has_generic_args + && !args.is_empty() { let ast_segment = delegation.path.segments.last().unwrap(); let segment = self.lower_path_segment( @@ -378,16 +407,17 @@ impl<'hir> LoweringContext<'_, 'hir> { let header = self.generate_header_error(); let sig = hir::FnSig { decl, header, span }; + let ident = Ident::dummy(); let body_id = self.lower_body(|this| (&[], this.mk_expr(hir::ExprKind::Err(err), span))); - DelegationResults { generics, body_id, sig } + DelegationResults { ident, generics, body_id, sig } } fn generate_header_error(&self) -> hir::FnHeader { hir::FnHeader { - safety: hir::Safety::Safe, + safety: hir::Safety::Safe.into(), constness: hir::Constness::NotConst, asyncness: hir::IsAsync::NotAsync, - abi: abi::Abi::Rust, + abi: ExternAbi::Rust, } } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 6b39c2d39556c..576fa9731e906 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,8 +1,7 @@ +use rustc_errors::DiagArgFromDisplay; use rustc_errors::codes::*; -use rustc_errors::{Diag, DiagArgFromDisplay, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::symbol::Ident; -use rustc_span::{Span, Symbol}; +use rustc_span::{Ident, Span, Symbol}; #[derive(Diagnostic)] #[diag(ast_lowering_generic_type_with_parentheses, code = E0214)] @@ -33,29 +32,23 @@ pub(crate) struct InvalidAbi { pub abi: Symbol, pub command: String, #[subdiagnostic] - pub explain: Option<InvalidAbiReason>, - #[subdiagnostic] pub suggestion: Option<InvalidAbiSuggestion>, } -pub(crate) struct InvalidAbiReason(pub &'static str); - -impl Subdiagnostic for InvalidAbiReason { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { - #[allow(rustc::untranslatable_diagnostic)] - diag.note(self.0); - } +#[derive(Diagnostic)] +#[diag(ast_lowering_default_field_in_tuple)] +pub(crate) struct TupleStructWithDefault { + #[primary_span] + #[label] + pub span: Span, } #[derive(Subdiagnostic)] #[suggestion( ast_lowering_invalid_abi_suggestion, - code = "{suggestion}", - applicability = "maybe-incorrect" + code = "\"{suggestion}\"", + applicability = "maybe-incorrect", + style = "verbose" )] pub(crate) struct InvalidAbiSuggestion { #[primary_span] @@ -114,14 +107,6 @@ pub(crate) struct UnderscoreExprLhsAssign { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_lowering_base_expression_double_dot, code = E0797)] -pub(crate) struct BaseExpressionDoubleDot { - #[primary_span] - #[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)] pub(crate) struct AwaitOnlyInAsyncFnAndBlocks { @@ -213,12 +198,13 @@ pub(crate) struct InvalidRegister<'a> { } #[derive(Diagnostic)] +#[note] #[diag(ast_lowering_invalid_register_class)] -pub(crate) struct InvalidRegisterClass<'a> { +pub(crate) struct InvalidRegisterClass { #[primary_span] pub op_span: Span, pub reg_class: Symbol, - pub error: &'a str, + pub supported_register_classes: String, } #[derive(Diagnostic)] @@ -279,6 +265,14 @@ pub(crate) struct RegisterClassOnlyClobber { pub reg_class_name: Symbol, } +#[derive(Diagnostic)] +#[diag(ast_lowering_register_class_only_clobber_stable)] +pub(crate) struct RegisterClassOnlyClobberStable { + #[primary_span] + pub op_span: Span, + pub reg_class_name: Symbol, +} + #[derive(Diagnostic)] #[diag(ast_lowering_register_conflict)] pub(crate) struct RegisterConflict<'a> { @@ -379,24 +373,39 @@ pub(crate) struct InclusiveRangeWithNoEnd { pub span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + ast_lowering_bad_return_type_notation_output_suggestion, + applicability = "machine-applicable", + style = "verbose" +)] +/// Given `T: Tr<m() -> Ret>` or `T: Tr<m(Ty) -> Ret>`, suggest `T: Tr<m(..)>`. +pub(crate) struct RTNSuggestion { + #[suggestion_part(code = "")] + pub output: Span, + #[suggestion_part(code = "(..)")] + pub input: Span, +} + #[derive(Diagnostic)] pub(crate) enum BadReturnTypeNotation { #[diag(ast_lowering_bad_return_type_notation_inputs)] Inputs { #[primary_span] - #[suggestion(code = "()", applicability = "maybe-incorrect")] + #[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")] span: Span, }, #[diag(ast_lowering_bad_return_type_notation_output)] Output { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] span: Span, + #[subdiagnostic] + suggestion: RTNSuggestion, }, #[diag(ast_lowering_bad_return_type_notation_needs_dots)] NeedsDots { #[primary_span] - #[suggestion(code = "(..)", applicability = "maybe-incorrect")] + #[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")] span: Span, }, #[diag(ast_lowering_bad_return_type_notation_position)] @@ -436,18 +445,33 @@ pub(crate) struct NoPreciseCapturesOnApit { } #[derive(Diagnostic)] -#[diag(ast_lowering_no_precise_captures_on_rpitit)] -#[note] -pub(crate) struct NoPreciseCapturesOnRpitit { +#[diag(ast_lowering_yield_in_closure)] +pub(crate) struct YieldInClosure { #[primary_span] pub span: Span, + #[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")] + pub suggestion: Option<Span>, } #[derive(Diagnostic)] -#[diag(ast_lowering_yield_in_closure)] -pub(crate) struct YieldInClosure { +#[diag(ast_lowering_invalid_legacy_const_generic_arg)] +pub(crate) struct InvalidLegacyConstGenericArg { #[primary_span] pub span: Span, - #[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")] - pub suggestion: Option<Span>, + #[subdiagnostic] + pub suggestion: UseConstGenericArg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + ast_lowering_invalid_legacy_const_generic_arg_suggestion, + applicability = "maybe-incorrect" +)] +pub(crate) struct UseConstGenericArg { + #[suggestion_part(code = "::<{const_args}>")] + pub end_of_fn: Span, + pub const_args: String, + pub other_args: String, + #[suggestion_part(code = "{other_args}")] + pub call_args: Span, } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index ae1e1b3f8a21d..8e1a3cd14354b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,30 +1,57 @@ use std::assert_matches::assert_matches; +use std::ops::ControlFlow; +use std::sync::Arc; use rustc_ast::ptr::P as AstP; use rustc_ast::*; +use rustc_ast_pretty::pprust::expr_to_string; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; use rustc_middle::span_bug; +use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, DesugaringKind, Span}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; +use visit::{Visitor, walk_expr}; use super::errors::{ - AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, - ClosureCannotBeStatic, CoroutineTooManyParameters, - FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, - NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, + AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, ClosureCannotBeStatic, + CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment, + InclusiveRangeWithNoEnd, MatchArmWithNoBody, NeverPatternWithBody, NeverPatternWithGuard, + UnderscoreExprLhsAssign, }; use super::{ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::errors::YieldInClosure; +use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure}; use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated}; +struct WillCreateDefIdsVisitor {} + +impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor { + type Result = ControlFlow<Span>; + + fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { + ControlFlow::Break(c.value.span) + } + + fn visit_item(&mut self, item: &'v Item) -> Self::Result { + ControlFlow::Break(item.span) + } + + fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result { + match ex.kind { + ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => { + ControlFlow::Break(ex.span) + } + _ => walk_expr(self, ex), + } + } +} + impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] { self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x))) @@ -47,15 +74,16 @@ impl<'hir> LoweringContext<'_, 'hir> { // Merge attributes into the inner expression. if !e.attrs.is_empty() { let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); - self.attrs.insert( - ex.hir_id.local_id, - &*self.arena.alloc_from_iter( - e.attrs - .iter() - .map(|a| self.lower_attr(a)) - .chain(old_attrs.iter().cloned()), - ), + let attrs = &*self.arena.alloc_from_iter( + self.lower_attrs_vec(&e.attrs, e.span) + .into_iter() + .chain(old_attrs.iter().cloned()), ); + if attrs.is_empty() { + return ex; + } + + self.attrs.insert(ex.hir_id.local_id, attrs); } return ex; } @@ -70,27 +98,15 @@ impl<'hir> LoweringContext<'_, 'hir> { _ => (), } - let hir_id = self.lower_node_id(e.id); - self.lower_attrs(hir_id, &e.attrs); + let expr_hir_id = self.lower_node_id(e.id); + self.lower_attrs(expr_hir_id, &e.attrs, e.span); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), - ExprKind::ConstBlock(c) => { - let c = self.with_new_scopes(c.value.span, |this| { - let def_id = this.local_def_id(c.id); - hir::ConstBlock { - def_id, - hir_id: this.lower_node_id(c.id), - body: this.with_def_id_parent(def_id, |this| { - this.lower_const_body(c.value.span, Some(&c.value)) - }), - } - }); - hir::ExprKind::ConstBlock(c) - } + ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)), ExprKind::Repeat(expr, count) => { let expr = self.lower_expr(expr); - let count = self.lower_array_length(count); + let count = self.lower_array_length_to_const_arg(count); hir::ExprKind::Repeat(expr, count) } ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), @@ -128,22 +144,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let ohs = self.lower_expr(ohs); hir::ExprKind::Unary(op, ohs) } - ExprKind::Lit(token_lit) => { - let lit_kind = match LitKind::from_token_lit(*token_lit) { - Ok(lit_kind) => lit_kind, - Err(err) => { - let guar = - report_lit_error(&self.tcx.sess.psess, err, *token_lit, e.span); - LitKind::Err(guar) - } - }; - let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind)); - hir::ExprKind::Lit(lit) - } + ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)), ExprKind::IncludedBytes(bytes) => { let lit = self.arena.alloc(respan( self.lower_span(e.span), - LitKind::ByteStr(bytes.clone(), StrStyle::Cooked), + LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked), )); hir::ExprKind::Lit(lit) } @@ -175,18 +180,25 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::If(cond, then, else_opt) => { self.lower_expr_if(cond, then, else_opt.as_deref()) } - ExprKind::While(cond, body, opt_label) => self.with_loop_scope(e.id, |this| { - let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); - this.lower_expr_while_in_loop_scope(span, cond, body, *opt_label) - }), - ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(e.id, |this| { - hir::ExprKind::Loop( - this.lower_block(body, false), - this.lower_label(*opt_label), - hir::LoopSource::Loop, - this.lower_span(*span), - ) - }), + ExprKind::While(cond, body, opt_label) => { + self.with_loop_scope(expr_hir_id, |this| { + let span = + this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) + }) + } + ExprKind::Loop(body, opt_label, span) => { + self.with_loop_scope(expr_hir_id, |this| { + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + hir::ExprKind::Loop( + this.lower_block(body, false), + opt_label, + hir::LoopSource::Loop, + this.lower_span(*span), + ) + }) + } ExprKind::TryBlock(body) => self.lower_expr_try_block(body), ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match( self.lower_expr(expr), @@ -197,6 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ), ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), + ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr), ExprKind::Closure(box Closure { binder, capture_clause, @@ -212,7 +225,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, - hir_id, + expr_hir_id, *coroutine_kind, fn_decl, body, @@ -223,7 +236,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, - hir_id, + expr_hir_id, *constness, *movability, fn_decl, @@ -250,12 +263,20 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Block(blk, opt_label) => { - let opt_label = self.lower_label(*opt_label); - hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label) + // Different from loops, label of block resolves to block id rather than + // expr node id. + let block_hir_id = self.lower_node_id(blk.id); + let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id); + let hir_block = self.arena.alloc(self.lower_block_noalloc( + block_hir_id, + blk, + opt_label.is_some(), + )); + hir::ExprKind::Block(hir_block, opt_label) } ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span), ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp( - self.lower_binop(*op), + self.lower_assign_op(*op), self.lower_expr(el), self.lower_expr(er), ), @@ -265,9 +286,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Index(el, er, brackets_span) => { hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span) } - ExprKind::Range(Some(e1), Some(e2), RangeLimits::Closed) => { - self.lower_expr_range_closed(e.span, e1, e2) - } ExprKind::Range(e1, e2, lims) => { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims) } @@ -295,8 +313,8 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label)) } ExprKind::Ret(e) => { - let e = e.as_ref().map(|x| self.lower_expr(x)); - hir::ExprKind::Ret(e) + let expr = e.as_ref().map(|x| self.lower_expr(x)); + self.checked_return(expr) } ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()), ExprKind::Become(sub_expr) => { @@ -316,12 +334,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ExprKind::Struct(se) => { let rest = match &se.rest { - StructRest::Base(e) => Some(self.lower_expr(e)), - StructRest::Rest(sp) => { - let guar = self.dcx().emit_err(BaseExpressionDoubleDot { span: *sp }); - Some(&*self.arena.alloc(self.expr_err(*sp, guar))) - } - StructRest::None => None, + StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)), + StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(*sp), + StructRest::None => hir::StructTailExpr::None, }; hir::ExprKind::Struct( self.arena.alloc(self.lower_qpath( @@ -338,9 +353,17 @@ impl<'hir> LoweringContext<'_, 'hir> { rest, ) } - ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), + ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)), ExprKind::Err(guar) => hir::ExprKind::Err(*guar), + ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast( + *kind, + self.lower_expr(expr), + ty.as_ref().map(|ty| { + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)) + }), + ), + ExprKind::Dummy => { span_bug!(e.span, "lowered ExprKind::Dummy") } @@ -354,10 +377,66 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), }; - hir::Expr { hir_id, kind, span: self.lower_span(e.span) } + hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) } }) } + /// Create an `ExprKind::Ret` that is optionally wrapped by a call to check + /// a contract ensures clause, if it exists. + fn checked_return(&mut self, opt_expr: Option<&'hir hir::Expr<'hir>>) -> hir::ExprKind<'hir> { + let checked_ret = + if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures { + let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span)); + Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id)) + } else { + opt_expr + }; + hir::ExprKind::Ret(checked_ret) + } + + /// Wraps an expression with a call to the ensures check before it gets returned. + pub(crate) fn inject_ensures_check( + &mut self, + expr: &'hir hir::Expr<'hir>, + span: Span, + cond_ident: Ident, + cond_hir_id: HirId, + ) -> &'hir hir::Expr<'hir> { + let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id); + let call_expr = self.expr_call_lang_item_fn_mut( + span, + hir::LangItem::ContractCheckEnsures, + arena_vec![self; *cond_fn, *expr], + ); + self.arena.alloc(call_expr) + } + + pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock { + self.with_new_scopes(c.value.span, |this| { + let def_id = this.local_def_id(c.id); + hir::ConstBlock { + def_id, + hir_id: this.lower_node_id(c.id), + body: this.lower_const_body(c.value.span, Some(&c.value)), + } + }) + } + + pub(crate) fn lower_lit( + &mut self, + token_lit: &token::Lit, + span: Span, + ) -> &'hir Spanned<LitKind> { + let lit_kind = match LitKind::from_token_lit(*token_lit) { + Ok(lit_kind) => lit_kind, + Err(err) => { + let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span); + LitKind::Err(guar) + } + }; + self.arena.alloc(respan(self.lower_span(span), lit_kind)) + } + fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { match u { UnOp::Deref => hir::UnOp::Deref, @@ -370,6 +449,10 @@ impl<'hir> LoweringContext<'_, 'hir> { Spanned { node: b.node, span: self.lower_span(b.span) } } + fn lower_assign_op(&mut self, a: AssignOp) -> AssignOp { + Spanned { node: a.node, span: self.lower_span(a.span) } + } + fn lower_legacy_const_generics( &mut self, mut f: Expr, @@ -380,21 +463,52 @@ impl<'hir> LoweringContext<'_, 'hir> { unreachable!(); }; + let mut error = None; + let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| { + // Avoid emitting the error multiple times. + if error.is_none() { + let mut const_args = vec![]; + let mut other_args = vec![]; + for (idx, arg) in args.iter().enumerate() { + if legacy_args_idx.contains(&idx) { + const_args.push(format!("{{ {} }}", expr_to_string(arg))); + } else { + other_args.push(expr_to_string(arg)); + } + } + let suggestion = UseConstGenericArg { + end_of_fn: f.span.shrink_to_hi(), + const_args: const_args.join(", "), + other_args: other_args.join(", "), + call_args: args[0].span.to(args.last().unwrap().span), + }; + error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion })); + } + error.unwrap() + }; + // Split the arguments into const generics and normal arguments let mut real_args = vec![]; let mut generic_args = ThinVec::new(); - for (idx, arg) in args.into_iter().enumerate() { + for (idx, arg) in args.iter().cloned().enumerate() { if legacy_args_idx.contains(&idx) { - let parent_def_id = self.current_def_id_parent; + let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); + self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span); + let mut visitor = WillCreateDefIdsVisitor {}; + let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { + AstP(Expr { + id: self.next_node_id(), + kind: ExprKind::Err(invalid_expr_error(self.tcx, span)), + span: f.span, + attrs: [].into(), + tokens: None, + }) + } else { + arg + }; - // HACK(min_generic_const_args): see lower_anon_const - if !arg.is_potential_trivial_const_arg(true) { - // Add a definition for the in-band const def. - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); - } - - let anon_const = AnonConst { id: node_id, value: arg }; + let anon_const = AnonConst { id: node_id, value: const_value }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); } else { real_args.push(arg); @@ -504,7 +618,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let if_expr = self.expr(span, if_kind); let block = self.block_expr(self.arena.alloc(if_expr)); let span = self.lower_span(span.with_hi(cond.span.hi())); - let opt_label = self.lower_label(opt_label); hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span) } @@ -512,8 +625,9 @@ impl<'hir> LoweringContext<'_, 'hir> { /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { - self.with_catch_scope(body.id, |this| { - let mut block = this.lower_block_noalloc(body, true); + let body_hir_id = self.lower_node_id(body.id); + self.with_catch_scope(body_hir_id, |this| { + let mut block = this.lower_block_noalloc(body_hir_id, body, true); // Final expression of the block (if present) or `()` with span at the end of block let (try_span, tail_expr) = if let Some(expr) = block.expr.take() { @@ -521,7 +635,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.mark_span_with_reason( DesugaringKind::TryBlock, expr.span, - Some(this.allow_try_trait.clone()), + Some(Arc::clone(&this.allow_try_trait)), ), expr, ) @@ -529,7 +643,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let try_span = this.mark_span_with_reason( DesugaringKind::TryBlock, this.tcx.sess.source_map().end_point(body.span), - Some(this.allow_try_trait.clone()), + Some(Arc::clone(&this.allow_try_trait)), ); (try_span, this.expr_unit(try_span)) @@ -566,16 +680,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs); + self.lower_attrs(hir_id, &arm.attrs, arm.span); let is_never_pattern = pat.is_never_pattern(); - let body = if let Some(body) = &arm.body + // We need to lower the body even if it's unneeded for never pattern in match, + // ensure that we can get HirId for DefId if need (issue #137708). + let body = arm.body.as_ref().map(|x| self.lower_expr(x)); + let body = if let Some(body) = body && !is_never_pattern { - self.lower_expr(body) + body } else { // Either `body.is_none()` or `is_never_pattern` here. if !is_never_pattern { - if self.tcx.features().never_patterns { + if self.tcx.features().never_patterns() { // If the feature is off we already emitted the error after parsing. let suggestion = span.shrink_to_hi(); self.dcx().emit_err(MatchArmWithNoBody { span, suggestion }); @@ -638,7 +755,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, self.lower_span(span), - Some(self.allow_gen_future.clone()), + Some(Arc::clone(&self.allow_gen_future)), ); let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None); @@ -679,19 +796,17 @@ impl<'hir> LoweringContext<'_, 'hir> { lifetime_elision_allowed: false, }); - let body = self.with_def_id_parent(closure_def_id, move |this| { - this.lower_body(move |this| { - this.coroutine_kind = Some(coroutine_kind); + let body = self.lower_body(move |this| { + this.coroutine_kind = Some(coroutine_kind); - let old_ctx = this.task_context; - if task_context.is_some() { - this.task_context = task_context; - } - let res = body(this); - this.task_context = old_ctx; + let old_ctx = this.task_context; + if task_context.is_some() { + this.task_context = task_context; + } + let res = body(this); + this.task_context = old_ctx; - (params, res) - }) + (params, res) }); // `static |<_task_context?>| -> <return_ty> { <body> }`: @@ -717,24 +832,28 @@ impl<'hir> LoweringContext<'_, 'hir> { outer_hir_id: HirId, inner_hir_id: HirId, ) { - if self.tcx.features().async_fn_track_caller + if self.tcx.features().async_fn_track_caller() && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, span, - Some(self.allow_gen_future.clone()), + Some(Arc::clone(&self.allow_gen_future)), + ); + self.lower_attrs( + inner_hir_id, + &[Attribute { + kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( + sym::track_caller, + span, + )))), + id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(), + style: AttrStyle::Outer, + span: unstable_span, + }], + span, ); - self.lower_attrs(inner_hir_id, &[Attribute { - kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( - sym::track_caller, - span, - )))), - id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(), - style: AttrStyle::Outer, - span: unstable_span, - }]); } } @@ -800,13 +919,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let features = match await_kind { FutureKind::Future => None, - FutureKind::AsyncIterator => Some(self.allow_for_await.clone()), + FutureKind::AsyncIterator => Some(Arc::clone(&self.allow_for_await)), }; let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features); let gen_future_span = self.mark_span_with_reason( DesugaringKind::Await, full_span, - Some(self.allow_gen_future.clone()), + Some(Arc::clone(&self.allow_gen_future)), ); let expr_hir_id = expr.hir_id; @@ -869,7 +988,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid); let ready_field = self.single_pat_field(gen_future_span, x_pat); let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); - let break_x = self.with_loop_scope(loop_node_id, move |this| { + let break_x = self.with_loop_scope(loop_hir_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); this.arena.alloc(this.expr(gen_future_span, expr_break)) @@ -959,6 +1078,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } + fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { + hir::ExprKind::Use(self.lower_expr(expr), use_kw_span) + } + fn lower_expr_closure( &mut self, binder: &ClosureBinder, @@ -976,26 +1099,25 @@ impl<'hir> LoweringContext<'_, 'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { - this.with_def_id_parent(closure_def_id, move |this| { - let mut coroutine_kind = if this - .attrs - .get(&closure_hir_id.local_id) - .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) - { - Some(hir::CoroutineKind::Coroutine(Movability::Movable)) - } else { - None - }; - let body_id = this.lower_fn_body(decl, |this| { - this.coroutine_kind = coroutine_kind; - let e = this.lower_expr_mut(body); - coroutine_kind = this.coroutine_kind; - e - }); - let coroutine_option = - this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability); - (body_id, coroutine_option) - }) + let mut coroutine_kind = if this + .attrs + .get(&closure_hir_id.local_id) + .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) + { + Some(hir::CoroutineKind::Coroutine(Movability::Movable)) + } else { + None + }; + // FIXME(contracts): Support contracts on closures? + let body_id = this.lower_fn_body(decl, None, |this| { + this.coroutine_kind = coroutine_kind; + let e = this.lower_expr_mut(body); + coroutine_kind = this.coroutine_kind; + e + }); + let coroutine_option = + this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability); + (body_id, coroutine_option) }); let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); @@ -1085,29 +1207,26 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let body = self.with_new_scopes(fn_decl_span, |this| { - this.with_def_id_parent(closure_def_id, |this| { - let inner_decl = - FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; - - // Transform `async |x: u8| -> X { ... }` into - // `|x: u8| || -> X { ... }`. - let body_id = this.lower_body(|this| { - let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( - &inner_decl, - |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), - fn_decl_span, - body.span, - coroutine_kind, - hir::CoroutineSource::Closure, - ); + let inner_decl = + FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; + + // Transform `async |x: u8| -> X { ... }` into + // `|x: u8| || -> X { ... }`. + let body_id = this.lower_body(|this| { + let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( + &inner_decl, + |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), + fn_decl_span, + body.span, + coroutine_kind, + hir::CoroutineSource::Closure, + ); - let hir_id = this.lower_node_id(coroutine_kind.closure_id()); - this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); + this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id); - (parameters, expr) - }); - body_id - }) + (parameters, expr) + }); + body_id }); let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); @@ -1317,7 +1436,11 @@ impl<'hir> LoweringContext<'_, 'hir> { None, ); // Destructure like a unit struct. - let unit_struct_pat = hir::PatKind::Path(qpath); + let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr { + kind: hir::PatExprKind::Path(qpath), + hir_id: self.next_id(), + span: self.lower_span(lhs.span), + })); return self.pat_without_dbm(lhs.span, unit_struct_pat); } } @@ -1434,15 +1557,39 @@ impl<'hir> LoweringContext<'_, 'hir> { let lang_item = match (e1, e2, lims) { (None, None, HalfOpen) => hir::LangItem::RangeFull, - (Some(..), None, HalfOpen) => hir::LangItem::RangeFrom, + (Some(..), None, HalfOpen) => { + if self.tcx.features().new_range() { + hir::LangItem::RangeFromCopy + } else { + hir::LangItem::RangeFrom + } + } (None, Some(..), HalfOpen) => hir::LangItem::RangeTo, - (Some(..), Some(..), HalfOpen) => hir::LangItem::Range, + (Some(..), Some(..), HalfOpen) => { + if self.tcx.features().new_range() { + hir::LangItem::RangeCopy + } else { + hir::LangItem::Range + } + } (None, Some(..), Closed) => hir::LangItem::RangeToInclusive, - (Some(..), Some(..), Closed) => unreachable!(), + (Some(e1), Some(e2), Closed) => { + if self.tcx.features().new_range() { + hir::LangItem::RangeInclusiveCopy + } else { + return self.lower_expr_range_closed(span, e1, e2); + } + } (start, None, Closed) => { self.dcx().emit_err(InclusiveRangeWithNoEnd { span }); match start { - Some(..) => hir::LangItem::RangeFrom, + Some(..) => { + if self.tcx.features().new_range() { + hir::LangItem::RangeFromCopy + } else { + hir::LangItem::RangeFrom + } + } None => hir::LangItem::RangeFull, } } @@ -1461,12 +1608,20 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Struct( self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))), fields, - None, + hir::StructTailExpr::None, ) } - fn lower_label(&self, opt_label: Option<Label>) -> Option<Label> { + // Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without + // lowering node id again. + fn lower_label( + &mut self, + opt_label: Option<Label>, + dest_id: NodeId, + dest_hir_id: hir::HirId, + ) -> Option<Label> { let label = opt_label?; + self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id); Some(Label { ident: self.lower_ident(label.ident) }) } @@ -1474,17 +1629,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let target_id = match destination { Some((id, _)) => { if let Some(loop_id) = self.resolver.get_label_res(id) { - Ok(self.lower_node_id(loop_id)) + let local_id = self.ident_and_label_to_local_id[&loop_id]; + let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id }; + Ok(loop_hir_id) } else { Err(hir::LoopIdError::UnresolvedLabel) } } - None => self - .loop_scope - .map(|id| Ok(self.lower_node_id(id))) - .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)), + None => { + self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) + } }; - let label = self.lower_label(destination.map(|(_, label)| label)); + let label = destination + .map(|(_, label)| label) + .map(|label| Label { ident: self.lower_ident(label.ident) }); hir::Destination { label, target_id } } @@ -1499,14 +1657,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_catch_scope<T>(&mut self, catch_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T { let old_scope = self.catch_scope.replace(catch_id); let result = f(self); self.catch_scope = old_scope; result } - fn with_loop_scope<T>(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T { // We're no longer in the base loop's condition; we're in another loop. let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; @@ -1533,7 +1691,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1547,6 +1705,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let yielded = opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span)); + if !self.tcx.features().yield_expr() + && !self.tcx.features().coroutines() + && !self.tcx.features().gen_blocks() + { + rustc_session::parse::feature_err( + &self.tcx.sess, + sym::yield_expr, + span, + fluent_generated::ast_lowering_yield, + ) + .emit(); + } + let is_async_gen = match self.coroutine_kind { Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true, @@ -1571,28 +1742,8 @@ impl<'hir> LoweringContext<'_, 'hir> { None, ); } - Some(hir::CoroutineKind::Coroutine(_)) => { - if !self.tcx.features().coroutines { - rustc_session::parse::feature_err( - &self.tcx.sess, - sym::coroutines, - span, - fluent_generated::ast_lowering_yield, - ) - .emit(); - } - false - } + Some(hir::CoroutineKind::Coroutine(_)) => false, None => { - if !self.tcx.features().coroutines { - rustc_session::parse::feature_err( - &self.tcx.sess, - sym::coroutines, - span, - fluent_generated::ast_lowering_yield, - ) - .emit(); - } let suggestion = self.current_item.map(|s| s.shrink_to_lo()); self.dcx().emit_err(YieldInClosure { span, suggestion }); self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable)); @@ -1658,9 +1809,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None); let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None); + let loop_hir_id = self.lower_node_id(e.id); + let label = self.lower_label(opt_label, e.id, loop_hir_id); + // `None => break` let none_arm = { - let break_expr = self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span)); + let break_expr = + self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span)); let pat = self.pat_none(for_span); self.arm(pat, break_expr) }; @@ -1668,7 +1823,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // Some(<pat>) => <body>, let some_arm = { let some_pat = self.pat_some(pat_span, pat); - let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); + let body_block = + self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false)); let body_expr = self.arena.alloc(self.expr_block(body_block)); self.arm(some_pat, body_expr) }; @@ -1722,12 +1878,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // `[opt_ident]: loop { ... }` let kind = hir::ExprKind::Loop( loop_block, - self.lower_label(opt_label), + label, hir::LoopSource::ForLoop, self.lower_span(for_span.with_hi(head.span.hi())), ); - let loop_expr = - self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span }); + let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span }); // `mut iter => { ... }` let iter_arm = self.arm(iter_pat, loop_expr); @@ -1792,7 +1947,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs); + self.lower_attrs(expr.hir_id, &e.attrs, e.span); expr } @@ -1812,13 +1967,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, span, - Some(self.allow_try_trait.clone()), + Some(Arc::clone(&self.allow_try_trait)), ); let try_span = self.tcx.sess.source_map().end_point(span); let try_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, try_span, - Some(self.allow_try_trait.clone()), + Some(Arc::clone(&self.allow_try_trait)), ); // `Try::branch(<expr>)` @@ -1849,7 +2004,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.expr_ident(span, val_ident, val_pat_nid); - self.lower_attrs(val_expr.hir_id, &attrs); + self.lower_attrs(val_expr.hir_id, &attrs, span); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) }; @@ -1867,8 +2022,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(residual_expr), unstable_span, ); - let ret_expr = if let Some(catch_node) = self.catch_scope { - let target_id = Ok(self.lower_node_id(catch_node)); + let ret_expr = if let Some(catch_id) = self.catch_scope { + let target_id = Ok(catch_id); self.arena.alloc(self.expr( try_span, hir::ExprKind::Break( @@ -1877,9 +2032,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ), )) } else { - self.arena.alloc(self.expr(try_span, hir::ExprKind::Ret(Some(from_residual_expr)))) + let ret_expr = self.checked_return(Some(from_residual_expr)); + self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs); + self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) @@ -1912,7 +2068,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::YeetExpr, span, - Some(self.allow_try_trait.clone()), + Some(Arc::clone(&self.allow_try_trait)), ); let from_yeet_expr = self.wrap_in_try_constructor( @@ -1922,11 +2078,11 @@ impl<'hir> LoweringContext<'_, 'hir> { yeeted_span, ); - if let Some(catch_node) = self.catch_scope { - let target_id = Ok(self.lower_node_id(catch_node)); + if let Some(catch_id) = self.catch_scope { + let target_id = Ok(catch_id); hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr)) } else { - hir::ExprKind::Ret(Some(from_yeet_expr)) + self.checked_return(Some(from_yeet_expr)) } } @@ -1984,31 +2140,24 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]))) } - pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> { let lit = self.arena.alloc(hir::Lit { span: sp, - node: ast::LitKind::Int( - (value as u128).into(), - ast::LitIntType::Unsigned(ast::UintTy::Usize), - ), + node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)), }); self.expr(sp, hir::ExprKind::Lit(lit)) } + pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + self.expr_uint(sp, ast::UintTy::Usize, value as u128) + } + pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { - span: sp, - node: ast::LitKind::Int( - u128::from(value).into(), - ast::LitIntType::Unsigned(ast::UintTy::U32), - ), - }); - self.expr(sp, hir::ExprKind::Lit(lit)) + self.expr_uint(sp, ast::UintTy::U32, value as u128) } - pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Char(value) }); - self.expr(sp, hir::ExprKind::Lit(lit)) + pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> { + self.expr_uint(sp, ast::UintTy::U16, value as u128) } pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { @@ -2036,7 +2185,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr_call_mut(span, e, args)) } - fn expr_call_lang_item_fn_mut( + pub(super) fn expr_call_lang_item_fn_mut( &mut self, span: Span, lang_item: hir::LangItem, @@ -2046,7 +2195,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr_call_mut(span, path, args) } - fn expr_call_lang_item_fn( + pub(super) fn expr_call_lang_item_fn( &mut self, span: Span, lang_item: hir::LangItem, @@ -2070,7 +2219,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let path = hir::ExprKind::Path(hir::QPath::TypeRelative( self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))), self.arena.alloc(hir::PathSegment::new( - Ident::new(name, span), + Ident::new(name, self.lower_span(span)), self.next_id(), Res::Err, )), diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 653116e1fe00d..0de0319c66763 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -6,8 +6,7 @@ use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_session::config::FmtDebug; -use rustc_span::symbol::{Ident, kw}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Ident, Span, Symbol, kw, sym}; use super::LoweringContext; @@ -293,7 +292,7 @@ fn make_count<'hir>( hir::LangItem::FormatCount, sym::Is, )); - let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]); + let value = ctx.arena.alloc_from_iter([ctx.expr_u16(sp, *n)]); ctx.expr_call_mut(sp, count_is, value) } Some(FormatCount::Argument(arg)) => { @@ -324,14 +323,12 @@ fn make_count<'hir>( /// Generates /// /// ```text -/// <core::fmt::rt::Placeholder::new( -/// …usize, // position -/// '…', // fill -/// <core::fmt::rt::Alignment>::…, // alignment -/// …u32, // flags -/// <core::fmt::rt::Count::…>, // width -/// <core::fmt::rt::Count::…>, // precision -/// ) +/// <core::fmt::rt::Placeholder { +/// position: …usize, +/// flags: …u32, +/// precision: <core::fmt::rt::Count::…>, +/// width: <core::fmt::rt::Count::…>, +/// } /// ``` fn make_format_spec<'hir>( ctx: &mut LoweringContext<'_, 'hir>, @@ -362,31 +359,36 @@ fn make_format_spec<'hir>( zero_pad, debug_hex, } = &placeholder.format_options; - let fill = ctx.expr_char(sp, fill.unwrap_or(' ')); - let align = - ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatAlignment, match alignment { - Some(FormatAlignment::Left) => sym::Left, - Some(FormatAlignment::Right) => sym::Right, - Some(FormatAlignment::Center) => sym::Center, - None => sym::Unknown, - }); - // This needs to match `Flag` in library/core/src/fmt/rt.rs. - let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) - | ((sign == Some(FormatSign::Minus)) as u32) << 1 - | (alternate as u32) << 2 - | (zero_pad as u32) << 3 - | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4 - | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5; + let fill = fill.unwrap_or(' '); + // These need to match the constants in library/core/src/fmt/rt.rs. + let align = match alignment { + Some(FormatAlignment::Left) => 0, + Some(FormatAlignment::Right) => 1, + Some(FormatAlignment::Center) => 2, + None => 3, + }; + // This needs to match the constants in library/core/src/fmt/rt.rs. + let flags: u32 = fill as u32 + | ((sign == Some(FormatSign::Plus)) as u32) << 21 + | ((sign == Some(FormatSign::Minus)) as u32) << 22 + | (alternate as u32) << 23 + | (zero_pad as u32) << 24 + | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25 + | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26 + | (width.is_some() as u32) << 27 + | (precision.is_some() as u32) << 28 + | align << 29 + | 1 << 31; // Highest bit always set. let flags = ctx.expr_u32(sp, flags); let precision = make_count(ctx, sp, precision, argmap); let width = make_count(ctx, sp, width, argmap); - let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - sp, - hir::LangItem::FormatPlaceholder, - sym::new, - )); - let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]); - ctx.expr_call_mut(sp, format_placeholder_new, args) + let position = ctx.expr_field(Ident::new(sym::position, sp), ctx.arena.alloc(position), sp); + let flags = ctx.expr_field(Ident::new(sym::flags, sp), ctx.arena.alloc(flags), sp); + let precision = ctx.expr_field(Ident::new(sym::precision, sp), ctx.arena.alloc(precision), sp); + let width = ctx.expr_field(Ident::new(sym::width, sp), ctx.arena.alloc(width), sp); + let placeholder = ctx.arena.alloc(hir::QPath::LangItem(hir::LangItem::FormatPlaceholder, sp)); + let fields = ctx.arena.alloc_from_iter([position, flags, precision, width]); + ctx.expr(sp, hir::ExprKind::Struct(placeholder, fields, hir::StructTailExpr::None)) } fn expand_format_args<'hir>( diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 6289966561f58..26c0e7e5f82af 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -1,3 +1,4 @@ +use intravisit::InferKind; use rustc_data_structures::sorted_map::SortedMap; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap}; @@ -78,24 +79,31 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // Make sure that the DepNode of some node coincides with the HirId // owner of that node. - if cfg!(debug_assertions) && hir_id.owner != self.owner { - span_bug!( - span, - "inconsistent HirId at `{:?}` for `{:?}`: \ + if cfg!(debug_assertions) { + if hir_id.owner != self.owner { + span_bug!( + span, + "inconsistent HirId at `{:?}` for `{node:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", - self.tcx.sess.source_map().span_to_diagnostic_string(span), - node, - self.tcx - .definitions_untracked() - .def_path(self.owner.def_id) - .to_string_no_crate_verbose(), - self.owner, - self.tcx - .definitions_untracked() - .def_path(hir_id.owner.def_id) - .to_string_no_crate_verbose(), - hir_id.owner, - ) + self.tcx.sess.source_map().span_to_diagnostic_string(span), + self.tcx + .definitions_untracked() + .def_path(self.owner.def_id) + .to_string_no_crate_verbose(), + self.owner, + self.tcx + .definitions_untracked() + .def_path(hir_id.owner.def_id) + .to_string_no_crate_verbose(), + hir_id.owner, + ) + } + if self.tcx.sess.opts.incremental.is_some() + && span.parent().is_none() + && !span.is_dummy() + { + span_bug!(span, "span without a parent: {:#?}, {node:?}", span.data()) + } } self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node }; @@ -156,7 +164,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_item(&mut self, i: &'hir Item<'hir>) { debug_assert_eq!(i.owner_id, self.owner); self.with_parent(i.hir_id(), |this| { - if let ItemKind::Struct(struct_def, _) = &i.kind { + if let ItemKind::Struct(_, struct_def, _) = &i.kind { // If this is a tuple or unit-like struct, register the constructor. if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def)); @@ -209,6 +217,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_pat_expr(&mut self, expr: &'hir PatExpr<'hir>) { + self.insert(expr.span, expr.hir_id, Node::PatExpr(expr)); + + self.with_parent(expr.hir_id, |this| { + intravisit::walk_pat_expr(this, expr); + }); + } + fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) { self.insert(field.span, field.hir_id, Node::PatField(field)); self.with_parent(field.hir_id, |this| { @@ -235,8 +251,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_anon_const(&mut self, constant: &'hir AnonConst) { - // FIXME: use real span? - self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); + self.insert(constant.span, constant.hir_id, Node::AnonConst(constant)); self.with_parent(constant.hir_id, |this| { intravisit::walk_anon_const(this, constant); @@ -251,15 +266,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) { - // FIXME: use real span? - self.insert(DUMMY_SP, const_arg.hir_id, Node::ConstArg(const_arg)); - - self.with_parent(const_arg.hir_id, |this| { - intravisit::walk_const_arg(this, const_arg); - }); - } - fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { self.insert(expr.span, expr.hir_id, Node::Expr(expr)); @@ -289,22 +295,41 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { intravisit::walk_path_segment(self, path_segment); } - fn visit_ty(&mut self, ty: &'hir Ty<'hir>) { - self.insert(ty.span, ty.hir_id, Node::Ty(ty)); + fn visit_ty(&mut self, ty: &'hir Ty<'hir, AmbigArg>) { + self.insert(ty.span, ty.hir_id, Node::Ty(ty.as_unambig_ty())); self.with_parent(ty.hir_id, |this| { intravisit::walk_ty(this, ty); }); } - fn visit_infer(&mut self, inf: &'hir InferArg) { - self.insert(inf.span, inf.hir_id, Node::Infer(inf)); + fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) { + self.insert( + const_arg.as_unambig_ct().span(), + const_arg.hir_id, + Node::ConstArg(const_arg.as_unambig_ct()), + ); - self.with_parent(inf.hir_id, |this| { - intravisit::walk_inf(this, inf); + self.with_parent(const_arg.hir_id, |this| { + intravisit::walk_ambig_const_arg(this, const_arg); }); } + fn visit_infer( + &mut self, + inf_id: HirId, + inf_span: Span, + kind: InferKind<'hir>, + ) -> Self::Result { + match kind { + InferKind::Ty(ty) => self.insert(inf_span, inf_id, Node::Ty(ty)), + InferKind::Const(ct) => self.insert(inf_span, inf_id, Node::ConstArg(ct)), + InferKind::Ambig(inf) => self.insert(inf_span, inf_id, Node::Infer(inf)), + } + + self.visit_id(inf_id); + } + fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) { self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr)); @@ -381,26 +406,18 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_where_predicate(&mut self, predicate: &'hir WherePredicate<'hir>) { - match predicate { - WherePredicate::BoundPredicate(pred) => { - self.insert(pred.span, pred.hir_id, Node::WhereBoundPredicate(pred)); - self.with_parent(pred.hir_id, |this| { - intravisit::walk_where_predicate(this, predicate) - }) - } - _ => intravisit::walk_where_predicate(self, predicate), - } + self.insert(predicate.span, predicate.hir_id, Node::WherePredicate(predicate)); + self.with_parent(predicate.hir_id, |this| { + intravisit::walk_where_predicate(this, predicate) + }); } - fn visit_array_length(&mut self, len: &'hir ArrayLen<'hir>) { - match len { - ArrayLen::Infer(inf) => self.insert(inf.span, inf.hir_id, Node::ArrayLenInfer(inf)), - ArrayLen::Body(..) => intravisit::walk_array_len(self, len), - } - } + fn visit_pattern_type_pattern(&mut self, pat: &'hir hir::TyPat<'hir>) { + self.insert(pat.span, pat.hir_id, Node::TyPat(pat)); - fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) { - self.visit_pat(p) + self.with_parent(pat.hir_id, |this| { + intravisit::walk_ty_pat(this, pat); + }); } fn visit_precise_capturing_arg( diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ce744cc56e1ab..fc32c4efce56a 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,23 +1,23 @@ +use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_hir::PredicateOrigin; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; +use rustc_hir::{self as hir, HirId, IsAnonInPath, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::symbol::{Ident, kw, sym}; -use rustc_span::{DesugaringKind, Span, Symbol}; -use rustc_target::spec::abi; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::instrument; -use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound}; +use super::errors::{ + InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault, +}; +use super::stability::{enabled_names, gate_unstable_abi}; use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, @@ -57,7 +57,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, ) { - let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index); + let mut lctx = LoweringContext::new(self.tcx, self.resolver); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { @@ -91,7 +91,8 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); + // FIXME(jdonszelman): is dummy span ever a problem here? + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); hir::OwnerNode::Crate(module) }) } @@ -102,10 +103,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { } fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) { - let def_id = self.resolver.node_id_to_def_id[&item.id]; - let parent_id = self.tcx.local_parent(def_id); - let parent_hir = self.lower_node(parent_id).unwrap(); - self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt, parent_hir)) + self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt)) } fn lower_foreign_item(&mut self, item: &ForeignItem) { @@ -129,8 +127,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> { - let mut node_ids = - smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }]; + let mut node_ids = smallvec![hir::ItemId { owner_id: self.owner_id(i.id) }]; if let ItemKind::Use(use_tree) = &i.kind { self.lower_item_id_use_tree(use_tree, &mut node_ids); } @@ -141,9 +138,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match &tree.kind { UseTreeKind::Nested { items, .. } => { for &(ref nested, id) in items { - vec.push(hir::ItemId { - owner_id: hir::OwnerId { def_id: self.local_def_id(id) }, - }); + vec.push(hir::ItemId { owner_id: self.owner_id(id) }); self.lower_item_id_use_tree(nested, vec); } } @@ -152,14 +147,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { - let mut ident = i.ident; let vis_span = self.lower_span(i.vis.span); - let hir_id = self.lower_node_id(i.id); - let attrs = self.lower_attrs(hir_id, &i.attrs); - let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), - ident: self.lower_ident(ident), kind, vis_span, span: self.lower_span(i.span), @@ -172,41 +165,62 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, id: NodeId, hir_id: hir::HirId, - ident: &mut Ident, - attrs: &'hir [Attribute], + attrs: &'hir [hir::Attribute], vis_span: Span, i: &ItemKind, ) -> hir::ItemKind<'hir> { match i { - ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(*orig_name), + ItemKind::ExternCrate(orig_name, ident) => { + let ident = self.lower_ident(*ident); + hir::ItemKind::ExternCrate(*orig_name, ident) + } ItemKind::Use(use_tree) => { // Start with an empty prefix. let prefix = Path { segments: ThinVec::new(), span: use_tree.span, tokens: None }; - self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs) + self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs) } - ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => { + ItemKind::Static(box ast::StaticItem { + ident, + ty: t, + safety: _, + mutability: m, + expr: e, + define_opaque, + }) => { + let ident = self.lower_ident(*ident); let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); - hir::ItemKind::Static(ty, *m, body_id) + self.lower_define_opaque(hir_id, define_opaque); + hir::ItemKind::Static(ident, ty, *m, body_id) } - ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + ItemKind::Const(box ast::ConstItem { + ident, + generics, + ty, + expr, + define_opaque, + .. + }) => { + let ident = self.lower_ident(*ident); let (generics, (ty, body_id)) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) }, ); - hir::ItemKind::Const(ty, generics, body_id) + self.lower_define_opaque(hir_id, &define_opaque); + hir::ItemKind::Const(ident, ty, generics, body_id) } ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, + ident, generics, body, + contract, + define_opaque, .. }) => { self.with_new_scopes(*fn_sig_span, |this| { @@ -222,41 +236,52 @@ impl<'hir> LoweringContext<'_, 'hir> { decl, coroutine_kind, body.as_deref(), + attrs, + contract.as_deref(), ); let itctx = ImplTraitContext::Universal; - let (generics, decl) = - this.lower_generics(generics, header.constness, false, id, itctx, |this| { - this.lower_fn_decl( - decl, - id, - *fn_sig_span, - FnDeclKind::Fn, - coroutine_kind, - ) - }); + let (generics, decl) = this.lower_generics(generics, id, itctx, |this| { + this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, coroutine_kind) + }); let sig = hir::FnSig { decl, - header: this.lower_fn_header(*header, hir::Safety::Safe), + header: this.lower_fn_header(*header, hir::Safety::Safe, attrs), span: this.lower_span(*fn_sig_span), }; - hir::ItemKind::Fn(sig, generics, body_id) + this.lower_define_opaque(hir_id, define_opaque); + let ident = this.lower_ident(*ident); + hir::ItemKind::Fn { + ident, + sig, + generics, + body: body_id, + has_body: body.is_some(), + } }) } - ItemKind::Mod(_, mod_kind) => match mod_kind { - ModKind::Loaded(items, _, spans) => { - hir::ItemKind::Mod(self.lower_mod(items, spans)) + ItemKind::Mod(_, ident, mod_kind) => { + let ident = self.lower_ident(*ident); + match mod_kind { + ModKind::Loaded(items, _, spans, _) => { + hir::ItemKind::Mod(ident, self.lower_mod(items, spans)) + } + ModKind::Unloaded => panic!("`mod` items should have been loaded by now"), } - ModKind::Unloaded => panic!("`mod` items should have been loaded by now"), - }, + } ItemKind::ForeignMod(fm) => hir::ItemKind::ForeignMod { - abi: fm.abi.map_or(abi::Abi::FALLBACK, |abi| self.lower_abi(abi)), + abi: fm.abi.map_or(ExternAbi::FALLBACK, |abi| self.lower_abi(abi)), items: self .arena .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), }, - ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)), - ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => { + ItemKind::GlobalAsm(asm) => { + let asm = self.lower_inline_asm(span, asm); + let fake_body = + self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm)))); + hir::ItemKind::GlobalAsm { asm, fake_body } + } + ItemKind::TyAlias(box TyAlias { ident, generics, where_clauses, ty, .. }) => { // We lower // // type Foo = impl Trait @@ -265,12 +290,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // // type Foo = Foo1 // opaque type Foo1: Trait + let ident = self.lower_ident(*ident); let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, *where_clauses, true); let (generics, ty) = self.lower_generics( &generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -281,21 +305,23 @@ impl<'hir> LoweringContext<'_, 'hir> { ); this.arena.alloc(this.ty(span, hir::TyKind::Err(guar))) } - Some(ty) => this.lower_ty(ty, ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(id), - in_assoc_ty: false, + Some(ty) => this.lower_ty( + ty, + ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(id), + in_assoc_ty: false, + }, }, - }), + ), }, ); - hir::ItemKind::TyAlias(ty, generics) + hir::ItemKind::TyAlias(ident, ty, generics) } - ItemKind::Enum(enum_definition, generics) => { + ItemKind::Enum(ident, enum_definition, generics) => { + let ident = self.lower_ident(*ident); let (generics, variants) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -304,29 +330,27 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }, ); - hir::ItemKind::Enum(hir::EnumDef { variants }, generics) + hir::ItemKind::Enum(ident, hir::EnumDef { variants }, generics) } - ItemKind::Struct(struct_def, generics) => { + ItemKind::Struct(ident, struct_def, generics) => { + let ident = self.lower_ident(*ident); let (generics, struct_def) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), ); - hir::ItemKind::Struct(struct_def, generics) + hir::ItemKind::Struct(ident, struct_def, generics) } - ItemKind::Union(vdata, generics) => { + ItemKind::Union(ident, vdata, generics) => { + let ident = self.lower_ident(*ident); let (generics, vdata) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), ); - hir::ItemKind::Union(vdata, generics) + hir::ItemKind::Union(ident, vdata, generics) } ItemKind::Impl(box Impl { safety, @@ -353,7 +377,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| { + self.lower_generics(ast_generics, id, itctx, |this| { let modifiers = TraitBoundModifiers { constness: BoundConstness::Never, asyncness: BoundAsyncness::Normal, @@ -377,10 +401,11 @@ impl<'hir> LoweringContext<'_, 'hir> { (trait_ref, lowered_ty) }); - self.is_in_trait_impl = trait_ref.is_some(); - let new_impl_items = self - .arena - .alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item))); + let new_impl_items = self.arena.alloc_from_iter( + impl_items + .iter() + .map(|item| self.lower_impl_item_ref(item, trait_ref.is_some())), + ); // `defaultness.has_value()` is never called for an `impl`, always `true` in order // to not cause an assertion failure inside the `lower_defaultness` function. @@ -402,11 +427,10 @@ impl<'hir> LoweringContext<'_, 'hir> { items: new_impl_items, })) } - ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => { + ItemKind::Trait(box Trait { is_auto, safety, ident, generics, bounds, items }) => { + let ident = self.lower_ident(*ident); let (generics, (safety, items, bounds)) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -421,13 +445,12 @@ impl<'hir> LoweringContext<'_, 'hir> { (safety, items, bounds) }, ); - hir::ItemKind::Trait(*is_auto, safety, generics, bounds, items) + hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items) } - ItemKind::TraitAlias(generics, bounds) => { + ItemKind::TraitAlias(ident, generics, bounds) => { + let ident = self.lower_ident(*ident); let (generics, bounds) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -437,9 +460,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }, ); - hir::ItemKind::TraitAlias(generics, bounds) + hir::ItemKind::TraitAlias(ident, generics, bounds) } - ItemKind::MacroDef(MacroDef { body, macro_rules }) => { + ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => { + let ident = self.lower_ident(*ident); let body = P(self.lower_delim_args(body)); let def_id = self.local_def_id(id); let def_kind = self.tcx.def_kind(def_id); @@ -450,15 +474,17 @@ impl<'hir> LoweringContext<'_, 'hir> { ); }; let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules }); - hir::ItemKind::Macro(macro_def, macro_kind) + hir::ItemKind::Macro(ident, macro_def, macro_kind) } ItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, id); - hir::ItemKind::Fn( - delegation_results.sig, - delegation_results.generics, - delegation_results.body_id, - ) + let delegation_results = self.lower_delegation(delegation, id, false); + hir::ItemKind::Fn { + ident: delegation_results.ident, + sig: delegation_results.sig, + generics: delegation_results.generics, + body: delegation_results.body_id, + has_body: true, + } } ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") @@ -484,15 +510,14 @@ impl<'hir> LoweringContext<'_, 'hir> { prefix: &Path, id: NodeId, vis_span: Span, - ident: &mut Ident, - attrs: &'hir [Attribute], + attrs: &'hir [hir::Attribute], ) -> hir::ItemKind<'hir> { let path = &tree.prefix; let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect(); match tree.kind { UseTreeKind::Simple(rename) => { - *ident = tree.ident(); + let mut ident = tree.ident(); // First, apply the prefix to the path. let mut path = Path { segments, span: path.span, tokens: None }; @@ -503,13 +528,14 @@ impl<'hir> LoweringContext<'_, 'hir> { { let _ = path.segments.pop(); if rename.is_none() { - *ident = path.segments.last().unwrap().ident; + ident = path.segments.last().unwrap().ident; } } let res = self.lower_import_res(id, path.span); let path = self.lower_use_path(res, &path, ParamMode::Explicit); - hir::ItemKind::Use(path, hir::UseKind::Single) + let ident = self.lower_ident(ident); + hir::ItemKind::Use(path, hir::UseKind::Single(ident)) } UseTreeKind::Glob => { let res = self.expect_full_res(id); @@ -548,7 +574,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Add all the nested `PathListItem`s to the HIR. for &(ref use_tree, id) in trees { - let new_hir_id = self.local_def_id(id); + let owner_id = self.owner_id(id); // Each `use` import is an item and thus are owners of the // names in the path. Up to this point the nested import is @@ -556,20 +582,16 @@ impl<'hir> LoweringContext<'_, 'hir> { // own its own names, we have to adjust the owner before // lowering the rest of the import. self.with_hir_id_owner(id, |this| { - let mut ident = *ident; - // `prefix` is lowered multiple times, but in different HIR owners. // So each segment gets renewed `HirId` with the same // `ItemLocalId` and the new owner. (See `lower_node_id`) - let kind = - this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs); + let kind = this.lower_use_tree(use_tree, &prefix, id, vis_span, attrs); if !attrs.is_empty() { this.attrs.insert(hir::ItemLocalId::ZERO, attrs); } let item = hir::Item { - owner_id: hir::OwnerId { def_id: new_hir_id }, - ident: this.lower_ident(ident), + owner_id, kind, vis_span, span: this.lower_span(use_tree.span), @@ -598,104 +620,77 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_assoc_item( - &mut self, - item: &AssocItem, - ctxt: AssocCtxt, - parent_hir: &'hir hir::OwnerInfo<'hir>, - ) -> hir::OwnerNode<'hir> { + fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) -> hir::OwnerNode<'hir> { // Evaluate with the lifetimes in `params` in-scope. // This is used to track which lifetimes have already been defined, // and which need to be replicated when lowering an async fn. - - let parent_item = parent_hir.node().expect_item(); - let constness = match parent_item.kind { - hir::ItemKind::Impl(impl_) => { - self.is_in_trait_impl = impl_.of_trait.is_some(); - // N.B. the impl should always lower to methods that have `const host: bool` params if the trait - // is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from - // calling non-const impls are done through associated types. - if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) { - if let Some(local_def) = def_id.as_local() { - match &self.ast_index[local_def] { - AstOwner::Item(ast::Item { attrs, .. }) => attrs - .iter() - .find(|attr| attr.has_name(sym::const_trait)) - .map_or(Const::No, |attr| Const::Yes(attr.span)), - _ => Const::No, - } - } else if self.tcx.is_const_trait(def_id) { - // FIXME(effects) span - Const::Yes(self.tcx.def_ident_span(def_id).unwrap()) - } else { - Const::No - } - } else { - Const::No - } - } - hir::ItemKind::Trait(_, _, _, _, _) => parent_hir - .attrs - .get(parent_item.hir_id().local_id) - .iter() - .find(|attr| attr.has_name(sym::const_trait)) - .map_or(Const::No, |attr| Const::Yes(attr.span)), - kind => { - span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr()) - } - }; - match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)), + AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)), + AssocCtxt::Impl { of_trait } => { + hir::OwnerNode::ImplItem(self.lower_impl_item(item, of_trait)) + } } } fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - self.lower_attrs(hir_id, &i.attrs); - let item = hir::ForeignItem { - owner_id, - ident: self.lower_ident(i.ident), - kind: match &i.kind { - ForeignItemKind::Fn(box Fn { sig, generics, .. }) => { - let fdec = &sig.decl; - let itctx = ImplTraitContext::Universal; - let (generics, (decl, fn_args)) = - self.lower_generics(generics, Const::No, false, i.id, itctx, |this| { - ( - // Disallow `impl Trait` in foreign items. - this.lower_fn_decl( - fdec, - i.id, - sig.span, - FnDeclKind::ExternFn, - None, - ), - this.lower_fn_params_to_names(fdec), - ) - }); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let (ident, kind) = match &i.kind { + ForeignItemKind::Fn(box Fn { sig, ident, generics, define_opaque, .. }) => { + let fdec = &sig.decl; + let itctx = ImplTraitContext::Universal; + let (generics, (decl, fn_args)) = + self.lower_generics(generics, i.id, itctx, |this| { + ( + // Disallow `impl Trait` in foreign items. + this.lower_fn_decl(fdec, i.id, sig.span, FnDeclKind::ExternFn, None), + this.lower_fn_params_to_idents(fdec), + ) + }); + + // Unmarked safety in unsafe block defaults to unsafe. + let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); - // Unmarked safety in unsafe block defaults to unsafe. - let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe); + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign functions cannot define opaque types"); + } + ( + ident, hir::ForeignItemKind::Fn( hir::FnSig { header, decl, span: self.lower_span(sig.span) }, fn_args, generics, - ) + ), + ) + } + ForeignItemKind::Static(box StaticItem { + ident, + ty, + mutability, + expr: _, + safety, + define_opaque, + }) => { + let ty = + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); } - ForeignItemKind::Static(box StaticItem { ty, mutability, expr: _, safety }) => { - let ty = self - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); - let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + (ident, hir::ForeignItemKind::Static(ty, *mutability, safety)) + } + ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => { + (ident, hir::ForeignItemKind::Type) + } + ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), + }; - hir::ForeignItemKind::Static(ty, *mutability, safety) - } - ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, - ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), - }, + let item = hir::ForeignItem { + owner_id, + ident: self.lower_ident(*ident), + kind, vis_span: self.lower_span(i.vis.span), span: self.lower_span(i.span), }; @@ -704,15 +699,17 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef { hir::ForeignItemRef { - id: hir::ForeignItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, - ident: self.lower_ident(i.ident), + id: hir::ForeignItemId { owner_id: self.owner_id(i.id) }, + // `unwrap` is safe because `ForeignItemKind::MacCall` is the only foreign item kind + // without an identifier and it cannot reach here. + ident: self.lower_ident(i.kind.ident().unwrap()), span: self.lower_span(i.span), } } fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> { let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs); + self.lower_attrs(hir_id, &v.attrs, v.span); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -738,13 +735,27 @@ impl<'hir> LoweringContext<'_, 'hir> { VariantData::Tuple(fields, id) => { let ctor_id = self.lower_node_id(*id); self.alias_attrs(ctor_id, parent_id); - hir::VariantData::Tuple( - self.arena.alloc_from_iter( - fields.iter().enumerate().map(|f| self.lower_field_def(f)), - ), - ctor_id, - self.local_def_id(*id), - ) + let fields = self + .arena + .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))); + for field in &fields[..] { + if let Some(default) = field.default { + // Default values in tuple struct and tuple variants are not allowed by the + // RFC due to concerns about the syntax, both in the item definition and the + // expression. We could in the future allow `struct S(i32 = 0);` and force + // users to construct the value with `let _ = S { .. };`. + if self.tcx.features().default_field_values() { + self.dcx().emit_err(TupleStructWithDefault { span: default.span }); + } else { + let _ = self.dcx().span_delayed_bug( + default.span, + "expected `default values on `struct` fields aren't supported` \ + feature-gate error but none was produced", + ); + } + } + } + hir::VariantData::Tuple(fields, ctor_id, self.local_def_id(*id)) } VariantData::Unit(id) => { let ctor_id = self.lower_node_id(*id); @@ -760,7 +771,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FieldDef<'hir> { let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -771,25 +782,28 @@ impl<'hir> LoweringContext<'_, 'hir> { None => Ident::new(sym::integer(index), self.lower_span(f.span)), }, vis_span: self.lower_span(f.vis.span), + default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)), ty, + safety: self.lower_safety(f.safety, hir::Safety::Safe), } } - fn lower_trait_item( - &mut self, - i: &AssocItem, - trait_constness: Const, - ) -> &'hir hir::TraitItem<'hir> { - let hir_id = self.lower_node_id(i.id); - self.lower_attrs(hir_id, &i.attrs); + fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let trait_item_def_id = hir_id.expect_owner(); - let (generics, kind, has_default) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { + let (ident, generics, kind, has_default) = match &i.kind { + AssocItemKind::Const(box ConstItem { + ident, + generics, + ty, + expr, + define_opaque, + .. + }) => { let (generics, kind) = self.lower_generics( generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -800,21 +814,56 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::TraitItemKind::Const(ty, body) }, ); - (generics, kind, expr.is_some()) + + if define_opaque.is_some() { + if expr.is_some() { + self.lower_define_opaque(hir_id, &define_opaque); + } else { + self.dcx().span_err( + i.span, + "only trait consts with default bodies can define opaque types", + ); + } + } + + (*ident, generics, kind, expr.is_some()) } - AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => { - let names = self.lower_fn_params_to_names(&sig.decl); + AssocItemKind::Fn(box Fn { + sig, ident, generics, body: None, define_opaque, .. + }) => { + // FIXME(contracts): Deny contract here since it won't apply to + // any impl method or callees. + let idents = self.lower_fn_params_to_idents(&sig.decl); let (generics, sig) = self.lower_method_sig( generics, sig, i.id, FnDeclKind::Trait, sig.header.coroutine_kind, - trait_constness, + attrs, ); - (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) + if define_opaque.is_some() { + self.dcx().span_err( + i.span, + "only trait methods with default bodies can define opaque types", + ); + } + ( + *ident, + generics, + hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(idents)), + false, + ) } - AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { + AssocItemKind::Fn(box Fn { + sig, + ident, + generics, + body: Some(body), + contract, + define_opaque, + .. + }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -822,6 +871,8 @@ impl<'hir> LoweringContext<'_, 'hir> { &sig.decl, sig.header.coroutine_kind, Some(body), + attrs, + contract.as_deref(), ); let (generics, sig) = self.lower_method_sig( generics, @@ -829,17 +880,23 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, - trait_constness, + attrs, ); - (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) + self.lower_define_opaque(hir_id, &define_opaque); + ( + *ident, + generics, + hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), + true, + ) } - AssocItemKind::Type(box TyAlias { generics, where_clauses, bounds, ty, .. }) => { + AssocItemKind::Type(box TyAlias { + ident, generics, where_clauses, bounds, ty, .. + }) => { let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, *where_clauses, false); let (generics, kind) = self.lower_generics( &generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -858,15 +915,15 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }, ); - (generics, kind, ty.is_some()) + (*ident, generics, kind, ty.is_some()) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, i.id); + let delegation_results = self.lower_delegation(delegation, i.id, false); let item_kind = hir::TraitItemKind::Fn( delegation_results.sig, hir::TraitFn::Provided(delegation_results.body_id), ); - (delegation_results.generics, item_kind, true) + (delegation.ident, delegation_results.generics, item_kind, true) } AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") @@ -875,7 +932,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let item = hir::TraitItem { owner_id: trait_item_def_id, - ident: self.lower_ident(i.ident), + ident: self.lower_ident(ident), generics, kind, span: self.lower_span(i.span), @@ -885,23 +942,28 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef { - let kind = match &i.kind { - AssocItemKind::Const(..) => hir::AssocItemKind::Const, - AssocItemKind::Type(..) => hir::AssocItemKind::Type, - AssocItemKind::Fn(box Fn { sig, .. }) => { - hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } + let (ident, kind) = match &i.kind { + AssocItemKind::Const(box ConstItem { ident, .. }) => { + (*ident, hir::AssocItemKind::Const) } - AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { - has_self: self.delegation_has_self(i.id, delegation.id, i.span), - }, + AssocItemKind::Type(box TyAlias { ident, .. }) => (*ident, hir::AssocItemKind::Type), + AssocItemKind::Fn(box Fn { ident, sig, .. }) => { + (*ident, hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }) + } + AssocItemKind::Delegation(box delegation) => ( + delegation.ident, + hir::AssocItemKind::Fn { + has_self: self.delegatee_is_method(i.id, delegation.id, i.span, false), + }, + ), AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") } }; - let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }; + let id = hir::TraitItemId { owner_id: self.owner_id(i.id) }; hir::TraitItemRef { id, - ident: self.lower_ident(i.ident), + ident: self.lower_ident(ident), span: self.lower_span(i.span), kind, } @@ -915,30 +977,46 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_impl_item( &mut self, i: &AssocItem, - constness_of_trait: Const, + is_in_trait_impl: bool, ) -> &'hir hir::ImplItem<'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); - let hir_id = self.lower_node_id(i.id); - self.lower_attrs(hir_id, &i.attrs); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); - let (generics, kind) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( + let (ident, (generics, kind)) = match &i.kind { + AssocItemKind::Const(box ConstItem { + ident, generics, - Const::No, - false, - i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| { - let ty = - this.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = this.lower_const_body(i.span, expr.as_deref()); - - hir::ImplItemKind::Const(ty, body) - }, + ty, + expr, + define_opaque, + .. + }) => ( + *ident, + self.lower_generics( + generics, + i.id, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| { + let ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let body = this.lower_const_body(i.span, expr.as_deref()); + this.lower_define_opaque(hir_id, &define_opaque); + hir::ImplItemKind::Const(ty, body) + }, + ), ), - AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { + AssocItemKind::Fn(box Fn { + sig, + ident, + generics, + body, + contract, + define_opaque, + .. + }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -946,53 +1024,63 @@ impl<'hir> LoweringContext<'_, 'hir> { &sig.decl, sig.header.coroutine_kind, body.as_deref(), + attrs, + contract.as_deref(), ); let (generics, sig) = self.lower_method_sig( generics, sig, i.id, - if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, + if is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_kind, - constness_of_trait, + attrs, ); + self.lower_define_opaque(hir_id, &define_opaque); - (generics, hir::ImplItemKind::Fn(sig, body_id)) + (*ident, (generics, hir::ImplItemKind::Fn(sig, body_id))) } - AssocItemKind::Type(box TyAlias { generics, where_clauses, ty, .. }) => { + AssocItemKind::Type(box TyAlias { ident, generics, where_clauses, ty, .. }) => { let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, *where_clauses, false); - self.lower_generics( - &generics, - Const::No, - false, - i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| match ty { - None => { - let guar = this.dcx().span_delayed_bug( - i.span, - "expected to lower associated type, but it was missing", - ); - let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err(guar))); - hir::ImplItemKind::Type(ty) - } - Some(ty) => { - let ty = this.lower_ty(ty, ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(i.id), - in_assoc_ty: true, - }, - }); - hir::ImplItemKind::Type(ty) - } - }, + ( + *ident, + self.lower_generics( + &generics, + i.id, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| match ty { + None => { + let guar = this.dcx().span_delayed_bug( + i.span, + "expected to lower associated type, but it was missing", + ); + let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err(guar))); + hir::ImplItemKind::Type(ty) + } + Some(ty) => { + let ty = this.lower_ty( + ty, + ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(i.id), + in_assoc_ty: true, + }, + }, + ); + hir::ImplItemKind::Type(ty) + } + }, + ), ) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, i.id); + let delegation_results = self.lower_delegation(delegation, i.id, is_in_trait_impl); ( - delegation_results.generics, - hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id), + delegation.ident, + ( + delegation_results.generics, + hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id), + ), ) } AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { @@ -1002,7 +1090,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let item = hir::ImplItem { owner_id: hir_id.expect_owner(), - ident: self.lower_ident(i.ident), + ident: self.lower_ident(ident), generics, kind, vis_span: self.lower_span(i.vis.span), @@ -1012,10 +1100,12 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(item) } - fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef { + fn lower_impl_item_ref(&mut self, i: &AssocItem, is_in_trait_impl: bool) -> hir::ImplItemRef { hir::ImplItemRef { - id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, - ident: self.lower_ident(i.ident), + id: hir::ImplItemId { owner_id: self.owner_id(i.id) }, + // `unwrap` is safe because `AssocItemKind::{MacCall,DelegationMac}` are the only + // assoc item kinds without an identifier and they cannot reach here. + ident: self.lower_ident(i.kind.ident().unwrap()), span: self.lower_span(i.span), kind: match &i.kind { AssocItemKind::Const(..) => hir::AssocItemKind::Const, @@ -1024,7 +1114,12 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { - has_self: self.delegation_has_self(i.id, delegation.id, i.span), + has_self: self.delegatee_is_method( + i.id, + delegation.id, + i.span, + is_in_trait_impl, + ), }, AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") @@ -1081,7 +1176,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs); + self.lower_attrs(hir_id, ¶m.attrs, param.span); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1093,38 +1188,107 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_fn_body( &mut self, decl: &FnDecl, + contract: Option<&FnContract>, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::BodyId { self.lower_body(|this| { - ( - this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x))), - body(this), - ) + let params = + this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x))); + + // Optionally lower the fn contract, which turns: + // + // { body } + // + // into: + // + // { contract_requires(PRECOND); let __postcond = |ret_val| POSTCOND; postcond({ body }) } + if let Some(contract) = contract { + let precond = if let Some(req) = &contract.requires { + // Lower the precondition check intrinsic. + let lowered_req = this.lower_expr_mut(&req); + let req_span = this.mark_span_with_reason( + DesugaringKind::Contract, + lowered_req.span, + None, + ); + let precond = this.expr_call_lang_item_fn_mut( + req_span, + hir::LangItem::ContractCheckRequires, + &*arena_vec![this; lowered_req], + ); + Some(this.stmt_expr(req.span, precond)) + } else { + None + }; + let (postcond, body) = if let Some(ens) = &contract.ensures { + let ens_span = this.lower_span(ens.span); + let ens_span = + this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None); + // Set up the postcondition `let` statement. + let check_ident: Ident = + Ident::from_str_and_span("__ensures_checker", ens_span); + let (checker_pat, check_hir_id) = this.pat_ident_binding_mode_mut( + ens_span, + check_ident, + hir::BindingMode::NONE, + ); + let lowered_ens = this.lower_expr_mut(&ens); + let postcond_checker = this.expr_call_lang_item_fn( + ens_span, + hir::LangItem::ContractBuildCheckEnsures, + &*arena_vec![this; lowered_ens], + ); + let postcond = this.stmt_let_pat( + None, + ens_span, + Some(postcond_checker), + this.arena.alloc(checker_pat), + hir::LocalSource::Contract, + ); + + // Install contract_ensures so we will intercept `return` statements, + // then lower the body. + this.contract_ensures = Some((ens_span, check_ident, check_hir_id)); + let body = this.arena.alloc(body(this)); + + // Finally, inject an ensures check on the implicit return of the body. + let body = this.inject_ensures_check(body, ens_span, check_ident, check_hir_id); + (Some(postcond), body) + } else { + let body = &*this.arena.alloc(body(this)); + (None, body) + }; + // Flatten the body into precond, then postcond, then wrapped body. + let wrapped_body = this.block_all( + body.span, + this.arena.alloc_from_iter([precond, postcond].into_iter().flatten()), + Some(body), + ); + (params, this.expr_block(wrapped_body)) + } else { + (params, body(this)) + } }) } fn lower_fn_body_block( &mut self, - span: Span, decl: &FnDecl, - body: Option<&Block>, + body: &Block, + contract: Option<&FnContract>, ) -> hir::BodyId { - self.lower_fn_body(decl, |this| this.lower_block_expr_opt(span, body)) - } - - fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> { - match block { - Some(block) => self.lower_block_expr(block), - None => self.expr_err(span, self.dcx().has_errors().unwrap()), - } + self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) } pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { self.lower_body(|this| { - (&[], match expr { - Some(expr) => this.lower_expr_mut(expr), - None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), - }) + ( + &[], + match expr { + Some(expr) => this.lower_expr_mut(expr), + None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), + }, + ) }) } @@ -1138,10 +1302,41 @@ impl<'hir> LoweringContext<'_, 'hir> { decl: &FnDecl, coroutine_kind: Option<CoroutineKind>, body: Option<&Block>, + attrs: &'hir [hir::Attribute], + contract: Option<&FnContract>, ) -> hir::BodyId { - let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else { - return self.lower_fn_body_block(span, decl, body); + let Some(body) = body else { + // Functions without a body are an error, except if this is an intrinsic. For those we + // create a fake body so that the entire rest of the compiler doesn't have to deal with + // this as a special case. + return self.lower_fn_body(decl, contract, |this| { + if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) { + let span = this.lower_span(span); + let empty_block = hir::Block { + hir_id: this.next_id(), + stmts: &[], + expr: None, + rules: hir::BlockCheckMode::DefaultBlock, + span, + targeted_by_break: false, + }; + let loop_ = hir::ExprKind::Loop( + this.arena.alloc(empty_block), + None, + hir::LoopSource::Loop, + span, + ); + hir::Expr { hir_id: this.next_id(), kind: loop_, span } + } else { + this.expr_err(span, this.dcx().has_errors().unwrap()) + } + }); + }; + let Some(coroutine_kind) = coroutine_kind else { + // Typical case: not a coroutine. + return self.lower_fn_body_block(decl, body, contract); }; + // FIXME(contracts): Support contracts on async fn. self.lower_body(|this| { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( decl, @@ -1153,7 +1348,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); // FIXME(async_fn_track_caller): Can this be moved above? - let hir_id = this.lower_node_id(coroutine_kind.closure_id()); + let hir_id = expr.hir_id; this.maybe_forward_track_caller(body.span, fn_id, hir_id); (parameters, expr) @@ -1220,9 +1415,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // we can keep the same name for the parameter. // This lets rustdoc render it correctly in documentation. hir::PatKind::Binding(_, _, ident, _) => (ident, false), - hir::PatKind::Wild => { - (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false) - } + hir::PatKind::Wild => (Ident::with_dummy_span(rustc_span::kw::Underscore), false), _ => { // Replace the ident for bindings that aren't simple. let name = format!("__arg{index}"); @@ -1370,18 +1563,13 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: FnDeclKind, coroutine_kind: Option<CoroutineKind>, - parent_constness: Const, + attrs: &[hir::Attribute], ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { - let header = self.lower_fn_header(sig.header, hir::Safety::Safe); - // Don't pass along the user-provided constness of trait associated functions; we don't want to - // synthesize a host effect param for them. We reject `const` on them during AST validation. - let constness = - if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness }; + let header = self.lower_fn_header(sig.header, hir::Safety::Safe, attrs); let itctx = ImplTraitContext::Universal; - let (generics, decl) = - self.lower_generics(generics, constness, kind == FnDeclKind::Impl, id, itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) - }); + let (generics, decl) = self.lower_generics(generics, id, itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1389,37 +1577,56 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, h: FnHeader, default_safety: hir::Safety, + attrs: &[hir::Attribute], ) -> hir::FnHeader { let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind { hir::IsAsync::Async(span) } else { hir::IsAsync::NotAsync }; + + let safety = self.lower_safety(h.safety, default_safety); + + // Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so. + let safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature)) + && safety.is_safe() + && !self.tcx.sess.target.is_like_wasm + { + hir::HeaderSafety::SafeTargetFeatures + } else { + safety.into() + }; + hir::FnHeader { - safety: self.lower_safety(h.safety, default_safety), + safety, asyncness, constness: self.lower_constness(h.constness), abi: self.lower_extern(h.ext), } } - pub(super) fn lower_abi(&mut self, abi: StrLit) -> abi::Abi { - abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|err| { - self.error_on_invalid_abi(abi, err); - abi::Abi::Rust - }) + pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi { + let ast::StrLit { symbol_unescaped, span, .. } = abi_str; + let extern_abi = symbol_unescaped.as_str().parse().unwrap_or_else(|_| { + self.error_on_invalid_abi(abi_str); + ExternAbi::Rust + }); + let sess = self.tcx.sess; + let features = self.tcx.features(); + gate_unstable_abi(sess, features, span, extern_abi); + extern_abi } - pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi { + pub(super) fn lower_extern(&mut self, ext: Extern) -> ExternAbi { match ext { - Extern::None => abi::Abi::Rust, - Extern::Implicit(_) => abi::Abi::FALLBACK, + Extern::None => ExternAbi::Rust, + Extern::Implicit(_) => ExternAbi::FALLBACK, Extern::Explicit(abi, _) => self.lower_abi(abi), } } - fn error_on_invalid_abi(&self, abi: StrLit, err: abi::AbiUnsupported) { - let abi_names = abi::enabled_names(self.tcx.features(), abi.span) + fn error_on_invalid_abi(&self, abi: StrLit) { + let abi_names = enabled_names(self.tcx.features(), abi.span) .iter() .map(|s| Symbol::intern(s)) .collect::<Vec<_>>(); @@ -1427,13 +1634,9 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(InvalidAbi { abi: abi.symbol_unescaped, span: abi.span, - explain: match err { - abi::AbiUnsupported::Reason { explain } => Some(InvalidAbiReason(explain)), - _ => None, - }, suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion { span: abi.span, - suggestion: format!("\"{suggested_name}\""), + suggestion: suggested_name.to_string(), }), command: "rustc --print=calling-conventions".to_string(), }); @@ -1446,7 +1649,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - pub(super) fn lower_safety(&mut self, s: Safety, default: hir::Safety) -> hir::Safety { + pub(super) fn lower_safety(&self, s: Safety, default: hir::Safety) -> hir::Safety { match s { Safety::Unsafe(_) => hir::Safety::Unsafe, Safety::Default => default, @@ -1460,8 +1663,6 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_generics<T>( &mut self, generics: &Generics, - constness: Const, - force_append_constness: bool, parent_node_id: NodeId, itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, @@ -1475,7 +1676,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // keep track of the Span info. Now, `<dyn HirTyLowerer>::add_implicit_sized_bound` // checks both param bounds and where clauses for `?Sized`. for pred in &generics.where_clause.predicates { - let WherePredicate::BoundPredicate(bound_pred) = pred else { + let WherePredicateKind::BoundPredicate(bound_pred) = &pred.kind else { continue; }; let compute_is_param = || { @@ -1512,7 +1713,7 @@ impl<'hir> LoweringContext<'_, 'hir> { continue; } let is_param = *is_param.get_or_insert_with(compute_is_param); - if !is_param && !self.tcx.features().more_maybe_bounds { + if !is_param && !self.tcx.features().more_maybe_bounds() { self.tcx .sess .create_feature_err( @@ -1524,30 +1725,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - // Desugar `~const` bound in generics into an additional `const host: bool` param - // if the effects feature is enabled. This needs to be done before we lower where - // clauses since where clauses need to bind to the DefId of the host param - let host_param_parts = if let Const::Yes(span) = constness - // if this comes from implementing a `const` trait, we must force constness to be appended - // to the impl item, no matter whether effects is enabled. - && (self.tcx.features().effects || force_append_constness) - { - let span = self.lower_span(span); - let param_node_id = self.next_node_id(); - let hir_id = self.next_id(); - let def_id = self.create_def( - self.local_def_id(parent_node_id), - param_node_id, - sym::host, - DefKind::ConstParam, - span, - ); - self.host_param_id = Some(def_id); - Some((span, hir_id, def_id)) - } else { - None - }; - let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new(); predicates.extend(generics.params.iter().filter_map(|param| { self.lower_generic_bound_predicate( @@ -1574,7 +1751,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .collect(); // Introduce extra lifetimes if late resolution tells us to. - let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); + let extra_lifetimes = self.resolver.extra_lifetime_params(parent_node_id); params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { self.lifetime_res_to_generic_param( ident, @@ -1595,74 +1772,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); predicates.extend(impl_trait_bounds.into_iter()); - if let Some((span, hir_id, def_id)) = host_param_parts { - let const_node_id = self.next_node_id(); - let anon_const_did = - self.create_def(def_id, const_node_id, kw::Empty, DefKind::AnonConst, span); - - let const_id = self.next_id(); - let const_expr_id = self.next_id(); - let bool_id = self.next_id(); - - self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id))); - - let const_body = self.lower_body(|this| { - (&[], hir::Expr { - hir_id: const_expr_id, - kind: hir::ExprKind::Lit( - this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), - ), - span, - }) - }); - - let default_ac = self.arena.alloc(hir::AnonConst { - def_id: anon_const_did, - hir_id: const_id, - body: const_body, - span, - }); - let default_ct = self.arena.alloc(hir::ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Anon(default_ac), - is_desugared_from_effects: false, - }); - let param = hir::GenericParam { - def_id, - hir_id, - name: hir::ParamName::Plain(Ident { name: sym::host, span }), - span, - kind: hir::GenericParamKind::Const { - ty: self.arena.alloc(self.ty( - span, - hir::TyKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - res: Res::PrimTy(hir::PrimTy::Bool), - span, - segments: self.arena.alloc_from_iter([hir::PathSegment { - ident: Ident { name: sym::bool, span }, - hir_id: bool_id, - res: Res::PrimTy(hir::PrimTy::Bool), - args: None, - infer_args: false, - }]), - }), - )), - )), - default: Some(default_ct), - is_host_effect: true, - synthetic: true, - }, - colon_span: None, - pure_wrt_drop: false, - source: hir::GenericParamSource::Generics, - }; - - params.push(param); - } - let lowered_generics = self.arena.alloc(hir::Generics { params: self.arena.alloc_from_iter(params), predicates: self.arena.alloc_from_iter(predicates), @@ -1674,6 +1783,35 @@ impl<'hir> LoweringContext<'_, 'hir> { (lowered_generics, res) } + pub(super) fn lower_define_opaque( + &mut self, + hir_id: HirId, + define_opaque: &Option<ThinVec<(NodeId, Path)>>, + ) { + assert_eq!(self.define_opaque, None); + assert!(hir_id.is_owner()); + let Some(define_opaque) = define_opaque.as_ref() else { + return; + }; + let define_opaque = define_opaque.iter().filter_map(|(id, path)| { + let res = self.resolver.get_partial_res(*id); + let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) else { + self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); + return None; + }; + let Some(did) = did.as_local() else { + self.dcx().span_err( + path.span, + "only opaque types defined in the local crate can be defined", + ); + return None; + }; + Some((self.lower_span(path.span), did)) + }); + let define_opaque = self.arena.alloc_from_iter(define_opaque); + self.define_opaque = Some(define_opaque); + } + pub(super) fn lower_generic_bound_predicate( &mut self, ident: Ident, @@ -1692,7 +1830,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let bounds = self.lower_param_bounds(bounds, itctx); - let ident = self.lower_ident(ident); let param_span = ident.span; // Reconstruct the span of the entire predicate from the individual generic bounds. @@ -1704,13 +1841,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } }); let span = self.lower_span(span); - - match kind { - GenericParamKind::Const { .. } => None, + let hir_id = self.next_id(); + let kind = self.arena.alloc(match kind { + GenericParamKind::Const { .. } => return None, GenericParamKind::Type { .. } => { let def_id = self.local_def_id(id).to_def_id(); let hir_id = self.next_id(); let res = Res::Def(DefKind::TyParam, def_id); + let ident = self.lower_ident(ident); let ty_path = self.arena.alloc(hir::Path { span: param_span, res, @@ -1721,38 +1859,36 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty_id = self.next_id(); let bounded_ty = self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path)); - Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - hir_id: self.next_id(), + hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { bounded_ty: self.arena.alloc(bounded_ty), bounds, - span, bound_generic_params: &[], origin, - })) + }) } GenericParamKind::Lifetime => { - let ident = self.lower_ident(ident); let lt_id = self.next_node_id(); - let lifetime = self.new_named_lifetime(id, lt_id, ident); - Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + let lifetime = self.new_named_lifetime(id, lt_id, ident, IsAnonInPath::No); + hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { lifetime, - span, bounds, in_where_clause: false, - })) + }) } - } + }); + Some(hir::WherePredicate { hir_id, span, kind }) } fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> { - match pred { - WherePredicate::BoundPredicate(WhereBoundPredicate { + let hir_id = self.lower_node_id(pred.id); + let span = self.lower_span(pred.span); + self.lower_attrs(hir_id, &pred.attrs, span); + let kind = self.arena.alloc(match &pred.kind { + WherePredicateKind::BoundPredicate(WhereBoundPredicate { bound_generic_params, bounded_ty, bounds, - span, - }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - hir_id: self.next_id(), + }) => hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { bound_generic_params: self .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), bounded_ty: self @@ -1761,12 +1897,10 @@ impl<'hir> LoweringContext<'_, 'hir> { bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), - span: self.lower_span(*span), origin: PredicateOrigin::WhereClause, }), - WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span }) => { - hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - span: self.lower_span(*span), + WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { + hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { lifetime: self.lower_lifetime(lifetime), bounds: self.lower_param_bounds( bounds, @@ -1775,15 +1909,15 @@ impl<'hir> LoweringContext<'_, 'hir> { in_where_clause: true, }) } - WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span }) => { - hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { + WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => { + hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate { lhs_ty: self .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), rhs_ty: self .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), - span: self.lower_span(*span), }) } - } + }); + hir::WherePredicate { hir_id, span, kind } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 00eafeb4d844d..c40987541f4a5 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -35,28 +35,27 @@ #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(exact_size_is_empty)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end -use std::collections::hash_map::Entry; +use std::sync::Arc; use rustc_ast::node_id::NodeMap; -use rustc_ast::ptr::P; use rustc_ast::{self as ast, *}; -use rustc_data_structures::captures::Captures; +use rustc_attr_parsing::{AttributeParser, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, MissingLifetimeKind, - ParamName, TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, IsAnonInPath, ItemLocalMap, LangItem, ParamName, + TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -85,9 +84,9 @@ mod expr; mod format; mod index; mod item; -mod lifetime_collector; mod pat; mod path; +pub mod stability; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -100,11 +99,15 @@ struct LoweringContext<'a, 'hir> { /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, + /// `#[define_opaque]` attributes + define_opaque: Option<&'hir [(Span, LocalDefId)]>, /// Attributes inside the owner being lowered. - attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>, + attrs: SortedMap<hir::ItemLocalId, &'hir [hir::Attribute]>, /// Collect items that were created by lowering the current owner. children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>, + contract_ensures: Option<(Span, Ident, HirId)>, + coroutine_kind: Option<hir::CoroutineKind>, /// When inside an `async` context, this is the `HirId` of the @@ -115,56 +118,37 @@ struct LoweringContext<'a, 'hir> { /// outside of an `async fn`. current_item: Option<Span>, - catch_scope: Option<NodeId>, - loop_scope: Option<NodeId>, + catch_scope: Option<HirId>, + loop_scope: Option<HirId>, is_in_loop_condition: bool, - is_in_trait_impl: bool, is_in_dyn_type: bool, current_hir_id_owner: hir::OwnerId, - /// Why do we need this in addition to [`Self::current_hir_id_owner`]? - /// - /// Currently (as of June 2024), anonymous constants are not HIR owners; however, - /// they do get their own DefIds. Some of these DefIds have to be created during - /// AST lowering, rather than def collection, because we can't tell until after - /// name resolution whether an anonymous constant will end up instead being a - /// [`hir::ConstArgKind::Path`]. However, to compute which generics are - /// available to an anonymous constant nested inside another, we need to make - /// sure that the parent is recorded as the parent anon const, not the enclosing - /// item. So we need to track parent defs differently from HIR owners, since they - /// will be finer-grained in the case of anon consts. - current_def_id_parent: LocalDefId, item_local_id_counter: hir::ItemLocalId, trait_map: ItemLocalMap<Box<[TraitCandidate]>>, impl_trait_defs: Vec<hir::GenericParam<'hir>>, impl_trait_bounds: Vec<hir::WherePredicate<'hir>>, - /// NodeIds that are lowered inside the current HIR owner. + /// NodeIds of pattern identifiers and labelled nodes that are lowered inside the current HIR owner. + ident_and_label_to_local_id: NodeMap<hir::ItemLocalId>, + /// NodeIds that are lowered inside the current HIR owner. Only used for duplicate lowering check. + #[cfg(debug_assertions)] node_id_to_local_id: NodeMap<hir::ItemLocalId>, - allow_try_trait: Lrc<[Symbol]>, - allow_gen_future: Lrc<[Symbol]>, - allow_async_iterator: Lrc<[Symbol]>, - allow_for_await: Lrc<[Symbol]>, - allow_async_fn_traits: Lrc<[Symbol]>, + allow_try_trait: Arc<[Symbol]>, + allow_gen_future: Arc<[Symbol]>, + allow_pattern_type: Arc<[Symbol]>, + allow_async_iterator: Arc<[Symbol]>, + allow_for_await: Arc<[Symbol]>, + allow_async_fn_traits: Arc<[Symbol]>, - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>, - - host_param_id: Option<LocalDefId>, - ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>, + attribute_parser: AttributeParser<'hir>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { - fn new( - tcx: TyCtxt<'hir>, - resolver: &'a mut ResolverAstLowering, - ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>, - ) -> Self { + fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { + let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect(); Self { // Pseudo-globals. tcx, @@ -173,11 +157,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // HirId handling. bodies: Vec::new(), + define_opaque: None, attrs: SortedMap::default(), children: Vec::default(), + contract_ensures: None, current_hir_id_owner: hir::CRATE_OWNER_ID, - current_def_id_parent: CRATE_DEF_ID, item_local_id_counter: hir::ItemLocalId::ZERO, + ident_and_label_to_local_id: Default::default(), + #[cfg(debug_assertions)] node_id_to_local_id: Default::default(), trait_map: Default::default(), @@ -185,7 +172,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { catch_scope: None, loop_scope: None, is_in_loop_condition: false, - is_in_trait_impl: false, is_in_dyn_type: false, coroutine_kind: None, task_context: None, @@ -193,7 +179,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { impl_trait_defs: Vec::new(), impl_trait_bounds: Vec::new(), allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(), - allow_gen_future: if tcx.features().async_fn_track_caller { + allow_pattern_type: [sym::pattern_types, sym::pattern_type_range_trait].into(), + allow_gen_future: if tcx.features().async_fn_track_caller() { [sym::gen_future, sym::closure_track_caller].into() } else { [sym::gen_future].into() @@ -203,9 +190,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), - generics_def_id_map: Default::default(), - host_param_id: None, - ast_index, + + attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools), } } @@ -241,7 +227,6 @@ impl ResolverAstLowering { None } - /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> { self.partial_res_map.get(&id).copied() } @@ -268,8 +253,8 @@ impl ResolverAstLowering { /// /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring /// should appear at the enclosing `PolyTraitRef`. - fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { - self.extra_lifetime_params_map.remove(&id).unwrap_or_default() + fn extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { + self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default() } } @@ -288,7 +273,14 @@ enum ImplTraitContext { /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`. /// - OpaqueTy { origin: hir::OpaqueTyOrigin }, + OpaqueTy { origin: hir::OpaqueTyOrigin<LocalDefId> }, + + /// Treat `impl Trait` as a "trait ascription", which is like a type + /// variable but that also enforces that a set of trait goals hold. + /// + /// This is useful to guide inference for unnameable types. + InBinding, + /// `impl Trait` is unstably accepted in this position. FeatureGated(ImplTraitPosition, Symbol), /// `impl Trait` is not accepted in this position. @@ -424,7 +416,7 @@ fn compute_hir_hash( .iter_enumerated() .filter_map(|(def_id, info)| { let info = info.as_owner()?; - let def_path_hash = tcx.hir().def_path_hash(def_id); + let def_path_hash = tcx.hir_def_path_hash(def_id); Some((def_path_hash, info)) }) .collect(); @@ -440,10 +432,10 @@ fn compute_hir_hash( pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { let sess = tcx.sess; // Queries that borrow `resolver_for_lowering`. - tcx.ensure_with_value().output_filenames(()); - tcx.ensure_with_value().early_lint_checks(()); - tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE); - tcx.ensure_with_value().get_lang_items(()); + tcx.ensure_done().output_filenames(()); + tcx.ensure_done().early_lint_checks(()); + tcx.ensure_done().debugger_visualizers(LOCAL_CRATE); + tcx.ensure_done().get_lang_items(()); let (mut resolver, krate) = tcx.resolver_for_lowering().steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); @@ -504,7 +496,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, parent: LocalDefId, node_id: ast::NodeId, - name: Symbol, + name: Option<Symbol>, def_kind: DefKind, span: Span, ) -> LocalDefId { @@ -514,7 +506,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { "adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}", node_id, def_kind, - self.tcx.hir().def_key(self.local_def_id(node_id)), + self.tcx.hir_def_key(self.local_def_id(node_id)), ); let def_id = self.tcx.at(span).create_def(parent, name, def_kind).def_id(); @@ -534,52 +526,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any). - fn orig_opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { - self.resolver.node_id_to_def_id.get(&node).copied() - } - - /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name - /// resolver (if any), after applying any remapping from `get_remapped_def_id`. - /// - /// For example, in a function like `fn foo<'a>(x: &'a u32)`, - /// invoking with the id from the `ast::Lifetime` node found inside - /// the `&'a u32` type would return the `LocalDefId` of the - /// `'a` parameter declared on `foo`. - /// - /// This function also applies remapping from `get_remapped_def_id`. - /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth. - /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`, - /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`. - /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`. fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { - self.orig_opt_local_def_id(node).map(|local_def_id| self.get_remapped_def_id(local_def_id)) + self.resolver.node_id_to_def_id.get(&node).copied() } fn local_def_id(&self, node: NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } - /// Get the previously recorded `to` local def id given the `from` local def id, obtained using - /// `generics_def_id_map` field. - fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId { - // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we - // push new mappings, so we first need to get the latest (innermost) mappings, hence `iter().rev()`. - // - // Consider: - // - // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` - // - // We would end with a generics_def_id_map like: - // - // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` - // - // for the opaque type generated on `impl Sized + 'b`, we want the result to be: impl_sized#'b. - // So, if we were trying to find first from the start (outermost) would give the wrong result, impl_trait#'b. - self.generics_def_id_map - .iter() - .rev() - .find_map(|map| map.get(&local_def_id).copied()) - .unwrap_or(local_def_id) + /// Given the id of an owner node in the AST, returns the corresponding `OwnerId`. + fn owner_id(&self, node: NodeId) -> hir::OwnerId { + hir::OwnerId { def_id: self.local_def_id(node) } } /// Freshen the `LoweringContext` and ready it to lower a nested item. @@ -593,14 +550,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>, ) { - let def_id = self.local_def_id(owner); + let owner_id = self.owner_id(owner); let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); - let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); + let current_define_opaque = std::mem::take(&mut self.define_opaque); + let current_ident_and_label_to_local_id = + std::mem::take(&mut self.ident_and_label_to_local_id); + + #[cfg(debug_assertions)] + let current_node_id_to_local_id = std::mem::take(&mut self.node_id_to_local_id); let current_trait_map = std::mem::take(&mut self.trait_map); - let current_owner = - std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); + let current_owner = std::mem::replace(&mut self.current_hir_id_owner, owner_id); let current_local_counter = std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs); @@ -611,11 +572,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s. // Always allocate the first `HirId` for the owner itself. - let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); - debug_assert_eq!(_old, None); + #[cfg(debug_assertions)] + { + let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); + debug_assert_eq!(_old, None); + } - let item = self.with_def_id_parent(def_id, f); - debug_assert_eq!(def_id, item.def_id().def_id); + let item = f(self); + debug_assert_eq!(owner_id, item.def_id()); // `f` should have consumed all the elements in these vectors when constructing `item`. debug_assert!(self.impl_trait_defs.is_empty()); debug_assert!(self.impl_trait_bounds.is_empty()); @@ -623,48 +587,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; - self.node_id_to_local_id = current_node_ids; + self.define_opaque = current_define_opaque; + self.ident_and_label_to_local_id = current_ident_and_label_to_local_id; + + #[cfg(debug_assertions)] + { + self.node_id_to_local_id = current_node_id_to_local_id; + } self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; self.impl_trait_defs = current_impl_trait_defs; self.impl_trait_bounds = current_impl_trait_bounds; - debug_assert!(!self.children.iter().any(|(id, _)| id == &def_id)); - self.children.push((def_id, hir::MaybeOwner::Owner(info))); - } - - fn with_def_id_parent<T>(&mut self, parent: LocalDefId, f: impl FnOnce(&mut Self) -> T) -> T { - let current_def_id_parent = std::mem::replace(&mut self.current_def_id_parent, parent); - let result = f(self); - self.current_def_id_parent = current_def_id_parent; - result - } - - /// Installs the remapping `remap` in scope while `f` is being executed. - /// This causes references to the `LocalDefId` keys to be changed to - /// refer to the values instead. - /// - /// The remapping is used when one piece of AST expands to multiple - /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`, - /// expands to both a function definition (`foo`) and a TAIT for the return value, - /// both of which have a lifetime parameter `'a`. The remapping allows us to - /// rewrite the `'a` in the return value to refer to the - /// `'a` declared on the TAIT, instead of the function. - fn with_remapping<R>( - &mut self, - remap: LocalDefIdMap<LocalDefId>, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - self.generics_def_id_map.push(remap); - let res = f(self); - self.generics_def_id_map.pop(); - res + debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id)); + self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info))); } fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); + let define_opaque = std::mem::take(&mut self.define_opaque); let trait_map = std::mem::take(&mut self.trait_map); #[cfg(debug_assertions)] @@ -680,48 +623,46 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Don't hash unless necessary, because it's expensive. let (opt_hash_including_bodies, attrs_hash) = - self.tcx.hash_owner_nodes(node, &bodies, &attrs); + self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; - let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash }; + let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque }; self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) } - /// This method allocates a new `HirId` for the given `NodeId` and stores it in - /// the `LoweringContext`'s `NodeId => HirId` map. + /// This method allocates a new `HirId` for the given `NodeId`. /// Take care not to call this method if the resulting `HirId` is then not /// actually used in the HIR, as that would trigger an assertion in the /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped - /// properly. Calling the method twice with the same `NodeId` is fine though. + /// properly. Calling the method twice with the same `NodeId` is also forbidden. #[instrument(level = "debug", skip(self), ret)] fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId { assert_ne!(ast_node_id, DUMMY_NODE_ID); - match self.node_id_to_local_id.entry(ast_node_id) { - Entry::Occupied(o) => HirId { owner: self.current_hir_id_owner, local_id: *o.get() }, - Entry::Vacant(v) => { - // Generate a new `HirId`. - let owner = self.current_hir_id_owner; - let local_id = self.item_local_id_counter; - let hir_id = HirId { owner, local_id }; - - v.insert(local_id); - self.item_local_id_counter.increment_by(1); + let owner = self.current_hir_id_owner; + let local_id = self.item_local_id_counter; + assert_ne!(local_id, hir::ItemLocalId::ZERO); + self.item_local_id_counter.increment_by(1); + let hir_id = HirId { owner, local_id }; - assert_ne!(local_id, hir::ItemLocalId::ZERO); - if let Some(def_id) = self.opt_local_def_id(ast_node_id) { - self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - } + if let Some(def_id) = self.opt_local_def_id(ast_node_id) { + self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); + } - if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { - self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice()); - } + if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { + self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice()); + } - hir_id - } + // Check whether the same `NodeId` is lowered more than once. + #[cfg(debug_assertions)] + { + let old = self.node_id_to_local_id.insert(ast_node_id, local_id); + assert_eq!(old, None); } + + hir_id } /// Generate a new `HirId` without a backing `NodeId`. @@ -738,7 +679,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_res(&mut self, res: Res<NodeId>) -> Res { let res: Result<Res, ()> = res.apply_id(|id| { let owner = self.current_hir_id_owner; - let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?; + let local_id = self.ident_and_label_to_local_id.get(&id).copied().ok_or(())?; Ok(HirId { owner, local_id }) }); trace!(?res); @@ -802,10 +743,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &self, reason: DesugaringKind, span: Span, - allow_internal_unstable: Option<Lrc<[Symbol]>>, + allow_internal_unstable: Option<Arc<[Symbol]>>, ) -> Span { self.tcx.with_stable_hashing_context(|hcx| { - span.mark_with_reason(allow_internal_unstable, reason, self.tcx.sess.edition(), hcx) + span.mark_with_reason(allow_internal_unstable, reason, span.edition(), hcx) }) } @@ -840,9 +781,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Fresh { param, kind, .. } => { // Late resolution delegates to us the creation of the `LocalDefId`. let _def_id = self.create_def( - self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent? + self.current_hir_id_owner.def_id, param, - kw::UnderscoreLifetime, + Some(kw::UnderscoreLifetime), DefKind::LifetimeParam, ident.span, ); @@ -885,7 +826,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut generic_params: Vec<_> = self .lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder) .collect(); - let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder); + let extra_lifetimes = self.resolver.extra_lifetime_params(binder); debug!(?extra_lifetimes); generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { self.lifetime_res_to_generic_param(ident, node_id, res, hir::GenericParamSource::Binder) @@ -914,12 +855,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; + let old_contract = self.contract_ensures.take(); + let catch_scope = self.catch_scope.take(); let loop_scope = self.loop_scope.take(); let ret = f(self); self.catch_scope = catch_scope; self.loop_scope = loop_scope; + self.contract_ensures = old_contract; + self.is_in_loop_condition = was_in_loop_condition; self.current_item = current_item; @@ -927,37 +872,38 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ret } - fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> &'hir [Attribute] { + fn lower_attrs( + &mut self, + id: HirId, + attrs: &[Attribute], + target_span: Span, + ) -> &'hir [hir::Attribute] { if attrs.is_empty() { &[] } else { + let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); + debug_assert_eq!(id.owner, self.current_hir_id_owner); - let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))); - debug_assert!(!ret.is_empty()); - self.attrs.insert(id.local_id, ret); - ret + let ret = self.arena.alloc_from_iter(lowered_attrs); + + // this is possible if an item contained syntactical attribute, + // but none of them parse succesfully or all of them were ignored + // for not being built-in attributes at all. They could be remaining + // unexpanded attributes used as markers in proc-macro derives for example. + // This will have emitted some diagnostics for the misparse, but will then + // not emit the attribute making the list empty. + if ret.is_empty() { + &[] + } else { + self.attrs.insert(id.local_id, ret); + ret + } } } - fn lower_attr(&self, attr: &Attribute) -> Attribute { - // Note that we explicitly do not walk the path. Since we don't really - // lower attributes (we use the AST version) there is nowhere to keep - // the `HirId`s. We don't actually need HIR version of attributes anyway. - // Tokens are also not needed after macro expansion and parsing. - let kind = match attr.kind { - AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr { - item: AttrItem { - unsafety: normal.item.unsafety, - path: normal.item.path.clone(), - args: self.lower_attr_args(&normal.item.args), - tokens: None, - }, - tokens: None, - })), - AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data), - }; - - Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) } + fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> { + self.attribute_parser + .parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s)) } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { @@ -969,39 +915,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_attr_args(&self, args: &AttrArgs) -> AttrArgs { - match args { - AttrArgs::Empty => AttrArgs::Empty, - AttrArgs::Delimited(args) => AttrArgs::Delimited(self.lower_delim_args(args)), - // This is an inert key-value attribute - it will never be visible to macros - // after it gets lowered to HIR. Therefore, we can extract literals to handle - // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). - AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => { - // In valid code the value always ends up as a single literal. Otherwise, a dummy - // literal suffices because the error is handled elsewhere. - let lit = if let ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span) - { - lit - } else { - let guar = self.dcx().has_errors().unwrap(); - MetaItemLit { - symbol: kw::Empty, - suffix: None, - kind: LitKind::Err(guar), - span: DUMMY_SP, - } - }; - AttrArgs::Eq(*eq_span, AttrArgsEq::Hir(lit)) - } - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => { - unreachable!("in literal form when lowering mac args eq: {:?}", lit) - } - } - } - fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs { - DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() } + DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() } } /// Lower an associated item constraint. @@ -1022,20 +937,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if let Some(first_char) = constraint.ident.as_str().chars().next() && first_char.is_ascii_lowercase() { - let mut err = if !data.inputs.is_empty() { - self.dcx().create_err(errors::BadReturnTypeNotation::Inputs { - span: data.inputs_span, - }) - } else if let FnRetTy::Ty(ty) = &data.output { - self.dcx().create_err(errors::BadReturnTypeNotation::Output { - span: data.inputs_span.shrink_to_hi().to(ty.span), - }) - } else { - self.dcx().create_err(errors::BadReturnTypeNotation::NeedsDots { - span: data.inputs_span, - }) + let err = match (&data.inputs[..], &data.output) { + ([_, ..], FnRetTy::Default(_)) => { + errors::BadReturnTypeNotation::Inputs { span: data.inputs_span } + } + ([], FnRetTy::Default(_)) => { + errors::BadReturnTypeNotation::NeedsDots { span: data.inputs_span } + } + // The case `T: Trait<method(..) -> Ret>` is handled in the parser. + (_, FnRetTy::Ty(ty)) => { + let span = data.inputs_span.shrink_to_hi().to(ty.span); + errors::BadReturnTypeNotation::Output { + span, + suggestion: errors::RTNSuggestion { + output: span, + input: data.inputs_span, + }, + } + } }; - if !self.tcx.features().return_type_notation + let mut err = self.dcx().create_err(err); + if !self.tcx.features().return_type_notation() && self.tcx.sess.is_nightly_build() { add_feature_diagnostics( @@ -1159,17 +1081,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), ast::GenericArg::Type(ty) => { + // We cannot just match on `TyKind::Infer` as `(_)` is represented as + // `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer` + if ty.is_maybe_parenthesised_infer() { + return GenericArg::Infer(hir::InferArg { + hir_id: self.lower_node_id(ty.id), + span: self.lower_span(ty.span), + }); + } + match &ty.kind { - TyKind::Infer if self.tcx.features().generic_arg_infer => { - return GenericArg::Infer(hir::InferArg { - hir_id: self.lower_node_id(ty.id), - span: self.lower_span(ty.span), - }); - } // We parse const arguments as path types as we cannot distinguish them during // parsing. We try to resolve that ambiguity by attempting resolution in both the // type and value namespaces. If we resolved the path in the value namespace, we // transform it into a generic const argument. + // + // FIXME: Should we be handling `(PATH_TO_CONST)`? TyKind::Path(None, path) => { if let Some(res) = self .resolver @@ -1177,7 +1104,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .and_then(|partial_res| partial_res.full_res()) { if !res.matches_ns(Namespace::TypeNS) - && path.is_potential_trivial_const_arg() + && path.is_potential_trivial_const_arg(false) { debug!( "lower_generic_arg: Lowering type argument as const argument: {:?}", @@ -1186,15 +1113,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let ct = self.lower_const_path_to_const_arg(path, res, ty.id, ty.span); - return GenericArg::Const(ct); + return GenericArg::Const(ct.try_as_ambig_ct().unwrap()); } } } _ => {} } - GenericArg::Type(self.lower_ty(ty, itctx)) + GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap()) + } + ast::GenericArg::Const(ct) => { + GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap()) } - ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)), } } @@ -1234,7 +1163,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lifetime_bound = this.elided_dyn_bound(t.span); (bounds, lifetime_bound) }); - let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None); + let kind = hir::TyKind::TraitObject( + bounds, + TaggedRef::new(lifetime_bound, TraitObjectSyntax::None), + ); return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() }; } @@ -1261,7 +1193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { - TyKind::Infer => hir::TyKind::Infer, + TyKind::Infer => hir::TyKind::Infer(()), TyKind::Err(guar) => hir::TyKind::Err(*guar), TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), @@ -1314,7 +1246,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { safety: self.lower_safety(f.safety, hir::Safety::Safe), abi: self.lower_extern(f.ext), decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None), - param_names: self.lower_fn_params_to_names(&f.decl), + param_idents: self.lower_fn_params_to_idents(&f.decl), + })) + } + TyKind::UnsafeBinder(f) => { + let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); + hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy { + generic_params, + inner_ty: self.lower_ty(&f.inner_ty, itctx), })) } TyKind::Never => hir::TyKind::Never, @@ -1344,9 +1283,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }), )) } - TyKind::Array(ty, length) => { - hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length)) - } + TyKind::Array(ty, length) => hir::TyKind::Array( + self.lower_ty(ty, itctx), + self.lower_array_length_to_const_arg(length), + ), TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const_to_anon_const(expr)), TyKind::TraitObject(bounds, kind) => { let mut lifetime_bound = None; @@ -1377,7 +1317,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span)); (bounds, lifetime_bound) }); - hir::TyKind::TraitObject(bounds, lifetime_bound, *kind) + hir::TyKind::TraitObject(bounds, TaggedRef::new(lifetime_bound, *kind)) } TyKind::ImplTrait(def_node_id, bounds) => { let span = t.span; @@ -1408,6 +1348,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } path } + ImplTraitContext::InBinding => { + hir::TyKind::TraitAscription(self.lower_param_bounds(bounds, itctx)) + } ImplTraitContext::FeatureGated(position, feature) => { let guar = self .tcx @@ -1431,7 +1374,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } - TyKind::Pat(ty, pat) => hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_pat(pat)), + TyKind::Pat(ty, pat) => { + hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span)) + } TyKind::MacCall(_) => { span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") } @@ -1483,7 +1428,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_opaque_impl_trait( &mut self, span: Span, - origin: hir::OpaqueTyOrigin, + origin: hir::OpaqueTyOrigin<LocalDefId>, opaque_ty_node_id: NodeId, bounds: &GenericBounds, itctx: ImplTraitContext, @@ -1495,102 +1440,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - let captured_lifetimes_to_duplicate = if let Some(args) = - // We only look for one `use<...>` syntax since we syntactially reject more than one. - bounds.iter().find_map( - |bound| match bound { - ast::GenericBound::Use(a, _) => Some(a), - _ => None, - }, - ) { - // We'll actually validate these later on; all we need is the list of - // lifetimes to duplicate during this portion of lowering. - args.iter() - .filter_map(|arg| match arg { - PreciseCapturingArg::Lifetime(lt) => Some(*lt), - PreciseCapturingArg::Arg(..) => None, - }) - // Add in all the lifetimes mentioned in the bounds. We will error - // them out later, but capturing them here is important to make sure - // they actually get resolved in resolve_bound_vars. - .chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)) - .collect() - } else { - match origin { - hir::OpaqueTyOrigin::TyAlias { .. } => { - // type alias impl trait and associated type position impl trait were - // decided to capture all in-scope lifetimes, which we collect for - // all opaques during resolution. - self.resolver - .take_extra_lifetime_params(opaque_ty_node_id) - .into_iter() - .map(|(ident, id, _)| Lifetime { id, ident }) - .collect() - } - hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => { - if in_trait_or_impl.is_some() - || self.tcx.features().lifetime_capture_rules_2024 - || span.at_least_rust_2024() - { - // return-position impl trait in trait was decided to capture all - // in-scope lifetimes, which we collect for all opaques during resolution. - self.resolver - .take_extra_lifetime_params(opaque_ty_node_id) - .into_iter() - .map(|(ident, id, _)| Lifetime { id, ident }) - .collect() - } else { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` - // example, we only need to duplicate lifetimes that appear in the - // bounds, since those are the only ones that are captured by the opaque. - lifetime_collector::lifetimes_in_bounds(self.resolver, bounds) - } - } - hir::OpaqueTyOrigin::AsyncFn { .. } => { - unreachable!("should be using `lower_async_fn_ret_ty`") - } - } - }; - debug!(?captured_lifetimes_to_duplicate); - - // Feature gate for RPITIT + use<..> - match origin { - rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { - if !self.tcx.features().precise_capturing_in_traits - && let Some(span) = bounds.iter().find_map(|bound| match *bound { - ast::GenericBound::Use(_, span) => Some(span), - _ => None, - }) - { - let mut diag = - self.tcx.dcx().create_err(errors::NoPreciseCapturesOnRpitit { span }); - add_feature_diagnostics( - &mut diag, - self.tcx.sess, - sym::precise_capturing_in_traits, - ); - diag.emit(); - } - } - _ => {} - } - - self.lower_opaque_inner( - opaque_ty_node_id, - origin, - captured_lifetimes_to_duplicate, - span, - opaque_ty_span, - |this| this.lower_param_bounds(bounds, itctx), - ) + self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| { + this.lower_param_bounds(bounds, itctx) + }) } fn lower_opaque_inner( &mut self, opaque_ty_node_id: NodeId, - origin: hir::OpaqueTyOrigin, - captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>, - span: Span, + origin: hir::OpaqueTyOrigin<LocalDefId>, opaque_ty_span: Span, lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { @@ -1598,145 +1456,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id); debug!(?opaque_ty_def_id, ?opaque_ty_hir_id); - // Map from captured (old) lifetime to synthetic (new) lifetime. - // Used to resolve lifetimes in the bounds of the opaque. - let mut captured_to_synthesized_mapping = LocalDefIdMap::default(); - // List of (early-bound) synthetic lifetimes that are owned by the opaque. - // This is used to create the `hir::Generics` owned by the opaque. - let mut synthesized_lifetime_definitions = vec![]; - // Pairs of lifetime arg (that resolves to the captured lifetime) - // and the def-id of the (early-bound) synthetic lifetime definition. - // This is used both to create generics for the `TyKind::OpaqueDef` that - // we return, and also as a captured lifetime mapping for RPITITs. - let mut synthesized_lifetime_args = vec![]; - - for lifetime in captured_lifetimes_to_duplicate { - let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error); - let (old_def_id, missing_kind) = match res { - LifetimeRes::Param { param: old_def_id, binder: _ } => (old_def_id, None), - - LifetimeRes::Fresh { param, kind, .. } => { - debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - if let Some(old_def_id) = self.orig_opt_local_def_id(param) { - (old_def_id, Some(kind)) - } else { - self.dcx() - .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime"); - continue; - } - } - - // Opaques do not capture `'static` - LifetimeRes::Static { .. } | LifetimeRes::Error => { - continue; - } - - res => { - let bug_msg = format!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, lifetime.ident, lifetime.ident.span - ); - span_bug!(lifetime.ident.span, "{}", bug_msg); - } - }; - - if captured_to_synthesized_mapping.get(&old_def_id).is_none() { - // Create a new lifetime parameter local to the opaque. - let duplicated_lifetime_node_id = self.next_node_id(); - let duplicated_lifetime_def_id = self.create_def( - opaque_ty_def_id, - duplicated_lifetime_node_id, - lifetime.ident.name, - DefKind::LifetimeParam, - self.lower_span(lifetime.ident.span), - ); - captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id); - // FIXME: Instead of doing this, we could move this whole loop - // into the `with_hir_id_owner`, then just directly construct - // the `hir::GenericParam` here. - synthesized_lifetime_definitions.push(( - duplicated_lifetime_node_id, - duplicated_lifetime_def_id, - self.lower_ident(lifetime.ident), - missing_kind, - )); - - // Now make an arg that we can use for the generic params of the opaque tykind. - let id = self.next_node_id(); - let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res); - let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id); - synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id)) - } - } - - let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| { - // Install the remapping from old to new (if any). This makes sure that - // any lifetimes that would have resolved to the def-id of captured - // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. - let bounds = this - .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); - - let generic_params = - this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map( - |&(new_node_id, new_def_id, ident, missing_kind)| { - let hir_id = this.lower_node_id(new_node_id); - let (name, kind) = if ident.name == kw::UnderscoreLifetime { - ( - hir::ParamName::Fresh, - hir::LifetimeParamKind::Elided( - missing_kind.unwrap_or(MissingLifetimeKind::Underscore), - ), - ) - } else { - (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) - }; - - hir::GenericParam { - hir_id, - def_id: new_def_id, - name, - span: ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }, - )); - debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); - - let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args); - - trace!("registering opaque type with id {:#?}", opaque_ty_def_id); - let opaque_ty_def = hir::OpaqueTy { - hir_id: opaque_ty_hir_id, - def_id: opaque_ty_def_id, - generics: this.arena.alloc(hir::Generics { - params: generic_params, - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: this.lower_span(span), - span: this.lower_span(span), - }), - bounds, - origin, - lifetime_mapping, - span: this.lower_span(opaque_ty_span), - }; - this.arena.alloc(opaque_ty_def) - }); - - let generic_args = self.arena.alloc_from_iter( - synthesized_lifetime_args - .iter() - .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), - ); + let bounds = lower_item_bounds(self); + let opaque_ty_def = hir::OpaqueTy { + hir_id: opaque_ty_hir_id, + def_id: opaque_ty_def_id, + bounds, + origin, + span: self.lower_span(opaque_ty_span), + }; + let opaque_ty_def = self.arena.alloc(opaque_ty_def); - // Create the `Foo<...>` reference itself. Note that the `type - // Foo = impl Trait` is, internally, created as a child of the - // async fn, so the *type parameters* are inherited. It's - // only the lifetime parameters that we must supply. - hir::TyKind::OpaqueDef(opaque_ty_def, generic_args) + hir::TyKind::OpaqueDef(opaque_ty_def) } fn lower_precise_capturing_args( @@ -1763,10 +1493,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { })) } - fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { + fn lower_fn_params_to_idents(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] { self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind { - PatKind::Ident(_, ident, _) => self.lower_ident(ident), - _ => Ident::new(kw::Empty, self.lower_span(param.pat.span)), + PatKind::Missing => None, + PatKind::Ident(_, ident, _) => Some(self.lower_ident(ident)), + PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))), + _ => { + self.dcx().span_delayed_bug( + param.pat.span, + "non-missing/ident/wild param pat must trigger an error", + ); + None + } })) } @@ -1911,20 +1649,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None), CoroutineKind::Gen { return_impl_trait_id, .. } => (return_impl_trait_id, None), CoroutineKind::AsyncGen { return_impl_trait_id, .. } => { - (return_impl_trait_id, Some(self.allow_async_iterator.clone())) + (return_impl_trait_id, Some(Arc::clone(&self.allow_async_iterator))) } }; let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features); - let captured_lifetimes = self - .resolver - .take_extra_lifetime_params(opaque_ty_node_id) - .into_iter() - .map(|(ident, id, _)| Lifetime { id, ident }) - .collect(); - let in_trait_or_impl = match fn_kind { FnDeclKind::Trait => Some(hir::RpitContext::Trait), FnDeclKind::Impl => Some(hir::RpitContext::TraitImpl), @@ -1935,8 +1666,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_ref = self.lower_opaque_inner( opaque_ty_node_id, hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, - captured_lifetimes, - span, opaque_ty_span, |this| { let bound = this.lower_coroutine_fn_output_type_to_bound( @@ -1993,7 +1722,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::GenericBound::Trait(hir::PolyTraitRef { bound_generic_params: &[], - modifiers: hir::TraitBoundModifier::None, + modifiers: hir::TraitBoundModifiers::NONE, trait_ref: hir::TraitRef { path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)), hir_ref_id: self.next_id(), @@ -2021,59 +1750,62 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime { - let ident = self.lower_ident(l.ident); - self.new_named_lifetime(l.id, l.id, ident) + self.new_named_lifetime(l.id, l.id, l.ident, IsAnonInPath::No) + } + + fn lower_lifetime_anon_in_path(&mut self, id: NodeId, span: Span) -> &'hir hir::Lifetime { + self.new_named_lifetime(id, id, Ident::new(kw::UnderscoreLifetime, span), IsAnonInPath::Yes) } #[instrument(level = "debug", skip(self))] - fn new_named_lifetime_with_res( + fn new_named_lifetime( &mut self, id: NodeId, + new_id: NodeId, ident: Ident, - res: LifetimeRes, + is_anon_in_path: IsAnonInPath, ) -> &'hir hir::Lifetime { + let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); let res = match res { - LifetimeRes::Param { param, .. } => { - let param = self.get_remapped_def_id(param); - hir::LifetimeName::Param(param) - } + LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param), LifetimeRes::Fresh { param, .. } => { + debug_assert_eq!(ident.name, kw::UnderscoreLifetime); let param = self.local_def_id(param); - hir::LifetimeName::Param(param) + hir::LifetimeKind::Param(param) + } + LifetimeRes::Infer => { + debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + hir::LifetimeKind::Infer + } + LifetimeRes::Static { .. } => { + debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); + hir::LifetimeKind::Static + } + LifetimeRes::Error => hir::LifetimeKind::Error, + LifetimeRes::ElidedAnchor { .. } => { + panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span); } - LifetimeRes::Infer => hir::LifetimeName::Infer, - LifetimeRes::Static { .. } => hir::LifetimeName::Static, - LifetimeRes::Error => hir::LifetimeName::Error, - res => panic!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, ident, ident.span - ), }; + #[cfg(debug_assertions)] + if is_anon_in_path == IsAnonInPath::Yes { + debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + } + debug!(?res); - self.arena.alloc(hir::Lifetime { - hir_id: self.lower_node_id(id), - ident: self.lower_ident(ident), + self.arena.alloc(hir::Lifetime::new( + self.lower_node_id(new_id), + self.lower_ident(ident), res, - }) + is_anon_in_path, + )) } - #[instrument(level = "debug", skip(self))] - fn new_named_lifetime( + fn lower_generic_params_mut( &mut self, - id: NodeId, - new_id: NodeId, - ident: Ident, - ) -> &'hir hir::Lifetime { - let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); - self.new_named_lifetime_with_res(new_id, ident, res) - } - - fn lower_generic_params_mut<'s>( - &'s mut self, - params: &'s [GenericParam], + params: &[GenericParam], source: hir::GenericParamSource, - ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> { + ) -> impl Iterator<Item = hir::GenericParam<'hir>> { params.iter().map(move |param| self.lower_generic_param(param, source)) } @@ -2091,14 +1823,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param: &GenericParam, source: hir::GenericParamSource, ) -> hir::GenericParam<'hir> { - let (name, kind) = self.lower_generic_param_kind( - param, - source, - attr::contains_name(¶m.attrs, sym::rustc_runtime), - ); + let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs); + self.lower_attrs(hir_id, ¶m.attrs, param.span()); hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), @@ -2115,17 +1843,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, param: &GenericParam, source: hir::GenericParamSource, - is_host_effect: bool, ) -> (hir::ParamName, hir::GenericParamKind<'hir>) { match ¶m.kind { GenericParamKind::Lifetime => { // AST resolution emitted an error on those parameters, so we lower them using // `ParamName::Error`. + let ident = self.lower_ident(param.ident); let param_name = if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) { - ParamName::Error + ParamName::Error(ident) } else { - let ident = self.lower_ident(param.ident); ParamName::Plain(ident) }; let kind = @@ -2181,7 +1908,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ( hir::ParamName::Plain(self.lower_ident(param.ident)), - hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false }, + hir::GenericParamKind::Const { ty, default, synthetic: false }, ) } } @@ -2239,11 +1966,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx)) } - fn lower_param_bounds_mut<'s>( - &'s mut self, - bounds: &'s [GenericBound], + fn lower_param_bounds_mut( + &mut self, + bounds: &[GenericBound], itctx: ImplTraitContext, - ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> { + ) -> impl Iterator<Item = hir::GenericBound<'hir>> { bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) } @@ -2304,15 +2031,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.expr_block(block) } - fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> { - match c.value.kind { + fn lower_array_length_to_const_arg(&mut self, c: &AnonConst) -> &'hir hir::ConstArg<'hir> { + // We cannot just match on `ExprKind::Underscore` as `(_)` is represented as + // `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer` + match c.value.peel_parens().kind { ExprKind::Underscore => { - if self.tcx.features().generic_arg_infer { - hir::ArrayLen::Infer(hir::InferArg { - hir_id: self.lower_node_id(c.id), - span: self.lower_span(c.value.span), - }) - } else { + if !self.tcx.features().generic_arg_infer() { feature_err( &self.tcx.sess, sym::generic_arg_infer, @@ -2320,13 +2044,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fluent_generated::ast_lowering_underscore_array_length_unstable, ) .stash(c.value.span, StashKey::UnderscoreForArrayLengths); - hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c)) } + let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ()); + self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind }) } - _ => hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c)), + _ => self.lower_anon_const_to_const_arg(c), } } + /// Used when lowering a type argument that turned out to actually be a const argument. + /// + /// Only use for that purpose since otherwise it will create a duplicate def. #[instrument(level = "debug", skip(self))] fn lower_const_path_to_const_arg( &mut self, @@ -2335,58 +2063,58 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ty_id: NodeId, span: Span, ) -> &'hir hir::ConstArg<'hir> { - let ct_kind = match res { - Res::Def(DefKind::ConstParam, _) => { - let qpath = self.lower_qpath( - ty_id, - &None, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - hir::ConstArgKind::Path(qpath) - } - _ => { - // Construct an AnonConst where the expr is the "ty"'s path. + let tcx = self.tcx; - let parent_def_id = self.current_def_id_parent; - let node_id = self.next_node_id(); - let span = self.lower_span(span); - - // Add a definition for the in-band const def. - let def_id = - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); - let hir_id = self.lower_node_id(node_id); + let ct_kind = if path + .is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) + && (tcx.features().min_generic_const_args() + || matches!(res, Res::Def(DefKind::ConstParam, _))) + { + let qpath = self.lower_qpath( + ty_id, + &None, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + // FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + hir::ConstArgKind::Path(qpath) + } else { + // Construct an AnonConst where the expr is the "ty"'s path. + + let parent_def_id = self.current_hir_id_owner.def_id; + let node_id = self.next_node_id(); + let span = self.lower_span(span); + + // Add a definition for the in-band const def. + // We're lowering a const argument that was originally thought to be a type argument, + // so the def collector didn't create the def ahead of time. That's why we have to do + // it here. + let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); + let hir_id = self.lower_node_id(node_id); + + let path_expr = Expr { + id: ty_id, + kind: ExprKind::Path(None, path.clone()), + span, + attrs: AttrVec::new(), + tokens: None, + }; - let path_expr = Expr { - id: ty_id, - kind: ExprKind::Path(None, path.clone()), + let ct = self.with_new_scopes(span, |this| { + self.arena.alloc(hir::AnonConst { + def_id, + hir_id, + body: this.lower_const_body(path_expr.span, Some(&path_expr)), span, - attrs: AttrVec::new(), - tokens: None, - }; - - let ct = self.with_new_scopes(span, |this| { - self.arena.alloc(hir::AnonConst { - def_id, - hir_id, - body: this.with_def_id_parent(def_id, |this| { - this.lower_const_body(path_expr.span, Some(&path_expr)) - }), - span, - }) - }); - hir::ConstArgKind::Anon(ct) - } + }) + }); + hir::ConstArgKind::Anon(ct) }; - self.arena.alloc(hir::ConstArg { - hir_id: self.next_id(), - kind: ct_kind, - is_desugared_from_effects: false, - }) + self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind }) } /// See [`hir::ConstArg`] for when to use this function vs @@ -2397,6 +2125,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { + let tcx = self.tcx; // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = if let ExprKind::Block(block, _) = &anon.value.kind @@ -2410,11 +2139,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let maybe_res = self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); - debug!("res={:?}", maybe_res); - // FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path - if let Some(res) = maybe_res - && let Res::Def(DefKind::ConstParam, _) = res - && let ExprKind::Path(qself, path) = &expr.kind + if let ExprKind::Path(qself, path) = &expr.kind + && path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) + && (tcx.features().min_generic_const_args() + || matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))) { let qpath = self.lower_qpath( expr.id, @@ -2422,51 +2150,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path, ParamMode::Optional, AllowReturnTypeNotation::No, + // FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); return ConstArg { - hir_id: self.next_id(), + hir_id: self.lower_node_id(anon.id), kind: hir::ConstArgKind::Path(qpath), - is_desugared_from_effects: false, }; } let lowered_anon = self.lower_anon_const_to_anon_const(anon); - ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Anon(lowered_anon), - is_desugared_from_effects: false, - } + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) } } /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_const_arg`]. fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst { - if c.value.is_potential_trivial_const_arg(true) { - // HACK(min_generic_const_args): see DefCollector::visit_anon_const - // Over there, we guess if this is a bare param and only create a def if - // we think it's not. However we may can guess wrong (see there for example) - // in which case we have to create the def here. - self.create_def( - self.current_def_id_parent, - c.id, - kw::Empty, - DefKind::AnonConst, - c.value.span, - ); - } - self.arena.alloc(self.with_new_scopes(c.value.span, |this| { let def_id = this.local_def_id(c.id); let hir_id = this.lower_node_id(c.id); hir::AnonConst { def_id, hir_id, - body: this.with_def_id_parent(def_id, |this| { - this.lower_const_body(c.value.span, Some(&c.value)) - }), + body: this.lower_const_body(c.value.span, Some(&c.value)), span: this.lower_span(c.value.span), } })) @@ -2482,22 +2190,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_bound_modifiers( &mut self, modifiers: TraitBoundModifiers, - ) -> hir::TraitBoundModifier { - // Invalid modifier combinations will cause an error during AST validation. - // Arbitrarily pick a placeholder for them to make compilation proceed. - match (modifiers.constness, modifiers.polarity) { - (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None, - (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, - (BoundConstness::Never, BoundPolarity::Negative(_)) => { - if self.tcx.features().negative_bounds { - hir::TraitBoundModifier::Negative - } else { - hir::TraitBoundModifier::None - } - } - (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const, - (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst, - } + ) -> hir::TraitBoundModifiers { + hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity } } // Helper methods for building HIR. @@ -2512,7 +2206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn stmt_let_pat( &mut self, - attrs: Option<&'hir [Attribute]>, + attrs: Option<&'hir [hir::Attribute]>, span: Span, init: Option<&'hir hir::Expr<'hir>>, pat: &'hir hir::Pat<'hir>, @@ -2524,6 +2218,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs.insert(hir_id.local_id, a); } let local = hir::LetStmt { + super_: None, hir_id, init, pat, @@ -2663,7 +2358,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { let principal = hir::PolyTraitRef { bound_generic_params: &[], - modifiers: hir::TraitBoundModifier::None, + modifiers: hir::TraitBoundModifiers::NONE, trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, span: self.lower_span(span), }; @@ -2673,8 +2368,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir_id = self.next_id(); hir::TyKind::TraitObject( arena_vec![self; principal], - self.elided_dyn_bound(span), - TraitObjectSyntax::None, + TaggedRef::new(self.elided_dyn_bound(span), TraitObjectSyntax::None), ) } _ => hir::TyKind::Path(hir::QPath::Resolved(None, path)), @@ -2691,11 +2385,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// when the bound is written, even if it is written with `'_` like in /// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked. fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime { - let r = hir::Lifetime { - hir_id: self.next_id(), - ident: Ident::new(kw::Empty, self.lower_span(span)), - res: hir::LifetimeName::ImplicitObjectLifetimeDefault, - }; + let r = hir::Lifetime::new( + self.next_id(), + Ident::new(kw::UnderscoreLifetime, self.lower_span(span)), + hir::LifetimeKind::ImplicitObjectLifetimeDefault, + IsAnonInPath::No, + ); debug!("elided_dyn_bound: r={:?}", r); self.arena.alloc(r) } diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs deleted file mode 100644 index fe64160fb4dcf..0000000000000 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ /dev/null @@ -1,118 +0,0 @@ -use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def::{DefKind, LifetimeRes, Res}; -use rustc_middle::span_bug; -use rustc_middle::ty::ResolverAstLowering; -use rustc_span::Span; -use rustc_span::symbol::{Ident, kw}; - -use super::ResolverAstLoweringExt; - -struct LifetimeCollectVisitor<'ast> { - resolver: &'ast ResolverAstLowering, - current_binders: Vec<NodeId>, - collected_lifetimes: FxIndexSet<Lifetime>, -} - -impl<'ast> LifetimeCollectVisitor<'ast> { - fn new(resolver: &'ast ResolverAstLowering) -> Self { - Self { resolver, current_binders: Vec::new(), collected_lifetimes: FxIndexSet::default() } - } - - fn record_lifetime_use(&mut self, lifetime: Lifetime) { - match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) { - LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => { - if !self.current_binders.contains(&binder) { - self.collected_lifetimes.insert(lifetime); - } - } - LifetimeRes::Static { .. } | LifetimeRes::Error => { - self.collected_lifetimes.insert(lifetime); - } - LifetimeRes::Infer => {} - res => { - let bug_msg = format!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, lifetime.ident, lifetime.ident.span - ); - span_bug!(lifetime.ident.span, "{}", bug_msg); - } - } - } - - /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit - /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids - /// in the list start..end. - fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) { - if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(node_id) - { - for i in start..end { - let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) }; - self.record_lifetime_use(lifetime); - } - } - } -} - -impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { - fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) { - self.record_lifetime_use(*lifetime); - } - - fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { - self.record_elided_anchor(path_segment.id, path_segment.ident.span); - visit::walk_path_segment(self, path_segment); - } - - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) { - self.current_binders.push(t.trait_ref.ref_id); - - visit::walk_poly_trait_ref(self, t); - - self.current_binders.pop(); - } - - fn visit_ty(&mut self, t: &'ast Ty) { - match &t.kind { - TyKind::Path(None, _) => { - // We can sometimes encounter bare trait objects - // which are represented in AST as paths. - if let Some(partial_res) = self.resolver.get_partial_res(t.id) - && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = - partial_res.full_res() - { - self.current_binders.push(t.id); - visit::walk_ty(self, t); - self.current_binders.pop(); - } else { - visit::walk_ty(self, t); - } - } - TyKind::BareFn(_) => { - self.current_binders.push(t.id); - visit::walk_ty(self, t); - self.current_binders.pop(); - } - TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => { - self.record_elided_anchor(t.id, t.span); - visit::walk_ty(self, t); - } - _ => { - visit::walk_ty(self, t); - } - } - } -} - -pub(crate) fn lifetimes_in_bounds( - resolver: &ResolverAstLowering, - bounds: &GenericBounds, -) -> FxIndexSet<Lifetime> { - let mut visitor = LifetimeCollectVisitor::new(resolver); - for bound in bounds { - visitor.visit_param_bound(bound, BoundKind::Bound); - } - visitor.collected_lifetimes -} diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 760f84564f1a2..f94d788a9b0e6 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,11 +1,13 @@ +use std::sync::Arc; + use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir as hir; -use rustc_hir::def::Res; -use rustc_span::Span; -use rustc_span::source_map::Spanned; -use rustc_span::symbol::Ident; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{self as hir, LangItem}; +use rustc_middle::span_bug; +use rustc_span::source_map::{Spanned, respan}; +use rustc_span::{DesugaringKind, Ident, Span}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -21,16 +23,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { ensure_sufficient_stack(|| { // loop here to avoid recursion + let pat_hir_id = self.lower_node_id(pattern.id); let node = loop { match &pattern.kind { + PatKind::Missing => break hir::PatKind::Missing, PatKind::Wild => break hir::PatKind::Wild, PatKind::Never => break hir::PatKind::Never, PatKind::Ident(binding_mode, ident, sub) => { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s)); - break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub); + break self.lower_pat_ident( + pattern, + *binding_mode, + *ident, + pat_hir_id, + lower_sub, + ); } - PatKind::Lit(e) => { - break hir::PatKind::Lit(self.lower_expr_within_pat(e, false)); + PatKind::Expr(e) => { + break hir::PatKind::Expr(self.lower_expr_within_pat(e, false)); } PatKind::TupleStruct(qself, path, pats) => { let qpath = self.lower_qpath( @@ -60,7 +70,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); - break hir::PatKind::Path(qpath); + let kind = hir::PatExprKind::Path(qpath); + let span = self.lower_span(pattern.span); + let expr = hir::PatExpr { hir_id: pat_hir_id, span, kind }; + let expr = self.arena.alloc(expr); + return hir::Pat { + hir_id: self.next_id(), + kind: hir::PatKind::Expr(expr), + span, + default_binding_modes: true, + }; } PatKind::Struct(qself, path, fields, etc) => { let qpath = self.lower_qpath( @@ -75,7 +94,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::PatField { hir_id, @@ -85,7 +104,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: self.lower_span(f.span), } })); - break hir::PatKind::Struct(qpath, fs, *etc == ast::PatFieldsRest::Rest); + break hir::PatKind::Struct( + qpath, + fs, + matches!( + etc, + ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) + ), + ); } PatKind::Tuple(pats) => { let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); @@ -107,6 +133,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_range_end(end, e2.is_some()), ); } + PatKind::Guard(inner, cond) => { + break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond)); + } PatKind::Slice(pats) => break self.lower_pat_slice(pats), PatKind::Rest => { // If we reach here the `..` pattern is not semantically allowed. @@ -119,7 +148,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }; - self.pat_with_node_id_of(pattern, node) + self.pat_with_node_id_of(pattern, node, pat_hir_id) }) } @@ -187,10 +216,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut prev_rest_span = None; // Lowers `$bm $ident @ ..` to `$bm $ident @ _`. - let lower_rest_sub = |this: &mut Self, pat, &ann, &ident, sub| { - let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); - let node = this.lower_pat_ident(pat, ann, ident, lower_sub); - this.pat_with_node_id_of(pat, node) + let lower_rest_sub = |this: &mut Self, pat: &Pat, &ann, &ident, sub: &Pat| { + let sub_hir_id = this.lower_node_id(sub.id); + let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub, sub_hir_id)); + let pat_hir_id = this.lower_node_id(pat.id); + let node = this.lower_pat_ident(pat, ann, ident, pat_hir_id, lower_sub); + this.pat_with_node_id_of(pat, node, pat_hir_id) }; let mut iter = pats.iter(); @@ -200,7 +231,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here. PatKind::Rest => { prev_rest_span = Some(pat.span); - slice = Some(self.pat_wild_with_node_id_of(pat)); + let hir_id = self.lower_node_id(pat.id); + slice = Some(self.pat_wild_with_node_id_of(pat, hir_id)); break; } // Found a sub-slice pattern `$binding_mode $ident @ ..`. @@ -248,50 +280,70 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &Pat, annotation: BindingMode, ident: Ident, + hir_id: hir::HirId, lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, ) -> hir::PatKind<'hir> { match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) { // `None` can occur in body-less function signatures res @ (None | Some(Res::Local(_))) => { - let canonical_id = match res { - Some(Res::Local(id)) => id, - _ => p.id, + let binding_id = match res { + Some(Res::Local(id)) => { + // In `Or` patterns like `VariantA(s) | VariantB(s, _)`, multiple identifier patterns + // will be resolved to the same `Res::Local`. Thus they just share a single + // `HirId`. + if id == p.id { + self.ident_and_label_to_local_id.insert(id, hir_id.local_id); + hir_id + } else { + hir::HirId { + owner: self.current_hir_id_owner, + local_id: self.ident_and_label_to_local_id[&id], + } + } + } + _ => { + self.ident_and_label_to_local_id.insert(p.id, hir_id.local_id); + hir_id + } }; - hir::PatKind::Binding( annotation, - self.lower_node_id(canonical_id), + binding_id, self.lower_ident(ident), lower_sub(self), ) } Some(res) => { - let hir_id = self.next_id(); let res = self.lower_res(res); - hir::PatKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - span: self.lower_span(ident.span), - res, - segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)], - }), - )) + let span = self.lower_span(ident.span); + hir::PatKind::Expr(self.arena.alloc(hir::PatExpr { + kind: hir::PatExprKind::Path(hir::QPath::Resolved( + None, + self.arena.alloc(hir::Path { + span, + res, + segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), self.next_id(), res)], + }), + )), + hir_id: self.next_id(), + span, + })) } } } - fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { - self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild)) + fn pat_wild_with_node_id_of(&mut self, p: &Pat, hir_id: hir::HirId) -> &'hir hir::Pat<'hir> { + self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild, hir_id)) } - /// Construct a `Pat` with the `HirId` of `p.id` lowered. - fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> { - hir::Pat { - hir_id: self.lower_node_id(p.id), - kind, - span: self.lower_span(p.span), - default_binding_modes: true, - } + /// Construct a `Pat` with the `HirId` of `p.id` already lowered. + fn pat_with_node_id_of( + &mut self, + p: &Pat, + kind: hir::PatKind<'hir>, + hir_id: hir::HirId, + ) -> hir::Pat<'hir> { + hir::Pat { hir_id, kind, span: self.lower_span(p.span), default_binding_modes: true } } /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. @@ -332,24 +384,171 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // } // m!(S); // ``` - fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> { - match &expr.kind { - ExprKind::Lit(..) - | ExprKind::ConstBlock(..) - | ExprKind::IncludedBytes(..) - | ExprKind::Err(_) - | ExprKind::Dummy => {} - ExprKind::Path(..) if allow_paths => {} - ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} + fn lower_expr_within_pat( + &mut self, + expr: &Expr, + allow_paths: bool, + ) -> &'hir hir::PatExpr<'hir> { + let span = self.lower_span(expr.span); + let err = |guar| hir::PatExprKind::Lit { + lit: self.arena.alloc(respan(span, LitKind::Err(guar))), + negated: false, + }; + let kind = match &expr.kind { + ExprKind::Lit(lit) => { + hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false } + } + ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)), + ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit { + lit: self + .arena + .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))), + negated: false, + }, + ExprKind::Err(guar) => err(*guar), + ExprKind::Dummy => span_bug!(span, "lowered ExprKind::Dummy"), + ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath( + expr.id, + qself, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + )), + ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => { + hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true } + } _ => { let pattern_from_macro = expr.is_approximately_pattern(); let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { - span: expr.span, + span, pattern_from_macro_note: pattern_from_macro, }); - return self.arena.alloc(self.expr_err(expr.span, guar)); + err(guar) } - } - self.lower_expr(expr) + }; + self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind }) + } + + pub(crate) fn lower_ty_pat( + &mut self, + pattern: &TyPat, + base_type: Span, + ) -> &'hir hir::TyPat<'hir> { + self.arena.alloc(self.lower_ty_pat_mut(pattern, base_type)) + } + + fn lower_ty_pat_mut(&mut self, pattern: &TyPat, base_type: Span) -> hir::TyPat<'hir> { + // loop here to avoid recursion + let pat_hir_id = self.lower_node_id(pattern.id); + let node = match &pattern.kind { + TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range( + e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| { + self.lower_ty_pat_range_end( + hir::LangItem::RangeMin, + span.shrink_to_lo(), + base_type, + ) + }), + e2.as_deref() + .map(|e| match end { + RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e), + RangeEnd::Excluded => self.lower_excluded_range_end(e), + }) + .unwrap_or_else(|| { + self.lower_ty_pat_range_end( + hir::LangItem::RangeMax, + span.shrink_to_hi(), + base_type, + ) + }), + ), + TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar), + }; + + hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) } + } + + /// Lowers the range end of an exclusive range (`2..5`) to an inclusive range 2..=(5 - 1). + /// This way the type system doesn't have to handle the distinction between inclusive/exclusive ranges. + fn lower_excluded_range_end(&mut self, e: &AnonConst) -> &'hir hir::ConstArg<'hir> { + let span = self.lower_span(e.value.span); + let unstable_span = self.mark_span_with_reason( + DesugaringKind::PatTyRange, + span, + Some(Arc::clone(&self.allow_pattern_type)), + ); + let anon_const = self.with_new_scopes(span, |this| { + let def_id = this.local_def_id(e.id); + let hir_id = this.lower_node_id(e.id); + let body = this.lower_body(|this| { + // Need to use a custom function as we can't just subtract `1` from a `char`. + let kind = hir::ExprKind::Path(this.make_lang_item_qpath( + hir::LangItem::RangeSub, + unstable_span, + None, + )); + let fn_def = this.arena.alloc(hir::Expr { hir_id: this.next_id(), kind, span }); + let args = this.arena.alloc([this.lower_expr_mut(&e.value)]); + ( + &[], + hir::Expr { + hir_id: this.next_id(), + kind: hir::ExprKind::Call(fn_def, args), + span, + }, + ) + }); + hir::AnonConst { def_id, hir_id, body, span } + }); + self.arena.alloc(hir::ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)), + }) + } + + /// When a range has no end specified (`1..` or `1..=`) or no start specified (`..5` or `..=5`), + /// we instead use a constant of the MAX/MIN of the type. + /// This way the type system does not have to handle the lack of a start/end. + fn lower_ty_pat_range_end( + &mut self, + lang_item: LangItem, + span: Span, + base_type: Span, + ) -> &'hir hir::ConstArg<'hir> { + let parent_def_id = self.current_hir_id_owner.def_id; + let node_id = self.next_node_id(); + + // Add a definition for the in-band const def. + // We're generating a range end that didn't exist in the AST, + // so the def collector didn't create the def ahead of time. That's why we have to do + // it here. + let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); + let hir_id = self.lower_node_id(node_id); + + let unstable_span = self.mark_span_with_reason( + DesugaringKind::PatTyRange, + self.lower_span(span), + Some(Arc::clone(&self.allow_pattern_type)), + ); + let span = self.lower_span(base_type); + + let path_expr = hir::Expr { + hir_id: self.next_id(), + kind: hir::ExprKind::Path(self.make_lang_item_qpath(lang_item, unstable_span, None)), + span, + }; + + let ct = self.with_new_scopes(span, |this| { + self.arena.alloc(hir::AnonConst { + def_id, + hir_id, + body: this.lower_body(|_this| (&[], path_expr)), + span, + }) + }); + let hir_id = self.next_id(); + self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id }) } } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index e60488fdc8c74..0bd65aec10f49 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,19 +1,19 @@ +use std::sync::Arc; + use rustc_ast::{self as ast, *}; -use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::GenericArg; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_session::parse::add_feature_diagnostics; -use rustc_span::symbol::{Ident, kw, sym}; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span, Symbol}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; use super::errors::{ AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation, - GenericTypeWithParentheses, UseAngleBrackets, + GenericTypeWithParentheses, RTNSuggestion, UseAngleBrackets, }; use super::{ AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition, @@ -34,7 +34,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { modifiers: Option<ast::TraitBoundModifiers>, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); - let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); + let qself = qself + .as_ref() + // Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`. + .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))); let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); @@ -70,11 +73,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res && self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some() { - Some(self.allow_async_fn_traits.clone()) + Some(Arc::clone(&self.allow_async_fn_traits)) } else { None }; + // Only permit `impl Trait` in the final segment. E.g., we permit `Option<impl Trait>`, + // `option::Option<T>::Xyz<impl Trait>` and reject `option::Option<impl Trait>::Xyz`. + let itctx = |i| { + if i + 1 == p.segments.len() { + itctx + } else { + ImplTraitContext::Disallowed(ImplTraitPosition::Path) + } + }; + let path_span_lo = p.span.shrink_to_lo(); let proj_start = p.segments.len() - unresolved_segments; let path = self.arena.alloc(hir::Path { @@ -121,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, generic_args_mode, - itctx, + itctx(i), bound_modifier_allowed_features.clone(), ) }, @@ -185,7 +198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, generic_args_mode, - itctx, + itctx(i), None, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); @@ -245,7 +258,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Additional features ungated with a bound modifier like `async`. // This is passed down to the implicit associated type binding in // parenthesized bounds. - bound_modifier_allowed_features: Option<Lrc<[Symbol]>>, + bound_modifier_allowed_features: Option<Arc<[Symbol]>>, ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment); let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() { @@ -255,20 +268,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArgs::Parenthesized(data) => match generic_args_mode { GenericArgsMode::ReturnTypeNotation => { - let mut err = if !data.inputs.is_empty() { - self.dcx().create_err(BadReturnTypeNotation::Inputs { - span: data.inputs_span, - }) - } else if let FnRetTy::Ty(ty) = &data.output { - self.dcx().create_err(BadReturnTypeNotation::Output { - span: data.inputs_span.shrink_to_hi().to(ty.span), - }) - } else { - self.dcx().create_err(BadReturnTypeNotation::NeedsDots { - span: data.inputs_span, - }) + let err = match (&data.inputs[..], &data.output) { + ([_, ..], FnRetTy::Default(_)) => { + BadReturnTypeNotation::Inputs { span: data.inputs_span } + } + ([], FnRetTy::Default(_)) => { + BadReturnTypeNotation::NeedsDots { span: data.inputs_span } + } + // The case `T: Trait<method(..) -> Ret>` is handled in the parser. + (_, FnRetTy::Ty(ty)) => { + let span = data.inputs_span.shrink_to_hi().to(ty.span); + BadReturnTypeNotation::Output { + span, + suggestion: RTNSuggestion { + output: span, + input: data.inputs_span, + }, + } + } }; - if !self.tcx.features().return_type_notation + let mut err = self.dcx().create_err(err); + if !self.tcx.features().return_type_notation() && self.tcx.sess.is_nightly_build() { add_feature_diagnostics( @@ -428,12 +448,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generic_args.args.insert_many( 0, - (start.as_u32()..end.as_u32()).map(|i| { - let id = NodeId::from_u32(i); - let l = self.lower_lifetime(&Lifetime { - id, - ident: Ident::new(kw::Empty, elided_lifetime_span), - }); + (start..end).map(|id| { + let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span); GenericArg::Lifetime(l) }), ); @@ -478,7 +494,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, data: &ParenthesizedArgs, itctx: ImplTraitContext, - bound_modifier_allowed_features: Option<Lrc<[Symbol]>>, + bound_modifier_allowed_features: Option<Arc<[Symbol]>>, ) -> (GenericArgsCtor<'hir>, bool) { // Switch to `PassThrough` mode for anonymous lifetimes; this // means that we permit things like `&Ref<T>`, where `Ref` has @@ -496,7 +512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^ // ``` FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => { - if self.tcx.features().impl_trait_in_fn_trait_return { + if self.tcx.features().impl_trait_in_fn_trait_return() { self.lower_ty(ty, itctx) } else { self.lower_ty( @@ -513,7 +529,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; - let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))]; + let args = smallvec![GenericArg::Type( + self.arena.alloc(self.ty_tup(*inputs_span, inputs)).try_as_ambig_ty().unwrap() + )]; // If we have a bound like `async Fn() -> T`, make sure that we mark the // `Output = T` associated type bound with the right feature gates. diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs new file mode 100644 index 0000000000000..eb052ba1c6d78 --- /dev/null +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -0,0 +1,138 @@ +use std::fmt; + +use rustc_abi::ExternAbi; +use rustc_feature::Features; +use rustc_session::Session; +use rustc_session::parse::feature_err; +use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; + +pub(crate) fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> { + ExternAbi::ALL_VARIANTS + .into_iter() + .filter(|abi| extern_abi_enabled(features, span, **abi).is_ok()) + .map(|abi| abi.as_str()) + .collect() +} + +pub(crate) fn extern_abi_enabled( + features: &rustc_feature::Features, + span: Span, + abi: ExternAbi, +) -> Result<(), UnstableAbi> { + extern_abi_stability(abi).or_else(|unstable @ UnstableAbi { feature, .. }| { + if features.enabled(feature) || span.allows_unstable(feature) { + Ok(()) + } else { + Err(unstable) + } + }) +} + +#[allow(rustc::untranslatable_diagnostic)] +pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) { + match extern_abi_enabled(features, span, abi) { + Ok(_) => (), + Err(unstable_abi) => { + let explain = unstable_abi.to_string(); + feature_err(sess, unstable_abi.feature, span, explain).emit(); + } + } +} + +pub struct UnstableAbi { + abi: ExternAbi, + feature: Symbol, + explain: GateReason, +} + +enum GateReason { + Experimental, + ImplDetail, +} + +impl fmt::Display for UnstableAbi { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { abi, .. } = self; + match self.explain { + GateReason::Experimental => { + write!(f, "the extern {abi} ABI is experimental and subject to change") + } + GateReason::ImplDetail => { + write!(f, "the extern {abi} ABI is an implementation detail and perma-unstable") + } + } + } +} + +pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { + match abi { + // stable ABIs + ExternAbi::Rust + | ExternAbi::C { .. } + | ExternAbi::Cdecl { .. } + | ExternAbi::Stdcall { .. } + | ExternAbi::Fastcall { .. } + | ExternAbi::Thiscall { .. } + | ExternAbi::Aapcs { .. } + | ExternAbi::Win64 { .. } + | ExternAbi::SysV64 { .. } + | ExternAbi::System { .. } + | ExternAbi::EfiApi => Ok(()), + ExternAbi::Unadjusted => { + Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail }) + } + // experimental + ExternAbi::Vectorcall { .. } => Err(UnstableAbi { + abi, + feature: sym::abi_vectorcall, + explain: GateReason::Experimental, + }), + ExternAbi::RustCall => Err(UnstableAbi { + abi, + feature: sym::unboxed_closures, + explain: GateReason::Experimental, + }), + ExternAbi::RustCold => { + Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental }) + } + ExternAbi::GpuKernel => Err(UnstableAbi { + abi, + feature: sym::abi_gpu_kernel, + explain: GateReason::Experimental, + }), + ExternAbi::PtxKernel => { + Err(UnstableAbi { abi, feature: sym::abi_ptx, explain: GateReason::Experimental }) + } + ExternAbi::Msp430Interrupt => Err(UnstableAbi { + abi, + feature: sym::abi_msp430_interrupt, + explain: GateReason::Experimental, + }), + ExternAbi::X86Interrupt => Err(UnstableAbi { + abi, + feature: sym::abi_x86_interrupt, + explain: GateReason::Experimental, + }), + ExternAbi::AvrInterrupt | ExternAbi::AvrNonBlockingInterrupt => Err(UnstableAbi { + abi, + feature: sym::abi_avr_interrupt, + explain: GateReason::Experimental, + }), + ExternAbi::RiscvInterruptM | ExternAbi::RiscvInterruptS => Err(UnstableAbi { + abi, + feature: sym::abi_riscv_interrupt, + explain: GateReason::Experimental, + }), + ExternAbi::CCmseNonSecureCall => Err(UnstableAbi { + abi, + feature: sym::abi_c_cmse_nonsecure_call, + explain: GateReason::Experimental, + }), + ExternAbi::CCmseNonSecureEntry => Err(UnstableAbi { + abi, + feature: sym::cmse_nonsecure_entry, + explain: GateReason::Experimental, + }), + } +} diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index eace5ce820892..c738cb2aa2fd4 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -1,14 +1,15 @@ [package] name = "rustc_ast_passes" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start itertools = "0.12" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr = { path = "../rustc_attr" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } @@ -17,6 +18,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 92acaaa5f36b0..80754a8f65a69 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -79,6 +79,10 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de .suggestion = remove the {$remove_descr} .label = `extern` block begins here +ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed + .suggestion = specify an ABI + .help = prior to Rust 2024, a default ABI was inferred + ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel .suggestion = remove the attribute .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable @@ -146,8 +150,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f ast_passes_generic_default_trailing = generic parameters with a default must be trailing -ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters - ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features @@ -209,10 +211,6 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc} -ast_passes_show_span = {$msg} - -ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library - ast_passes_static_without_body = free static item without body .suggestion = provide a definition for the static diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 20a4f2120dcdf..1feb3e9bf9b40 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -20,6 +20,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; use itertools::{Either, Itertools}; +use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list}; use rustc_ast::*; @@ -34,9 +35,7 @@ use rustc_session::lint::builtin::{ PATTERNS_IN_FNS_WITHOUT_BODY, }; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; -use rustc_span::Span; -use rustc_span::symbol::{Ident, kw, sym}; -use rustc_target::spec::abi; +use rustc_span::{Ident, Span, kw, sym}; use thin_vec::thin_vec; use crate::errors::{self, TildeConstReason}; @@ -48,14 +47,14 @@ enum SelfSemantic { } enum TraitOrTraitImpl { - Trait { span: Span, constness: Option<Span> }, - TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: Span }, + Trait { span: Span, constness_span: Option<Span> }, + TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span }, } impl TraitOrTraitImpl { fn constness(&self) -> Option<Span> { match self { - Self::Trait { constness: Some(span), .. } + Self::Trait { constness_span: Some(span), .. } | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span), _ => None, } @@ -67,7 +66,7 @@ struct AstValidator<'a> { features: &'a Features, /// The span of the `extern` in an `extern { ... }` block, if any. - extern_mod: Option<Span>, + extern_mod_span: Option<Span>, outer_trait_or_trait_impl: Option<TraitOrTraitImpl>, @@ -76,14 +75,10 @@ struct AstValidator<'a> { /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`. /// Nested `impl Trait` _is_ allowed in associated type position, /// e.g., `impl Iterator<Item = impl Debug>`. - outer_impl_trait: Option<Span>, + outer_impl_trait_span: Option<Span>, disallow_tilde_const: Option<TildeConstReason>, - /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` - /// or `Foo::Bar<impl Trait>` - is_impl_trait_banned: bool, - /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option<Safety>, @@ -101,17 +96,22 @@ impl<'a> AstValidator<'a> { trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl { constness, polarity, - trait_ref: trait_ref.path.span, + trait_ref_span: trait_ref.path.span, }), ); f(self); self.outer_trait_or_trait_impl = old; } - fn with_in_trait(&mut self, span: Span, constness: Option<Span>, f: impl FnOnce(&mut Self)) { + fn with_in_trait( + &mut self, + span: Span, + constness_span: Option<Span>, + f: impl FnOnce(&mut Self), + ) { let old = mem::replace( &mut self.outer_trait_or_trait_impl, - Some(TraitOrTraitImpl::Trait { span, constness }), + Some(TraitOrTraitImpl::Trait { span, constness_span }), ); f(self); self.outer_trait_or_trait_impl = old; @@ -123,12 +123,6 @@ impl<'a> AstValidator<'a> { self.extern_mod_safety = old; } - fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_impl_trait_banned, true); - f(self); - self.is_impl_trait_banned = old; - } - fn with_tilde_const( &mut self, disallowed: Option<TildeConstReason>, @@ -181,10 +175,10 @@ impl<'a> AstValidator<'a> { Err(errors::WhereClauseBeforeTypeAlias { span, sugg }) } - fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.outer_impl_trait, outer); + fn with_impl_trait(&mut self, outer_span: Option<Span>, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.outer_impl_trait_span, outer_span); f(self); - self.outer_impl_trait = old; + self.outer_impl_trait_span = old; } // Mirrors `visit::walk_ty`, but tracks relevant state. @@ -213,43 +207,12 @@ impl<'a> AstValidator<'a> { .with_tilde_const(Some(TildeConstReason::TraitObject), |this| { visit::walk_ty(this, t) }), - TyKind::Path(qself, path) => { - // We allow these: - // - `Option<impl Trait>` - // - `option::Option<impl Trait>` - // - `option::Option<T>::Foo<impl Trait>` - // - // But not these: - // - `<impl Trait>::Foo` - // - `option::Option<impl Trait>::Foo`. - // - // To implement this, we disallow `impl Trait` from `qself` - // (for cases like `<impl Trait>::Foo>`) - // but we allow `impl Trait` in `GenericArgs` - // iff there are no more PathSegments. - if let Some(qself) = qself { - // `impl Trait` in `qself` is always illegal - self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); - } - - // Note that there should be a call to visit_path here, - // so if any logic is added to process `Path`s a call to it should be - // added both in visit_path and here. This code mirrors visit::walk_path. - for (i, segment) in path.segments.iter().enumerate() { - // Allow `impl Trait` iff we're on the final path segment - if i == path.segments.len() - 1 { - self.visit_path_segment(segment); - } else { - self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); - } - } - } _ => visit::walk_ty(self, t), } } fn visit_struct_field_def(&mut self, field: &'a FieldDef) { - if let Some(ident) = field.ident + if let Some(ref ident) = field.ident && ident.name == kw::Underscore { self.visit_vis(&field.vis); @@ -281,7 +244,7 @@ impl<'a> AstValidator<'a> { fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) { for Param { pat, .. } in &decl.inputs { match pat.kind { - PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {} + PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {} PatKind::Ident(BindingMode::MUT, ident, None) => { report_err(pat.span, Some(ident), true) } @@ -295,21 +258,22 @@ impl<'a> AstValidator<'a> { return; }; - let make_impl_const_sugg = if self.features.const_trait_impl + let const_trait_impl = self.features.const_trait_impl(); + let make_impl_const_sugg = if const_trait_impl && let TraitOrTraitImpl::TraitImpl { constness: Const::No, polarity: ImplPolarity::Positive, - trait_ref, + trait_ref_span, .. } = parent { - Some(trait_ref.shrink_to_lo()) + Some(trait_ref_span.shrink_to_lo()) } else { None }; - let make_trait_const_sugg = if self.features.const_trait_impl - && let TraitOrTraitImpl::Trait { span, constness: None } = parent + let make_trait_const_sugg = if const_trait_impl + && let TraitOrTraitImpl::Trait { span, constness_span: None } = parent { Some(span.shrink_to_lo()) } else { @@ -376,14 +340,14 @@ impl<'a> AstValidator<'a> { .filter(|attr| { let arr = [ sym::allow, - sym::cfg, - sym::cfg_attr, + sym::cfg_trace, + sym::cfg_attr_trace, sym::deny, sym::expect, sym::forbid, sym::warn, ]; - !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr) + !attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr) }) .for_each(|attr| { if attr.is_doc_comment() { @@ -490,13 +454,13 @@ impl<'a> AstValidator<'a> { check_where_clause(where_clauses.after); } - fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) { - let Some(body) = body else { + fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body_span: Option<Span>) { + let Some(body_span) = body_span else { return; }; self.dcx().emit_err(errors::BodyInExtern { span: ident.span, - body, + body: body_span, block: self.current_extern_span(), kind, }); @@ -515,7 +479,7 @@ impl<'a> AstValidator<'a> { } fn current_extern_span(&self) -> Span { - self.sess.source_map().guess_head_span(self.extern_mod.unwrap()) + self.sess.source_map().guess_head_span(self.extern_mod_span.unwrap()) } /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. @@ -625,9 +589,10 @@ impl<'a> AstValidator<'a> { self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name }); } - fn deny_generic_params(&self, generics: &Generics, ident: Span) { + fn deny_generic_params(&self, generics: &Generics, ident_span: Span) { if !generics.params.is_empty() { - self.dcx().emit_err(errors::AutoTraitGeneric { span: generics.span, ident }); + self.dcx() + .emit_err(errors::AutoTraitGeneric { span: generics.span, ident: ident_span }); } } @@ -647,11 +612,11 @@ impl<'a> AstValidator<'a> { } } - fn deny_items(&self, trait_items: &[P<AssocItem>], ident: Span) { + fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) { if !trait_items.is_empty() { - let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); + let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect(); let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); - self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident }); + self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident: ident_span }); } } @@ -718,9 +683,8 @@ impl<'a> AstValidator<'a> { Self::check_decl_no_pat(&bfty.decl, |span, _, _| { self.dcx().emit_err(errors::PatternFnPointer { span }); }); - if let Extern::Implicit(_) = bfty.ext { - let sig_span = self.sess.source_map().next_point(ty.span.shrink_to_lo()); - self.maybe_lint_missing_abi(sig_span, ty.id); + if let Extern::Implicit(extern_span) = bfty.ext { + self.handle_missing_abi(extern_span, ty.id); } } TyKind::TraitObject(bounds, ..) => { @@ -737,11 +701,7 @@ impl<'a> AstValidator<'a> { } } TyKind::ImplTrait(_, bounds) => { - if self.is_impl_trait_banned { - self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); - } - - if let Some(outer_impl_trait_sp) = self.outer_impl_trait { + if let Some(outer_impl_trait_sp) = self.outer_impl_trait_span { self.dcx().emit_err(errors::NestedImplTrait { span: ty.span, outer: outer_impl_trait_sp, @@ -757,10 +717,12 @@ impl<'a> AstValidator<'a> { } } - fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) { + fn handle_missing_abi(&mut self, span: Span, id: NodeId) { // FIXME(davidtwco): This is a hack to detect macros which produce spans of the // call site which do not have a macro backtrace. See #61963. - if self + if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() { + self.dcx().emit_err(errors::MissingAbi { span }); + } else if self .sess .source_map() .span_to_snippet(span) @@ -770,10 +732,23 @@ impl<'a> AstValidator<'a> { MISSING_ABI, id, span, - BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK), + BuiltinLintDiag::MissingAbi(span, ExternAbi::FALLBACK), ) } } + + // Used within `visit_item` for item kinds where we don't call `visit::walk_item`. + fn visit_attrs_vis(&mut self, attrs: &'a AttrVec, vis: &'a Visibility) { + walk_list!(self, visit_attribute, attrs); + self.visit_vis(vis); + } + + // Used within `visit_item` for item kinds where we don't call `visit::walk_item`. + fn visit_attrs_vis_ident(&mut self, attrs: &'a AttrVec, vis: &'a Visibility, ident: &'a Ident) { + walk_list!(self, visit_attribute, attrs); + self.visit_vis(vis); + self.visit_ident(ident); + } } /// Checks that generic parameters are in the correct order, @@ -864,8 +839,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } - if attr::contains_name(&item.attrs, sym::no_mangle) { - self.check_nomangle_item_asciionly(item.ident, item.span); + if let Some(ident) = item.kind.ident() + && attr::contains_name(&item.attrs, sym::no_mangle) + { + self.check_nomangle_item_asciionly(ident, item.span); } match &item.kind { @@ -879,37 +856,33 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self_ty, items, }) => { - self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| { - this.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::TraitImpl, - ); - if let TyKind::Dummy = self_ty.kind { - // Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering, - // which isn't allowed. Not a problem for this obscure, obsolete syntax. - this.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span }); - } - if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity) - { - this.dcx().emit_err(errors::UnsafeNegativeImpl { - span: sp.to(t.path.span), - negative: sp, - r#unsafe: span, - }); - } + self.visit_attrs_vis(&item.attrs, &item.vis); + self.visibility_not_permitted( + &item.vis, + errors::VisibilityNotPermittedNote::TraitImpl, + ); + if let TyKind::Dummy = self_ty.kind { + // Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering, + // which isn't allowed. Not a problem for this obscure, obsolete syntax. + self.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span }); + } + if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity) { + self.dcx().emit_err(errors::UnsafeNegativeImpl { + span: sp.to(t.path.span), + negative: sp, + r#unsafe: span, + }); + } - this.visit_vis(&item.vis); - this.visit_ident(item.ident); - let disallowed = matches!(constness, Const::No) - .then(|| TildeConstReason::TraitImpl { span: item.span }); - this.with_tilde_const(disallowed, |this| this.visit_generics(generics)); - this.visit_trait_ref(t); - this.visit_ty(self_ty); + let disallowed = matches!(constness, Const::No) + .then(|| TildeConstReason::TraitImpl { span: item.span }); + self.with_tilde_const(disallowed, |this| this.visit_generics(generics)); + self.visit_trait_ref(t); + self.visit_ty(self_ty); - walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); + self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| { + walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true }); }); - walk_list!(self, visit_attribute, &item.attrs); - return; // Avoid visiting again. } ItemKind::Impl(box Impl { safety, @@ -929,45 +902,53 @@ impl<'a> Visitor<'a> for AstValidator<'a> { only_trait, }; - self.with_in_trait_impl(None, |this| { - this.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::IndividualImplItems, - ); - if let &Safety::Unsafe(span) = safety { - this.dcx().emit_err(errors::InherentImplCannotUnsafe { - span: self_ty.span, - annotation_span: span, - annotation: "unsafe", - self_ty: self_ty.span, - }); - } - if let &ImplPolarity::Negative(span) = polarity { - this.dcx().emit_err(error(span, "negative", false)); - } - if let &Defaultness::Default(def_span) = defaultness { - this.dcx().emit_err(error(def_span, "`default`", true)); - } - if let &Const::Yes(span) = constness { - this.dcx().emit_err(error(span, "`const`", true)); - } + self.visit_attrs_vis(&item.attrs, &item.vis); + self.visibility_not_permitted( + &item.vis, + errors::VisibilityNotPermittedNote::IndividualImplItems, + ); + if let &Safety::Unsafe(span) = safety { + self.dcx().emit_err(errors::InherentImplCannotUnsafe { + span: self_ty.span, + annotation_span: span, + annotation: "unsafe", + self_ty: self_ty.span, + }); + } + if let &ImplPolarity::Negative(span) = polarity { + self.dcx().emit_err(error(span, "negative", false)); + } + if let &Defaultness::Default(def_span) = defaultness { + self.dcx().emit_err(error(def_span, "`default`", true)); + } + if let &Const::Yes(span) = constness { + self.dcx().emit_err(error(span, "`const`", true)); + } - this.visit_vis(&item.vis); - this.visit_ident(item.ident); - this.with_tilde_const( - Some(TildeConstReason::Impl { span: item.span }), - |this| this.visit_generics(generics), - ); - this.visit_ty(self_ty); - walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); + self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| { + this.visit_generics(generics) + }); + self.visit_ty(self_ty); + self.with_in_trait_impl(None, |this| { + walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false }); }); - walk_list!(self, visit_attribute, &item.attrs); - return; // Avoid visiting again. } - ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => { + ItemKind::Fn( + func @ box Fn { + defaultness, + ident, + generics: _, + sig, + contract: _, + body, + define_opaque: _, + }, + ) => { + self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.check_defaultness(item.span, *defaultness); - if body.is_none() { + let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); + if body.is_none() && !is_intrinsic { self.dcx().emit_err(errors::FnWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), @@ -990,46 +971,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - let kind = - FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); + let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func); self.visit_fn(kind, item.span, item.id); - walk_list!(self, visit_attribute, &item.attrs); - return; // Avoid visiting again. } - ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { - self.with_in_extern_mod(*safety, |this| { - let old_item = mem::replace(&mut this.extern_mod, Some(item.span)); - this.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::IndividualForeignItems, - ); + ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => { + let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span)); + self.visibility_not_permitted( + &item.vis, + errors::VisibilityNotPermittedNote::IndividualForeignItems, + ); - if &Safety::Default == safety { - if item.span.at_least_rust_2024() { - this.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span }); - } else { - this.lint_buffer.buffer_lint( - MISSING_UNSAFE_ON_EXTERN, - item.id, - item.span, - BuiltinLintDiag::MissingUnsafeOnExtern { - suggestion: item.span.shrink_to_lo(), - }, - ); - } + if &Safety::Default == safety { + if item.span.at_least_rust_2024() { + self.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span }); + } else { + self.lint_buffer.buffer_lint( + MISSING_UNSAFE_ON_EXTERN, + item.id, + item.span, + BuiltinLintDiag::MissingUnsafeOnExtern { + suggestion: item.span.shrink_to_lo(), + }, + ); } + } - if abi.is_none() { - this.maybe_lint_missing_abi(item.span, item.id); - } + if abi.is_none() { + self.handle_missing_abi(*extern_span, item.id); + } + self.with_in_extern_mod(*safety, |this| { visit::walk_item(this, item); - this.extern_mod = old_item; }); - return; // Avoid visiting again. + self.extern_mod_span = old_item; } - ItemKind::Enum(def, _) => { + ItemKind::Enum(_, def, _) => { for variant in &def.variants { self.visibility_not_permitted( &variant.vis, @@ -1042,73 +1017,65 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); } } + visit::walk_item(self, item) } - ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => { + ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => { + self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); let is_const_trait = attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); - self.with_in_trait(item.span, is_const_trait, |this| { - if *is_auto == IsAuto::Yes { - // Auto traits cannot have generics, super traits nor contain items. - this.deny_generic_params(generics, item.ident.span); - this.deny_super_traits(bounds, item.ident.span); - this.deny_where_clause(&generics.where_clause, item.ident.span); - this.deny_items(items, item.ident.span); - } + if *is_auto == IsAuto::Yes { + // Auto traits cannot have generics, super traits nor contain items. + self.deny_generic_params(generics, ident.span); + self.deny_super_traits(bounds, ident.span); + self.deny_where_clause(&generics.where_clause, ident.span); + self.deny_items(items, ident.span); + } - // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound - // context for the supertraits. - this.visit_vis(&item.vis); - this.visit_ident(item.ident); - let disallowed = is_const_trait - .is_none() - .then(|| TildeConstReason::Trait { span: item.span }); - this.with_tilde_const(disallowed, |this| { - this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) - }); + // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound + // context for the supertraits. + let disallowed = + is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span }); + self.with_tilde_const(disallowed, |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) + }); + self.with_in_trait(item.span, is_const_trait, |this| { walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); }); - walk_list!(self, visit_attribute, &item.attrs); - return; // Avoid visiting again } - ItemKind::Mod(safety, mod_kind) => { + ItemKind::Mod(safety, ident, mod_kind) => { if let &Safety::Unsafe(span) = safety { self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). - if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) + if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) && !attr::contains_name(&item.attrs, sym::path) { - self.check_mod_file_item_asciionly(item.ident); + self.check_mod_file_item_asciionly(*ident); } + visit::walk_item(self, item) } - ItemKind::Struct(vdata, generics) => match vdata { + ItemKind::Struct(ident, vdata, generics) => match vdata { VariantData::Struct { fields, .. } => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.visit_generics(generics); // Permit `Anon{Struct,Union}` as field type. walk_list!(self, visit_struct_field_def, fields); - walk_list!(self, visit_attribute, &item.attrs); - return; } - _ => {} + _ => visit::walk_item(self, item), }, - ItemKind::Union(vdata, generics) => { + ItemKind::Union(ident, vdata, generics) => { if vdata.fields().is_empty() { self.dcx().emit_err(errors::FieldlessUnion { span: item.span }); } match vdata { VariantData::Struct { fields, .. } => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.visit_generics(generics); // Permit `Anon{Struct,Union}` as field type. walk_list!(self, visit_struct_field_def, fields); - walk_list!(self, visit_attribute, &item.attrs); - return; } - _ => {} + _ => visit::walk_item(self, item), } } ItemKind::Const(box ConstItem { defaultness, expr, .. }) => { @@ -1119,6 +1086,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { replace_span: self.ending_semi_or_hi(item.span), }); } + visit::walk_item(self, item); } ItemKind::Static(box StaticItem { expr, safety, .. }) => { self.check_item_safety(item.span, *safety); @@ -1132,6 +1100,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { replace_span: self.ending_semi_or_hi(item.span), }); } + visit::walk_item(self, item); } ItemKind::TyAlias( ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. }, @@ -1145,7 +1114,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.check_type_no_bounds(bounds, "this context"); - if self.features.lazy_type_alias { + if self.features.lazy_type_alias() { if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { self.dcx().emit_err(err); } @@ -1155,23 +1124,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { help: self.sess.is_nightly_build(), }); } + visit::walk_item(self, item); } - _ => {} + _ => visit::walk_item(self, item), } - - visit::walk_item(self, item); } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match &fi.kind { - ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { + ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => { self.check_defaultness(fi.span, *defaultness); - self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); + self.check_foreign_fn_bodyless(*ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); - self.check_foreign_item_ascii_only(fi.ident); + self.check_foreign_item_ascii_only(*ident); } ForeignItemKind::TyAlias(box TyAlias { defaultness, + ident, generics, where_clauses, bounds, @@ -1179,15 +1148,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .. }) => { self.check_defaultness(fi.span, *defaultness); - self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span)); + self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span)); self.check_type_no_bounds(bounds, "`extern` blocks"); self.check_foreign_ty_genericless(generics, where_clauses); - self.check_foreign_item_ascii_only(fi.ident); + self.check_foreign_item_ascii_only(*ident); } - ForeignItemKind::Static(box StaticItem { expr, safety, .. }) => { + ForeignItemKind::Static(box StaticItem { ident, safety, expr, .. }) => { self.check_item_safety(fi.span, *safety); - self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span)); - self.check_foreign_item_ascii_only(fi.ident); + self.check_foreign_kind_bodyless(*ident, "static", expr.as_ref().map(|b| b.span)); + self.check_foreign_item_ascii_only(*ident); } ForeignItemKind::MacCall(..) => {} } @@ -1247,14 +1216,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { validate_generic_param_order(self.dcx(), &generics.params, generics.span); for predicate in &generics.where_clause.predicates { - if let WherePredicate::EqPredicate(predicate) = predicate { - deny_equality_constraints(self, predicate, generics); + let span = predicate.span; + if let WherePredicateKind::EqPredicate(predicate) = &predicate.kind { + deny_equality_constraints(self, predicate, span, generics); } } walk_list!(self, visit_generic_param, &generics.params); for predicate in &generics.where_clause.predicates { - match predicate { - WherePredicate::BoundPredicate(bound_pred) => { + match &predicate.kind { + WherePredicateKind::BoundPredicate(bound_pred) => { // This is slightly complicated. Our representation for poly-trait-refs contains a single // binder and thus we only allow a single level of quantification. However, // the syntax of Rust permits quantification in two places in where clauses, @@ -1286,7 +1256,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { GenericBound::Trait(trait_ref) => { match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) { (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds => + if !self.features.more_maybe_bounds() => { self.sess .create_feature_err( @@ -1299,7 +1269,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds => + if !self.features.more_maybe_bounds() => { self.sess .create_feature_err( @@ -1395,17 +1365,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let FnKind::Fn( _, _, - FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. }, - _, - _, - _, + Fn { + sig: FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. }, + .. + }, ) = fk { - self.maybe_lint_missing_abi(*sig_span, id); + self.handle_missing_abi(*extern_span, id); } // Functions without bodies cannot have patterns. - if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk { + if let FnKind::Fn(ctxt, _, Fn { body: None, sig, .. }) = fk { Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { if let Some(ident) = ident { @@ -1439,22 +1409,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .is_some(); let disallowed = (!tilde_const_allowed).then(|| match fk { - FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span }, + FnKind::Fn(_, _, f) => TildeConstReason::Function { ident: f.ident.span }, FnKind::Closure(..) => TildeConstReason::Closure, }); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - if attr::contains_name(&item.attrs, sym::no_mangle) { - self.check_nomangle_item_asciionly(item.ident, item.span); + if let Some(ident) = item.kind.ident() + && attr::contains_name(&item.attrs, sym::no_mangle) + { + self.check_nomangle_item_asciionly(ident, item.span); } if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() { self.check_defaultness(item.span, item.kind.defaultness()); } - if ctxt == AssocCtxt::Impl { + if let AssocCtxt::Impl { .. } = ctxt { match &item.kind { AssocItemKind::Const(box ConstItem { expr: None, .. }) => { self.dcx().emit_err(errors::AssocConstWithoutBody { @@ -1507,30 +1479,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - if let AssocItemKind::Const(..) = item.kind { - self.check_item_named(item.ident, "const"); + if let AssocItemKind::Const(ci) = &item.kind { + self.check_item_named(ci.ident, "const"); } let parent_is_const = self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some(); match &item.kind { - AssocItemKind::Fn(box Fn { sig, generics, body, .. }) + AssocItemKind::Fn(func) if parent_is_const || ctxt == AssocCtxt::Trait - || matches!(sig.header.constness, Const::Yes(_)) => + || matches!(func.sig.header.constness, Const::Yes(_)) => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - let kind = FnKind::Fn( - FnCtxt::Assoc(ctxt), - item.ident, - sig, - &item.vis, - generics, - body.as_deref(), - ); - walk_list!(self, visit_attribute, &item.attrs); + self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident); + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func); self.visit_fn(kind, item.span, item.id); } AssocItemKind::Type(_) => { @@ -1557,9 +1520,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn deny_equality_constraints( this: &AstValidator<'_>, predicate: &WhereEqPredicate, + predicate_span: Span, generics: &Generics, ) { - let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None }; + let mut err = errors::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None }; // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`. if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind @@ -1603,7 +1567,7 @@ fn deny_equality_constraints( } } err.assoc = Some(errors::AssociatedSuggestion { - span: predicate.span, + span: predicate_span, ident: *ident, param: param.ident, path: pprust::path_to_string(&assoc_path), @@ -1633,23 +1597,23 @@ fn deny_equality_constraints( // We're removing th eonly where bound left, remove the whole thing. generics.where_clause.span } else { - let mut span = predicate.span; - let mut prev: Option<Span> = None; + let mut span = predicate_span; + let mut prev_span: Option<Span> = None; let mut preds = generics.where_clause.predicates.iter().peekable(); // Find the predicate that shouldn't have been in the where bound list. while let Some(pred) = preds.next() { - if let WherePredicate::EqPredicate(pred) = pred - && pred.span == predicate.span + if let WherePredicateKind::EqPredicate(_) = pred.kind + && pred.span == predicate_span { if let Some(next) = preds.peek() { // This is the first predicate, remove the trailing comma as well. - span = span.with_hi(next.span().lo()); - } else if let Some(prev) = prev { + span = span.with_hi(next.span.lo()); + } else if let Some(prev_span) = prev_span { // Remove the previous comma as well. - span = span.with_lo(prev.hi()); + span = span.with_lo(prev_span.hi()); } } - prev = Some(pred.span()); + prev_span = Some(pred.span); } span }; @@ -1666,8 +1630,8 @@ fn deny_equality_constraints( if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind { // Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`. for bounds in generics.params.iter().map(|p| &p.bounds).chain( - generics.where_clause.predicates.iter().filter_map(|pred| match pred { - WherePredicate::BoundPredicate(p) => Some(&p.bounds), + generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind { + WherePredicateKind::BoundPredicate(p) => Some(&p.bounds), _ => None, }), ) { @@ -1690,8 +1654,8 @@ fn deny_equality_constraints( // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`. if let [potential_param, potential_assoc] = &full_path.segments[..] { for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain( - generics.where_clause.predicates.iter().filter_map(|pred| match pred { - WherePredicate::BoundPredicate(p) + generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind { + WherePredicateKind::BoundPredicate(p) if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind && let [segment] = &path.segments[..] => { @@ -1724,12 +1688,11 @@ pub fn check_crate( let mut validator = AstValidator { sess, features, - extern_mod: None, + extern_mod_span: None, outer_trait_or_trait_impl: None, has_proc_macro_decls: false, - outer_impl_trait: None, + outer_impl_trait_span: None, disallow_tilde_const: Some(TildeConstReason::Item), - is_impl_trait_banned: false, extern_mod_safety: None, lint_buffer: lints, }; diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 4ca1acde1e289..6f9737e08314e 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -2,10 +2,9 @@ use rustc_ast::ParamKindOrd; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::symbol::Ident; -use rustc_span::{Span, Symbol}; +use rustc_span::{Ident, Span, Symbol}; use crate::fluent_generated as fluent; @@ -395,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec<Span>); // The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each impl Subdiagnostic for EmptyLabelManySpans { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.0, ""); } } @@ -418,13 +413,6 @@ pub(crate) struct TraitObjectBound { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_passes_impl_trait_path, code = E0667)] -pub(crate) struct ImplTraitPath { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_nested_impl_trait, code = E0666)] pub(crate) struct NestedImplTrait { @@ -543,7 +531,6 @@ pub(crate) struct WhereClauseBeforeTypeAlias { } #[derive(Subdiagnostic)] - pub(crate) enum WhereClauseBeforeTypeAliasSugg { #[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")] Remove { @@ -601,8 +588,8 @@ pub(crate) struct ConstBoundTraitObject { pub span: Span, } -// FIXME(effects): Consider making the note/reason the message of the diagnostic. -// FIXME(effects): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here). +// FIXME(const_trait_impl): Consider making the note/reason the message of the diagnostic. +// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here). #[derive(Diagnostic)] #[diag(ast_passes_tilde_const_disallowed)] pub(crate) struct TildeConstDisallowed { @@ -740,13 +727,6 @@ pub(crate) struct AssociatedSuggestion2 { pub potential_assoc: Ident, } -#[derive(Diagnostic)] -#[diag(ast_passes_stability_outside_std, code = E0734)] -pub(crate) struct StabilityOutsideStd { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_feature_on_non_nightly, code = E0554)] pub(crate) struct FeatureOnNonNightly { @@ -765,11 +745,7 @@ pub(crate) struct StableFeature { } impl Subdiagnostic for StableFeature { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _: &F, - ) { + fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { diag.arg("name", self.name); diag.arg("since", self.since); diag.help(fluent::ast_passes_stable_since); @@ -786,14 +762,6 @@ pub(crate) struct IncompatibleFeatures { pub f2: Symbol, } -#[derive(Diagnostic)] -#[diag(ast_passes_show_span)] -pub(crate) struct ShowSpan { - #[primary_span] - pub span: Span, - pub msg: &'static str, -} - #[derive(Diagnostic)] #[diag(ast_passes_negative_bound_not_supported)] pub(crate) struct NegativeBoundUnsupported { @@ -820,7 +788,14 @@ pub(crate) struct NegativeBoundWithParentheticalNotation { pub(crate) struct MatchArmWithNoBody { #[primary_span] pub span: Span, - #[suggestion(code = " => todo!(),", applicability = "has-placeholders")] + // We include the braces around `todo!()` so that a comma is optional, and we don't have to have + // any logic looking at the arm being replaced if there was a comma already or not for the + // resulting code to be correct. + #[suggestion( + code = " => {{ todo!() }}", + applicability = "has-placeholders", + style = "verbose" + )] pub suggestion: Span, } @@ -840,3 +815,12 @@ pub(crate) struct DuplicatePreciseCapturing { #[label] pub bound2: Span, } + +#[derive(Diagnostic)] +#[diag(ast_passes_extern_without_abi)] +#[help] +pub(crate) struct MissingAbi { + #[primary_span] + #[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")] + pub span: Span, +} diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index f2773dcdc601d..e312f15f05b08 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,13 +1,11 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{NodeId, PatKind, attr, token}; -use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features, GateIssue}; +use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features}; use rustc_session::Session; -use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; +use rustc_session::parse::{feature_err, feature_warn}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol}; -use rustc_target::spec::abi; +use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use crate::errors; @@ -15,13 +13,13 @@ use crate::errors; /// The common case. macro_rules! gate { ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit(); } }}; ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { // FIXME: make this translatable #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] @@ -43,7 +41,7 @@ macro_rules! gate_alt { /// The case involving a multispan. macro_rules! gate_multi { ($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{ - if !$visitor.features.$feature { + if !$visitor.features.$feature() { let spans: Vec<_> = $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect(); if !spans.is_empty() { @@ -56,7 +54,7 @@ macro_rules! gate_multi { /// The legacy case. macro_rules! gate_legacy { ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { feature_warn(&$visitor.sess, sym::$feature, $span, $explain); } }}; @@ -74,35 +72,6 @@ struct PostExpansionVisitor<'a> { } impl<'a> PostExpansionVisitor<'a> { - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn check_abi(&self, abi: ast::StrLit) { - let ast::StrLit { symbol_unescaped, span, .. } = abi; - - match abi::is_enabled(self.features, span, symbol_unescaped.as_str()) { - Ok(()) => (), - Err(abi::AbiDisabled::Unstable { feature, explain }) => { - feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit(); - } - Err(abi::AbiDisabled::Unrecognized) => { - if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { - self.sess.dcx().span_delayed_bug( - span, - format!( - "unrecognized ABI not caught in lowering: {}", - symbol_unescaped.as_str() - ), - ); - } - } - } - } - - fn check_extern(&self, ext: ast::Extern) { - if let ast::Extern::Explicit(abi, _) = ext { - self.check_abi(abi); - } - } - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. fn check_impl_trait(&self, ty: &ast::Ty, in_associated_ty: bool) { struct ImplTraitVisitor<'a> { @@ -130,6 +99,13 @@ impl<'a> PostExpansionVisitor<'a> { } visit::walk_ty(self, ty); } + + fn visit_anon_const(&mut self, _: &ast::AnonConst) -> Self::Result { + // We don't walk the anon const because it crosses a conceptual boundary: We're no + // longer "inside" the original type. + // Brittle: We assume that the callers of `check_impl_trait` will later recurse into + // the items found in the AnonConst to look for nested TyAliases. + } } ImplTraitVisitor { vis: self, in_associated_ty }.visit_ty(ty); } @@ -150,7 +126,7 @@ impl<'a> PostExpansionVisitor<'a> { // FIXME(non_lifetime_binders): Const bound params are pretty broken. // Let's keep users from using this feature accidentally. - if self.features.non_lifetime_binders { + if self.features.non_lifetime_binders() { let const_param_spans: Vec<_> = params .iter() .filter_map(|param| match param.kind { @@ -204,45 +180,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "meant for internal use only" { keyword => rustdoc_internals fake_variadic => rustdoc_internals + search_unbox => rustdoc_internals } ); } } - - // Emit errors for non-staged-api crates. - if !self.features.staged_api { - if attr.has_name(sym::unstable) - || attr.has_name(sym::stable) - || attr.has_name(sym::rustc_const_unstable) - || attr.has_name(sym::rustc_const_stable) - || attr.has_name(sym::rustc_default_body_unstable) - { - self.sess.dcx().emit_err(errors::StabilityOutsideStd { span: attr.span }); - } - } } fn visit_item(&mut self, i: &'a ast::Item) { match &i.kind { - ast::ItemKind::ForeignMod(foreign_module) => { - if let Some(abi) = foreign_module.abi { - self.check_abi(abi); - } - } - - ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs, sym::start) { - gate!( - &self, - start, - i.span, - "`#[start]` functions are experimental and their signature may change \ - over time" - ); - } + ast::ItemKind::ForeignMod(_foreign_module) => { + // handled during lowering } - - ast::ItemKind::Struct(..) => { + ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => { for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(sym::simd) { @@ -263,7 +213,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { &self, negative_impls, span.to(of_trait.as_ref().map_or(span, |t| t.path.span)), - "negative trait bounds are not yet fully implemented; \ + "negative trait bounds are not fully implemented; \ use marker types for now" ); } @@ -286,7 +236,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate!(&self, trait_alias, i.span, "trait aliases are experimental"); } - ast::ItemKind::MacroDef(ast::MacroDef { macro_rules: false, .. }) => { + ast::ItemKind::MacroDef(_, ast::MacroDef { macro_rules: false, .. }) => { let msg = "`macro` is experimental"; gate!(&self, decl_macro, i.span, msg); } @@ -328,7 +278,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match &ty.kind { ast::TyKind::BareFn(bare_fn_ty) => { // Function pointers cannot be `const` - self.check_extern(bare_fn_ty.ext); self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params); } ast::TyKind::Never => { @@ -344,8 +293,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_generics(&mut self, g: &'a ast::Generics) { for predicate in &g.where_clause.predicates { - match predicate { - ast::WherePredicate::BoundPredicate(bound_pred) => { + match &predicate.kind { + ast::WherePredicateKind::BoundPredicate(bound_pred) => { // A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params); } @@ -383,17 +332,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ExprKind::TryBlock(_) => { gate!(&self, try_blocks, e.span, "`try` expression is experimental"); } - ast::ExprKind::Lit(token::Lit { kind: token::LitKind::Float, suffix, .. }) => { - match suffix { - Some(sym::f16) => { - gate!(&self, f16, e.span, "the type `f16` is unstable") - } - Some(sym::f128) => { - gate!(&self, f128, e.span, "the type `f128` is unstable") - } - _ => (), + ast::ExprKind::Lit(token::Lit { + kind: token::LitKind::Float | token::LitKind::Integer, + suffix, + .. + }) => match suffix { + Some(sym::f16) => { + gate!(&self, f16, e.span, "the type `f16` is unstable") } - } + Some(sym::f128) => { + gate!(&self, f128, e.span, "the type `f128` is unstable") + } + _ => (), + }, _ => {} } visit::walk_expr(self, e) @@ -431,9 +382,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { - if let Some(header) = fn_kind.header() { + if let Some(_header) = fn_kind.header() { // Stability of const fn methods are covered in `visit_assoc_item` below. - self.check_extern(header.ext); } if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind { @@ -470,7 +420,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // Limit `min_specialization` to only specializing functions. gate_alt!( &self, - self.features.specialization || (is_fn && self.features.min_specialization), + self.features.specialization() || (is_fn && self.features.min_specialization()), sym::specialization, i.span, "specialization is unstable" @@ -511,9 +461,9 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { ); gate_all!(let_chains, "`let` expressions in this position are unstable"); gate_all!( - async_closure, - "async closures are unstable", - "to use an async block, remove the `||`: `async {`" + async_trait_bounds, + "`async` trait bounds are unstable", + "use the desugared name of the async trait, such as `AsyncFn`" ); gate_all!(async_for_loop, "`for await` loops are experimental"); gate_all!( @@ -522,9 +472,18 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { "consider removing `for<...>`" ); gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); - for &span in spans.get(&sym::yield_expr).iter().copied().flatten() { - if !span.at_least_rust_2024() { - gate!(&visitor, coroutines, span, "yield syntax is experimental"); + // yield can be enabled either by `coroutines` or `gen_blocks` + if let Some(spans) = spans.get(&sym::yield_expr) { + for span in spans { + if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines)) + && (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks