Compare commits
43 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01f6ddf758 | ||
|
|
674ccdd847 | ||
|
|
f0867bf650 | ||
|
|
b8cc170b70 | ||
|
|
128b1c9f64 | ||
|
|
f8cf317da3 | ||
|
|
9c13ace16d | ||
|
|
feb759bb79 | ||
|
|
f691f9a0ec | ||
|
|
254b59607d | ||
|
|
01ad1d67a6 | ||
|
|
641c209049 | ||
|
|
a741008f5b | ||
|
|
6feceec6b3 | ||
|
|
2b8a999ac4 | ||
|
|
4c28b43a94 | ||
|
|
a8201d341a | ||
|
|
9a4aba12f3 | ||
|
|
36e6625457 | ||
|
|
7bea8c6cf1 | ||
|
|
4dc996fa0f | ||
|
|
05448c2b8d | ||
|
|
2827b1b83d | ||
|
|
af53cfa882 | ||
|
|
efcf90104e | ||
|
|
d851fe6684 | ||
|
|
c5b220e1de | ||
|
|
249d399caa | ||
|
|
0aa11b5dd2 | ||
|
|
9f8bfd6b4a | ||
|
|
72b6488ba4 | ||
|
|
4bc6d75592 | ||
|
|
834ced45a4 | ||
|
|
3f4f07f0b9 | ||
|
|
e17ea4bf4e | ||
|
|
6dfb8017ed | ||
|
|
2a8e61f538 | ||
|
|
eb937a3172 | ||
|
|
de868f6b43 | ||
|
|
51da96d7d2 | ||
|
|
1b6e21e163 | ||
|
|
f80e3ac624 | ||
|
|
3c55c98ec8 |
9284 changed files with 169379 additions and 265183 deletions
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
|
@ -1 +0,0 @@
|
||||||
custom: ["rust-lang.org/funding"]
|
|
||||||
1
.github/ISSUE_TEMPLATE/ice.md
vendored
1
.github/ISSUE_TEMPLATE/ice.md
vendored
|
|
@ -2,7 +2,6 @@
|
||||||
name: Internal Compiler Error
|
name: Internal Compiler Error
|
||||||
about: Create a report for an internal compiler error in rustc.
|
about: Create a report for an internal compiler error in rustc.
|
||||||
labels: C-bug, I-ICE, T-compiler
|
labels: C-bug, I-ICE, T-compiler
|
||||||
title: "[ICE]: "
|
|
||||||
---
|
---
|
||||||
<!--
|
<!--
|
||||||
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
||||||
|
|
|
||||||
36
.github/workflows/ci.yml
vendored
36
.github/workflows/ci.yml
vendored
|
|
@ -11,9 +11,11 @@ name: CI
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- automation/bors/auto
|
- auto
|
||||||
- automation/bors/try
|
- try
|
||||||
- try-perf
|
- try-perf
|
||||||
|
- automation/bors/try
|
||||||
|
- automation/bors/auto
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "**"
|
- "**"
|
||||||
|
|
@ -31,10 +33,9 @@ defaults:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
# For a given workflow, if we push to the same branch, cancel all previous builds on that branch.
|
# For a given workflow, if we push to the same branch, cancel all previous builds on that branch.
|
||||||
# We add an exception for try builds (automation/bors/try branch) and unrolled rollup builds
|
# We add an exception for try builds (try branch) and unrolled rollup builds (try-perf), which
|
||||||
# (try-perf), which are all triggered on the same branch, but which should be able to run
|
# are all triggered on the same branch, but which should be able to run concurrently.
|
||||||
# concurrently.
|
group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }}
|
||||||
group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }}
|
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
env:
|
env:
|
||||||
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
|
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
|
||||||
|
|
@ -56,7 +57,7 @@ jobs:
|
||||||
- name: Test citool
|
- name: Test citool
|
||||||
# Only test citool on the auto branch, to reduce latency of the calculate matrix job
|
# Only test citool on the auto branch, to reduce latency of the calculate matrix job
|
||||||
# on PR/try builds.
|
# on PR/try builds.
|
||||||
if: ${{ github.ref == 'refs/heads/automation/bors/auto' }}
|
if: ${{ github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto' }}
|
||||||
run: |
|
run: |
|
||||||
cd src/ci/citool
|
cd src/ci/citool
|
||||||
CARGO_INCREMENTAL=0 cargo test
|
CARGO_INCREMENTAL=0 cargo test
|
||||||
|
|
@ -79,7 +80,7 @@ jobs:
|
||||||
# access the environment.
|
# access the environment.
|
||||||
#
|
#
|
||||||
# We only enable the environment for the rust-lang/rust repository, so that CI works on forks.
|
# We only enable the environment for the rust-lang/rust repository, so that CI works on forks.
|
||||||
environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }}
|
environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }}
|
||||||
env:
|
env:
|
||||||
CI_JOB_NAME: ${{ matrix.name }}
|
CI_JOB_NAME: ${{ matrix.name }}
|
||||||
CI_JOB_DOC_URL: ${{ matrix.doc_url }}
|
CI_JOB_DOC_URL: ${{ matrix.doc_url }}
|
||||||
|
|
@ -165,6 +166,9 @@ jobs:
|
||||||
- name: install sccache
|
- name: install sccache
|
||||||
run: src/ci/scripts/install-sccache.sh
|
run: src/ci/scripts/install-sccache.sh
|
||||||
|
|
||||||
|
- name: select Xcode
|
||||||
|
run: src/ci/scripts/select-xcode.sh
|
||||||
|
|
||||||
- name: install clang
|
- name: install clang
|
||||||
run: src/ci/scripts/install-clang.sh
|
run: src/ci/scripts/install-clang.sh
|
||||||
|
|
||||||
|
|
@ -302,22 +306,30 @@ jobs:
|
||||||
DD_GITHUB_JOB_NAME: ${{ matrix.full_name }}
|
DD_GITHUB_JOB_NAME: ${{ matrix.full_name }}
|
||||||
run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv
|
run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv
|
||||||
|
|
||||||
# This job is used to publish toolstate for successful auto builds.
|
# 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:
|
outcome:
|
||||||
name: publish toolstate
|
name: bors build finished
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
needs: [ calculate_matrix, job ]
|
needs: [ calculate_matrix, job ]
|
||||||
if: ${{ needs.calculate_matrix.outputs.run_type == 'auto' }}
|
# !cancelled() executes the job regardless of whether the previous jobs passed or failed
|
||||||
environment: ${{ (github.repository == 'rust-lang/rust' && 'bors') || '' }}
|
if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }}
|
||||||
|
environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout the source code
|
- name: checkout the source code
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
# Calculate the exit status of the whole CI workflow.
|
||||||
|
# If all dependent jobs were successful, this exits with 0 (and the outcome job continues successfully).
|
||||||
|
# If a some dependent job has failed, this exits with 1.
|
||||||
|
- name: calculate the correct exit status
|
||||||
|
run: jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'
|
||||||
# Publish the toolstate if an auto build succeeds (just before push to the default branch)
|
# Publish the toolstate if an auto build succeeds (just before push to the default branch)
|
||||||
- name: publish toolstate
|
- name: publish toolstate
|
||||||
run: src/ci/publish_toolstate.sh
|
run: src/ci/publish_toolstate.sh
|
||||||
shell: bash
|
shell: bash
|
||||||
|
if: needs.calculate_matrix.outputs.run_type == 'auto'
|
||||||
env:
|
env:
|
||||||
TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
|
TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
|
||||||
TOOLSTATE_PUBLISH: 1
|
TOOLSTATE_PUBLISH: 1
|
||||||
|
|
|
||||||
16
.github/workflows/dependencies.yml
vendored
16
.github/workflows/dependencies.yml
vendored
|
|
@ -62,9 +62,19 @@ jobs:
|
||||||
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
|
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
|
||||||
rustup default $TOOLCHAIN
|
rustup default $TOOLCHAIN
|
||||||
|
|
||||||
- name: cargo update
|
- name: cargo update compiler & tools
|
||||||
run: ./src/tools/update-lockfile.sh
|
# Remove first line that always just says "Updating crates.io index"
|
||||||
|
run: |
|
||||||
|
echo -e "\ncompiler & tools dependencies:" >> cargo_update.log
|
||||||
|
cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||||
|
- name: cargo update library
|
||||||
|
run: |
|
||||||
|
echo -e "\nlibrary dependencies:" >> cargo_update.log
|
||||||
|
cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||||
|
- name: cargo update rustbook
|
||||||
|
run: |
|
||||||
|
echo -e "\nrustbook dependencies:" >> cargo_update.log
|
||||||
|
cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||||
- name: upload Cargo.lock artifact for use in PR
|
- name: upload Cargo.lock artifact for use in PR
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
2
.github/workflows/ghcr.yml
vendored
2
.github/workflows/ghcr.yml
vendored
|
|
@ -55,8 +55,6 @@ jobs:
|
||||||
images=(
|
images=(
|
||||||
# Mirrored because used by the tidy job, which doesn't cache Docker images
|
# Mirrored because used by the tidy job, which doesn't cache Docker images
|
||||||
"ubuntu:22.04"
|
"ubuntu:22.04"
|
||||||
# Mirrored because used by x86-64-gnu-miri
|
|
||||||
"ubuntu:24.04"
|
|
||||||
# Mirrored because used by all linux CI jobs, including tidy
|
# Mirrored because used by all linux CI jobs, including tidy
|
||||||
"moby/buildkit:buildx-stable-1"
|
"moby/buildkit:buildx-stable-1"
|
||||||
# Mirrored because used when CI is running inside a Docker container
|
# Mirrored because used when CI is running inside a Docker container
|
||||||
|
|
|
||||||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -25,7 +25,7 @@
|
||||||
[submodule "src/llvm-project"]
|
[submodule "src/llvm-project"]
|
||||||
path = src/llvm-project
|
path = src/llvm-project
|
||||||
url = https://github.com/rust-lang/llvm-project.git
|
url = https://github.com/rust-lang/llvm-project.git
|
||||||
branch = rustc/22.1-2026-01-27
|
branch = rustc/21.1-2025-08-01
|
||||||
shallow = true
|
shallow = true
|
||||||
[submodule "src/doc/embedded-book"]
|
[submodule "src/doc/embedded-book"]
|
||||||
path = src/doc/embedded-book
|
path = src/doc/embedded-book
|
||||||
|
|
|
||||||
3
.mailmap
3
.mailmap
|
|
@ -83,7 +83,6 @@ Ben Sago <ogham@users.noreply.github.com> <ogham@bsago.me>
|
||||||
Ben Striegel <ben.striegel@gmail.com>
|
Ben Striegel <ben.striegel@gmail.com>
|
||||||
Benjamin Jackman <ben@jackman.biz>
|
Benjamin Jackman <ben@jackman.biz>
|
||||||
Benoît Cortier <benoit.cortier@fried-world.eu>
|
Benoît Cortier <benoit.cortier@fried-world.eu>
|
||||||
binarycat <binarycat@envs.net> lolbinarycat <dogedoge61+github@gmail.com> <dogedoge61@gmail.com>
|
|
||||||
Bheesham Persaud <bheesham123@hotmail.com> Bheesham Persaud <bheesham.persaud@live.ca>
|
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@users.noreply.github.com>
|
||||||
bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3_gh@protonmail.com>
|
bjorn3 <17426603+bjorn3@users.noreply.github.com> <bjorn3_gh@protonmail.com>
|
||||||
|
|
@ -96,7 +95,6 @@ boolean_coercion <booleancoercion@gmail.com>
|
||||||
Boris Egorov <jightuse@gmail.com> <egorov@linux.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] <26634292+bors[bot]@users.noreply.github.com>
|
||||||
bors <bors@rust-lang.org> bors[bot] <bors[bot]@users.noreply.github.com>
|
bors <bors@rust-lang.org> bors[bot] <bors[bot]@users.noreply.github.com>
|
||||||
bors <bors@rust-lang.org> <122020455+rust-bors[bot]@users.noreply.github.com>
|
|
||||||
BoxyUwU <rust@boxyuwu.dev>
|
BoxyUwU <rust@boxyuwu.dev>
|
||||||
BoxyUwU <rust@boxyuwu.dev> <supbscripter@gmail.com>
|
BoxyUwU <rust@boxyuwu.dev> <supbscripter@gmail.com>
|
||||||
Braden Nelson <moonheart08@users.noreply.github.com>
|
Braden Nelson <moonheart08@users.noreply.github.com>
|
||||||
|
|
@ -432,7 +430,6 @@ Lzu Tao <taolzu@gmail.com>
|
||||||
Maik Klein <maikklein@googlemail.com>
|
Maik Klein <maikklein@googlemail.com>
|
||||||
Maja Kądziołka <maya@compilercrim.es> <github@compilercrim.es>
|
Maja Kądziołka <maya@compilercrim.es> <github@compilercrim.es>
|
||||||
Maja Kądziołka <maya@compilercrim.es> <kuba@kadziolka.net>
|
Maja Kądziołka <maya@compilercrim.es> <kuba@kadziolka.net>
|
||||||
Makai <m4kai410@gmail.com>
|
|
||||||
Malo Jaffré <jaffre.malo@gmail.com>
|
Malo Jaffré <jaffre.malo@gmail.com>
|
||||||
Manish Goregaokar <manishsmail@gmail.com>
|
Manish Goregaokar <manishsmail@gmail.com>
|
||||||
Mara Bos <m-ou.se@m-ou.se>
|
Mara Bos <m-ou.se@m-ou.se>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ the Zulip stream is the best place to *ask* for help.
|
||||||
|
|
||||||
Documentation for contributing to the compiler or tooling is located in the [Guide to Rustc
|
Documentation for contributing to the compiler or tooling is located in the [Guide to Rustc
|
||||||
Development][rustc-dev-guide], commonly known as the [rustc-dev-guide]. Documentation for the
|
Development][rustc-dev-guide], commonly known as the [rustc-dev-guide]. Documentation for the
|
||||||
standard library is in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
|
standard library in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
|
||||||
|
|
||||||
## Making changes to subtrees and submodules
|
## Making changes to subtrees and submodules
|
||||||
|
|
||||||
|
|
|
||||||
377
Cargo.lock
377
Cargo.lock
File diff suppressed because it is too large
Load diff
|
|
@ -97,7 +97,7 @@ See [the rustc-dev-guide for more info][sysllvm].
|
||||||
--set llvm.ninja=false \
|
--set llvm.ninja=false \
|
||||||
--set rust.debug-assertions=false \
|
--set rust.debug-assertions=false \
|
||||||
--set rust.jemalloc \
|
--set rust.jemalloc \
|
||||||
--set rust.bootstrap-override-lld=true \
|
--set rust.use-lld=true \
|
||||||
--set rust.lto=thin \
|
--set rust.lto=thin \
|
||||||
--set rust.codegen-units=1
|
--set rust.codegen-units=1
|
||||||
```
|
```
|
||||||
|
|
@ -233,7 +233,7 @@ itself back on after some time).
|
||||||
|
|
||||||
### MSVC
|
### MSVC
|
||||||
|
|
||||||
MSVC builds of Rust additionally require an installation of:
|
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 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.
|
Visual Studio versions such as 2019 *may* work but aren't actively tested.
|
||||||
|
|
|
||||||
|
|
@ -1555,7 +1555,7 @@ Compatibility Notes
|
||||||
- [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
|
- [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)
|
- [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>.
|
- 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 previously did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
|
- [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.
|
- 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.
|
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.
|
Use of those two attributes outside of `#![cfg_attr]` continue to be fully supported.
|
||||||
|
|
@ -1731,7 +1731,7 @@ Cargo
|
||||||
Compatibility Notes
|
Compatibility Notes
|
||||||
-------------------
|
-------------------
|
||||||
- We now [disallow setting some built-in cfgs via the command-line](https://github.com/rust-lang/rust/pull/126158) with the newly added [`explicit_builtin_cfgs_in_flags`](https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html#explicit-builtin-cfgs-in-flags) lint in order to prevent incoherent state, eg. `windows` cfg active but target is Linux based. The appropriate [`rustc` flag](https://doc.rust-lang.org/rustc/command-line-arguments.html) should be used instead.
|
- We now [disallow setting some built-in cfgs via the command-line](https://github.com/rust-lang/rust/pull/126158) with the newly added [`explicit_builtin_cfgs_in_flags`](https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html#explicit-builtin-cfgs-in-flags) lint in order to prevent incoherent state, eg. `windows` cfg active but target is Linux based. The appropriate [`rustc` flag](https://doc.rust-lang.org/rustc/command-line-arguments.html) should be used instead.
|
||||||
- The standard library has a new implementation of `binary_search` which significantly improves performance ([#128254](https://github.com/rust-lang/rust/pull/128254)). However when a sorted slice has multiple values which compare equal, the new implementation may select a different value among the equal ones than the old implementation.
|
- The standard library has a new implementation of `binary_search` which is significantly improves performance ([#128254](https://github.com/rust-lang/rust/pull/128254)). However when a sorted slice has multiple values which compare equal, the new implementation may select a different value among the equal ones than the old implementation.
|
||||||
- [illumos/Solaris now sets `MSG_NOSIGNAL` when writing to sockets](https://github.com/rust-lang/rust/pull/128259). This avoids killing the process with SIGPIPE when writing to a closed socket, which matches the existing behavior on other UNIX targets.
|
- [illumos/Solaris now sets `MSG_NOSIGNAL` when writing to sockets](https://github.com/rust-lang/rust/pull/128259). This avoids killing the process with SIGPIPE when writing to a closed socket, which matches the existing behavior on other UNIX targets.
|
||||||
- [Removes a problematic hack that always passed the --whole-archive linker flag for tests, which may cause linker errors for code accidentally relying on it.](https://github.com/rust-lang/rust/pull/128400)
|
- [Removes a problematic hack that always passed the --whole-archive linker flag for tests, which may cause linker errors for code accidentally relying on it.](https://github.com/rust-lang/rust/pull/128400)
|
||||||
- The WebAssembly target features `multivalue` and `reference-types` are now
|
- The WebAssembly target features `multivalue` and `reference-types` are now
|
||||||
|
|
@ -1881,7 +1881,7 @@ These changes do not affect any public interfaces of Rust, but they represent
|
||||||
significant improvements to the performance or internals of rustc and related
|
significant improvements to the performance or internals of rustc and related
|
||||||
tools.
|
tools.
|
||||||
|
|
||||||
- [Add a Rust-for-Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
|
- [Add a Rust-for Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
|
||||||
|
|
||||||
Version 1.80.1 (2024-08-08)
|
Version 1.80.1 (2024-08-08)
|
||||||
===========================
|
===========================
|
||||||
|
|
@ -4519,7 +4519,7 @@ Compatibility Notes
|
||||||
saturating to `0` instead][89926]. In the real world the panic happened mostly
|
saturating to `0` instead][89926]. In the real world the panic happened mostly
|
||||||
on platforms with buggy monotonic clock implementations rather than catching
|
on platforms with buggy monotonic clock implementations rather than catching
|
||||||
programming errors like reversing the start and end times. Such programming
|
programming errors like reversing the start and end times. Such programming
|
||||||
errors will now result in `0` rather than a panic.
|
errors will now results in `0` rather than a panic.
|
||||||
- In a future release we're planning to increase the baseline requirements for
|
- In a future release we're planning to increase the baseline requirements for
|
||||||
the Linux kernel to version 3.2, and for glibc to version 2.17. We'd love
|
the Linux kernel to version 3.2, and for glibc to version 2.17. We'd love
|
||||||
your feedback in [PR #95026][95026].
|
your feedback in [PR #95026][95026].
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ path = [
|
||||||
]
|
]
|
||||||
precedence = "override"
|
precedence = "override"
|
||||||
SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)"
|
SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)"
|
||||||
SPDX-License-Identifier = "MIT OR Apache-2.0"
|
SPDX-License-Identifier = "MIT or Apache-2.0"
|
||||||
|
|
||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = "compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp"
|
path = "compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp"
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,6 @@
|
||||||
# Whether to build LLVM with support for it's gpu offload runtime.
|
# Whether to build LLVM with support for it's gpu offload runtime.
|
||||||
#llvm.offload = false
|
#llvm.offload = false
|
||||||
|
|
||||||
# Absolute path to the directory containing ClangConfig.cmake
|
|
||||||
#llvm.offload-clang-dir = ""
|
|
||||||
|
|
||||||
# When true, link libstdc++ statically into the rustc_llvm.
|
# When true, link libstdc++ statically into the rustc_llvm.
|
||||||
# This is useful if you don't want to use the dynamic version of that
|
# This is useful if you don't want to use the dynamic version of that
|
||||||
# library provided by LLVM.
|
# library provided by LLVM.
|
||||||
|
|
@ -194,31 +191,6 @@
|
||||||
# Currently, this is only supported for the `x86_64-unknown-linux-gnu` target.
|
# Currently, this is only supported for the `x86_64-unknown-linux-gnu` target.
|
||||||
#gcc.download-ci-gcc = false
|
#gcc.download-ci-gcc = false
|
||||||
|
|
||||||
# Provide a directory of prebuilt libgccjit.so dylibs for given (host, target) compilation pairs.
|
|
||||||
# This is useful when you want to cross-compile `rustc` to another target since GCC is not a
|
|
||||||
# multi-target compiler.
|
|
||||||
# You have to use a directory structure that looks like this:
|
|
||||||
# `<libgccjit-libs-dir>/<host>/<target>/libgccjit.so`.
|
|
||||||
# For example:
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# <libgccjit-libs-dir>
|
|
||||||
# ├── m68k-unknown-linux-gnu
|
|
||||||
# │ └── m68k-unknown-linux-gnu
|
|
||||||
# │ └── libgccjit.so
|
|
||||||
# └── x86_64-unknown-linux-gnu
|
|
||||||
# ├── m68k-unknown-linux-gnu
|
|
||||||
# │ └── libgccjit.so
|
|
||||||
# └── x86_64-unknown-linux-gnu
|
|
||||||
# └── libgccjit.so
|
|
||||||
# ```
|
|
||||||
# The directory above would allow you to cross-compile rustc from x64 to m68k
|
|
||||||
#
|
|
||||||
# Note that this option has priority over `gcc.download-ci-gcc`.
|
|
||||||
# If you set both, bootstrap will first try to load libgccjit.so from this directory.
|
|
||||||
# Only if it isn't found, it will try to download it from CI or build it locally.
|
|
||||||
#gcc.libgccjit-libs-dir = "/path/to/libgccjit-libs-dir"
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# General build configuration options
|
# General build configuration options
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
// Several crates are depended upon but unused so that they are present in the sysroot
|
// Several crates are depended upon but unused so that they are present in the sysroot
|
||||||
#![expect(unused_crate_dependencies)]
|
#![expect(unused_crate_dependencies)]
|
||||||
|
|
||||||
use std::process::ExitCode;
|
|
||||||
|
|
||||||
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
||||||
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
||||||
// mechanism. However, for complicated reasons (see
|
// mechanism. However, for complicated reasons (see
|
||||||
|
|
@ -40,6 +38,6 @@ use std::process::ExitCode;
|
||||||
#[cfg(feature = "jemalloc")]
|
#[cfg(feature = "jemalloc")]
|
||||||
use tikv_jemalloc_sys as _;
|
use tikv_jemalloc_sys as _;
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() {
|
||||||
rustc_driver::main()
|
rustc_driver::main()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
/// This is public so that it can be used in unit tests, but
|
/// This is public so that it can be used in unit tests, but
|
||||||
/// should generally only be relevant to the ABI details of
|
/// should generally only be relevant to the ABI details of
|
||||||
/// specific targets.
|
/// specific targets.
|
||||||
#[tracing::instrument(skip(cx), level = "debug")]
|
|
||||||
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
|
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
|
||||||
where
|
where
|
||||||
Ty: TyAbiInterface<'a, C> + Copy,
|
Ty: TyAbiInterface<'a, C> + Copy,
|
||||||
|
|
@ -83,10 +82,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendRepr::ScalableVector { .. } => {
|
|
||||||
unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
|
|
||||||
}
|
|
||||||
|
|
||||||
BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
|
BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
|
||||||
// Helper for computing `homogeneous_aggregate`, allowing a custom
|
// Helper for computing `homogeneous_aggregate`, allowing a custom
|
||||||
// starting offset (used below for handling variants).
|
// starting offset (used below for handling variants).
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ impl Reg {
|
||||||
|
|
||||||
reg_ctor!(f32, Float, 32);
|
reg_ctor!(f32, Float, 32);
|
||||||
reg_ctor!(f64, Float, 64);
|
reg_ctor!(f64, Float, 64);
|
||||||
reg_ctor!(f128, Float, 128);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reg {
|
impl Reg {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ pub enum CanonAbi {
|
||||||
C,
|
C,
|
||||||
Rust,
|
Rust,
|
||||||
RustCold,
|
RustCold,
|
||||||
RustPreserveNone,
|
|
||||||
|
|
||||||
/// An ABI that rustc does not know how to call or define.
|
/// An ABI that rustc does not know how to call or define.
|
||||||
Custom,
|
Custom,
|
||||||
|
|
@ -55,7 +54,7 @@ pub enum CanonAbi {
|
||||||
impl CanonAbi {
|
impl CanonAbi {
|
||||||
pub fn is_rustic_abi(self) -> bool {
|
pub fn is_rustic_abi(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
|
CanonAbi::Rust | CanonAbi::RustCold => true,
|
||||||
CanonAbi::C
|
CanonAbi::C
|
||||||
| CanonAbi::Custom
|
| CanonAbi::Custom
|
||||||
| CanonAbi::Arm(_)
|
| CanonAbi::Arm(_)
|
||||||
|
|
@ -75,7 +74,6 @@ impl fmt::Display for CanonAbi {
|
||||||
CanonAbi::C => ExternAbi::C { unwind: false },
|
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||||
CanonAbi::Rust => ExternAbi::Rust,
|
CanonAbi::Rust => ExternAbi::Rust,
|
||||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||||
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
|
|
||||||
CanonAbi::Custom => ExternAbi::Custom,
|
CanonAbi::Custom => ExternAbi::Custom,
|
||||||
CanonAbi::Arm(arm_call) => match arm_call {
|
CanonAbi::Arm(arm_call) => match arm_call {
|
||||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,6 @@ pub enum ExternAbi {
|
||||||
/// in a platform-agnostic way.
|
/// in a platform-agnostic way.
|
||||||
RustInvalid,
|
RustInvalid,
|
||||||
|
|
||||||
/// Preserves no registers.
|
|
||||||
///
|
|
||||||
/// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
|
|
||||||
/// and may fall-back to a more conservative calling convention if the backend does not support
|
|
||||||
/// forcing callers to save all registers.
|
|
||||||
RustPreserveNone,
|
|
||||||
|
|
||||||
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
|
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
|
||||||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||||
Unadjusted,
|
Unadjusted,
|
||||||
|
|
@ -74,6 +67,7 @@ pub enum ExternAbi {
|
||||||
|
|
||||||
/* gpu */
|
/* gpu */
|
||||||
/// An entry-point function called by the GPU's host
|
/// 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,
|
GpuKernel,
|
||||||
/// An entry-point function called by the GPU's host
|
/// An entry-point function called by the GPU's host
|
||||||
// FIXME: why do we have two of these?
|
// FIXME: why do we have two of these?
|
||||||
|
|
@ -170,7 +164,6 @@ abi_impls! {
|
||||||
RustCall =><= "rust-call",
|
RustCall =><= "rust-call",
|
||||||
RustCold =><= "rust-cold",
|
RustCold =><= "rust-cold",
|
||||||
RustInvalid =><= "rust-invalid",
|
RustInvalid =><= "rust-invalid",
|
||||||
RustPreserveNone =><= "rust-preserve-none",
|
|
||||||
Stdcall { unwind: false } =><= "stdcall",
|
Stdcall { unwind: false } =><= "stdcall",
|
||||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||||
System { unwind: false } =><= "system",
|
System { unwind: false } =><= "system",
|
||||||
|
|
@ -251,7 +244,7 @@ impl ExternAbi {
|
||||||
/// - are subject to change between compiler versions
|
/// - are subject to change between compiler versions
|
||||||
pub fn is_rustic_abi(self) -> bool {
|
pub fn is_rustic_abi(self) -> bool {
|
||||||
use ExternAbi::*;
|
use ExternAbi::*;
|
||||||
matches!(self, Rust | RustCall | RustCold | RustPreserveNone)
|
matches!(self, Rust | RustCall | RustCold)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
|
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
|
||||||
|
|
@ -323,8 +316,7 @@ impl ExternAbi {
|
||||||
| Self::Thiscall { .. }
|
| Self::Thiscall { .. }
|
||||||
| Self::Vectorcall { .. }
|
| Self::Vectorcall { .. }
|
||||||
| Self::SysV64 { .. }
|
| Self::SysV64 { .. }
|
||||||
| Self::Win64 { .. }
|
| Self::Win64 { .. } => true,
|
||||||
| Self::RustPreserveNone => true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
|
use std::assert_matches::assert_matches;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use rustc_data_structures::assert_matches;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use tracing::{debug, trace};
|
||||||
use crate::{
|
use crate::{
|
||||||
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
|
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
|
||||||
LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
|
LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
|
||||||
TargetDataLayout, Variants, WrappingRange,
|
Variants, WrappingRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod coroutine;
|
mod coroutine;
|
||||||
|
|
@ -143,32 +143,58 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scalable_vector_type<FieldIdx, VariantIdx, F>(
|
pub fn simd_type<
|
||||||
&self,
|
|
||||||
element: F,
|
|
||||||
count: u64,
|
|
||||||
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
|
|
||||||
where
|
|
||||||
FieldIdx: Idx,
|
FieldIdx: Idx,
|
||||||
VariantIdx: Idx,
|
VariantIdx: Idx,
|
||||||
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||||
{
|
>(
|
||||||
vector_type_layout(VectorKind::Scalable, self.cx.data_layout(), element, count)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn simd_type<FieldIdx, VariantIdx, F>(
|
|
||||||
&self,
|
&self,
|
||||||
element: F,
|
element: F,
|
||||||
count: u64,
|
count: u64,
|
||||||
repr_packed: bool,
|
repr_packed: bool,
|
||||||
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
|
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
|
||||||
where
|
let elt = element.as_ref();
|
||||||
FieldIdx: Idx,
|
if count == 0 {
|
||||||
VariantIdx: Idx,
|
return Err(LayoutCalculatorError::ZeroLengthSimdType);
|
||||||
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
} else if count > crate::MAX_SIMD_LANES {
|
||||||
{
|
return Err(LayoutCalculatorError::OversizedSimdType {
|
||||||
let kind = if repr_packed { VectorKind::PackedFixed } else { VectorKind::Fixed };
|
max_lanes: crate::MAX_SIMD_LANES,
|
||||||
vector_type_layout(kind, self.cx.data_layout(), element, count)
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 }, Align::max_aligned_factor(size))
|
||||||
|
} else {
|
||||||
|
(BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size))
|
||||||
|
};
|
||||||
|
let size = size.align_to(align);
|
||||||
|
|
||||||
|
Ok(LayoutData {
|
||||||
|
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||||
|
fields: FieldsShape::Arbitrary {
|
||||||
|
offsets: [Size::ZERO].into(),
|
||||||
|
memory_index: [0].into(),
|
||||||
|
},
|
||||||
|
backend_repr: repr,
|
||||||
|
largest_niche: elt.largest_niche,
|
||||||
|
uninhabited: false,
|
||||||
|
size,
|
||||||
|
align: AbiAlign::new(align),
|
||||||
|
max_repr_align: None,
|
||||||
|
unadjusted_abi_align: elt.align.abi,
|
||||||
|
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the layout for a coroutine.
|
/// Compute the layout for a coroutine.
|
||||||
|
|
@ -427,7 +453,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
BackendRepr::Scalar(..)
|
BackendRepr::Scalar(..)
|
||||||
| BackendRepr::ScalarPair(..)
|
| BackendRepr::ScalarPair(..)
|
||||||
| BackendRepr::SimdVector { .. }
|
| BackendRepr::SimdVector { .. }
|
||||||
| BackendRepr::ScalableVector { .. }
|
|
||||||
| BackendRepr::Memory { .. } => repr,
|
| BackendRepr::Memory { .. } => repr,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -499,8 +524,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
hide_niches(a);
|
hide_niches(a);
|
||||||
hide_niches(b);
|
hide_niches(b);
|
||||||
}
|
}
|
||||||
BackendRepr::SimdVector { element, .. }
|
BackendRepr::SimdVector { element, count: _ } => hide_niches(element),
|
||||||
| BackendRepr::ScalableVector { element, .. } => hide_niches(element),
|
|
||||||
BackendRepr::Memory { sized: _ } => {}
|
BackendRepr::Memory { sized: _ } => {}
|
||||||
}
|
}
|
||||||
st.largest_niche = None;
|
st.largest_niche = None;
|
||||||
|
|
@ -714,7 +738,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
},
|
},
|
||||||
fields: FieldsShape::Arbitrary {
|
fields: FieldsShape::Arbitrary {
|
||||||
offsets: [niche_offset].into(),
|
offsets: [niche_offset].into(),
|
||||||
in_memory_order: [FieldIdx::new(0)].into(),
|
memory_index: [0].into(),
|
||||||
},
|
},
|
||||||
backend_repr: abi,
|
backend_repr: abi,
|
||||||
largest_niche,
|
largest_niche,
|
||||||
|
|
@ -1008,8 +1032,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
let pair =
|
let pair =
|
||||||
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar);
|
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar);
|
||||||
let pair_offsets = match pair.fields {
|
let pair_offsets = match pair.fields {
|
||||||
FieldsShape::Arbitrary { ref offsets, ref in_memory_order } => {
|
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
|
||||||
assert_eq!(in_memory_order.raw, [FieldIdx::new(0), FieldIdx::new(1)]);
|
assert_eq!(memory_index.raw, [0, 1]);
|
||||||
offsets
|
offsets
|
||||||
}
|
}
|
||||||
_ => panic!("encountered a non-arbitrary layout during enum layout"),
|
_ => panic!("encountered a non-arbitrary layout during enum layout"),
|
||||||
|
|
@ -1061,7 +1085,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
},
|
},
|
||||||
fields: FieldsShape::Arbitrary {
|
fields: FieldsShape::Arbitrary {
|
||||||
offsets: [Size::ZERO].into(),
|
offsets: [Size::ZERO].into(),
|
||||||
in_memory_order: [FieldIdx::new(0)].into(),
|
memory_index: [0].into(),
|
||||||
},
|
},
|
||||||
largest_niche,
|
largest_niche,
|
||||||
uninhabited,
|
uninhabited,
|
||||||
|
|
@ -1110,10 +1134,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
let pack = repr.pack;
|
let pack = repr.pack;
|
||||||
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
|
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
|
||||||
let mut max_repr_align = repr.align;
|
let mut max_repr_align = repr.align;
|
||||||
let mut in_memory_order: IndexVec<u32, FieldIdx> = fields.indices().collect();
|
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
|
||||||
let optimize_field_order = !repr.inhibit_struct_field_reordering();
|
let optimize_field_order = !repr.inhibit_struct_field_reordering();
|
||||||
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
||||||
let optimizing = &mut in_memory_order.raw[..end];
|
let optimizing = &mut inverse_memory_index.raw[..end];
|
||||||
let fields_excluding_tail = &fields.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.
|
// unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts.
|
||||||
let field_seed = fields_excluding_tail
|
let field_seed = fields_excluding_tail
|
||||||
|
|
@ -1248,10 +1272,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
// regardless of the status of `-Z randomize-layout`
|
// regardless of the status of `-Z randomize-layout`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// in_memory_order holds field indices by increasing memory offset.
|
// inverse_memory_index holds field indices by increasing memory offset.
|
||||||
// That is, if field 5 has offset 0, the first element of in_memory_order is 5.
|
// That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
|
||||||
// We now write field offsets to the corresponding offset slot;
|
// We now write field offsets to the corresponding offset slot;
|
||||||
// field 5 with offset 0 puts 0 in offsets[5].
|
// field 5 with offset 0 puts 0 in offsets[5].
|
||||||
|
// At the bottom of this function, we invert `inverse_memory_index` to
|
||||||
|
// produce `memory_index` (see `invert_mapping`).
|
||||||
let mut unsized_field = None::<&F>;
|
let mut unsized_field = None::<&F>;
|
||||||
let mut offsets = IndexVec::from_elem(Size::ZERO, fields);
|
let mut offsets = IndexVec::from_elem(Size::ZERO, fields);
|
||||||
let mut offset = Size::ZERO;
|
let mut offset = Size::ZERO;
|
||||||
|
|
@ -1263,7 +1289,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
align = align.max(prefix_align);
|
align = align.max(prefix_align);
|
||||||
offset = prefix_size.align_to(prefix_align);
|
offset = prefix_size.align_to(prefix_align);
|
||||||
}
|
}
|
||||||
for &i in &in_memory_order {
|
for &i in &inverse_memory_index {
|
||||||
let field = &fields[i];
|
let field = &fields[i];
|
||||||
if let Some(unsized_field) = unsized_field {
|
if let Some(unsized_field) = unsized_field {
|
||||||
return Err(LayoutCalculatorError::UnexpectedUnsized(*unsized_field));
|
return Err(LayoutCalculatorError::UnexpectedUnsized(*unsized_field));
|
||||||
|
|
@ -1320,6 +1346,18 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
|
|
||||||
debug!("univariant min_size: {:?}", offset);
|
debug!("univariant min_size: {:?}", offset);
|
||||||
let min_size = offset;
|
let min_size = offset;
|
||||||
|
// As stated above, inverse_memory_index holds field indices by increasing offset.
|
||||||
|
// This makes it an already-sorted view of the offsets vec.
|
||||||
|
// To invert it, consider:
|
||||||
|
// If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
|
||||||
|
// Field 5 would be the first element, so memory_index is i:
|
||||||
|
// Note: if we didn't optimize, it's already right.
|
||||||
|
let memory_index = if optimize_field_order {
|
||||||
|
inverse_memory_index.invert_bijective_mapping()
|
||||||
|
} else {
|
||||||
|
debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
|
||||||
|
inverse_memory_index.into_iter().map(|it| it.index() as u32).collect()
|
||||||
|
};
|
||||||
let size = min_size.align_to(align);
|
let size = min_size.align_to(align);
|
||||||
// FIXME(oli-obk): deduplicate and harden these checks
|
// FIXME(oli-obk): deduplicate and harden these checks
|
||||||
if size.bytes() >= dl.obj_size_bound() {
|
if size.bytes() >= dl.obj_size_bound() {
|
||||||
|
|
@ -1375,11 +1413,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
let pair =
|
let pair =
|
||||||
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b);
|
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b);
|
||||||
let pair_offsets = match pair.fields {
|
let pair_offsets = match pair.fields {
|
||||||
FieldsShape::Arbitrary { ref offsets, ref in_memory_order } => {
|
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
|
||||||
assert_eq!(
|
assert_eq!(memory_index.raw, [0, 1]);
|
||||||
in_memory_order.raw,
|
|
||||||
[FieldIdx::new(0), FieldIdx::new(1)]
|
|
||||||
);
|
|
||||||
offsets
|
offsets
|
||||||
}
|
}
|
||||||
FieldsShape::Primitive
|
FieldsShape::Primitive
|
||||||
|
|
@ -1423,7 +1458,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
|
|
||||||
Ok(LayoutData {
|
Ok(LayoutData {
|
||||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||||
fields: FieldsShape::Arbitrary { offsets, in_memory_order },
|
fields: FieldsShape::Arbitrary { offsets, memory_index },
|
||||||
backend_repr: abi,
|
backend_repr: abi,
|
||||||
largest_niche,
|
largest_niche,
|
||||||
uninhabited,
|
uninhabited,
|
||||||
|
|
@ -1466,70 +1501,3 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum VectorKind {
|
|
||||||
/// `#[rustc_scalable_vector]`
|
|
||||||
Scalable,
|
|
||||||
/// `#[repr(simd, packed)]`
|
|
||||||
PackedFixed,
|
|
||||||
/// `#[repr(simd)]`
|
|
||||||
Fixed,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vector_type_layout<FieldIdx, VariantIdx, F>(
|
|
||||||
kind: VectorKind,
|
|
||||||
dl: &TargetDataLayout,
|
|
||||||
element: F,
|
|
||||||
count: u64,
|
|
||||||
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
|
|
||||||
where
|
|
||||||
FieldIdx: Idx,
|
|
||||||
VariantIdx: Idx,
|
|
||||||
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
|
||||||
{
|
|
||||||
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(element) = elt.backend_repr else {
|
|
||||||
return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compute the size and alignment of the vector
|
|
||||||
let size =
|
|
||||||
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
|
|
||||||
let (repr, align) = match kind {
|
|
||||||
VectorKind::Scalable => {
|
|
||||||
(BackendRepr::ScalableVector { element, count }, dl.llvmlike_vector_align(size))
|
|
||||||
}
|
|
||||||
// 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.
|
|
||||||
VectorKind::PackedFixed if !count.is_power_of_two() => {
|
|
||||||
(BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
|
|
||||||
}
|
|
||||||
VectorKind::PackedFixed | VectorKind::Fixed => {
|
|
||||||
(BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let size = size.align_to(align);
|
|
||||||
|
|
||||||
Ok(LayoutData {
|
|
||||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
|
||||||
fields: FieldsShape::Arbitrary {
|
|
||||||
offsets: [Size::ZERO].into(),
|
|
||||||
in_memory_order: [FieldIdx::new(0)].into(),
|
|
||||||
},
|
|
||||||
backend_repr: repr,
|
|
||||||
largest_niche: elt.largest_niche,
|
|
||||||
uninhabited: false,
|
|
||||||
size,
|
|
||||||
align: AbiAlign::new(align),
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: elt.align.abi,
|
|
||||||
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -182,29 +182,33 @@ pub(super) fn layout<
|
||||||
// CoroutineLayout.
|
// CoroutineLayout.
|
||||||
debug!("prefix = {:#?}", prefix);
|
debug!("prefix = {:#?}", prefix);
|
||||||
let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
|
let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
|
||||||
FieldsShape::Arbitrary { mut offsets, in_memory_order } => {
|
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
|
// "a" (`0..b_start`) and "b" (`b_start..`) correspond to
|
||||||
// "outer" and "promoted" fields respectively.
|
// "outer" and "promoted" fields respectively.
|
||||||
let b_start = tag_index.plus(1);
|
let b_start = tag_index.plus(1);
|
||||||
let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index()));
|
let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index()));
|
||||||
let offsets_a = offsets;
|
let offsets_a = offsets;
|
||||||
|
|
||||||
// Disentangle the "a" and "b" components of `in_memory_order`
|
// Disentangle the "a" and "b" components of `inverse_memory_index`
|
||||||
// by preserving the order but keeping only one disjoint "half" each.
|
// by preserving the order but keeping only one disjoint "half" each.
|
||||||
// FIXME(eddyb) build a better abstraction for permutations, if possible.
|
// FIXME(eddyb) build a better abstraction for permutations, if possible.
|
||||||
let mut in_memory_order_a = IndexVec::<u32, FieldIdx>::new();
|
let inverse_memory_index_b: IndexVec<u32, FieldIdx> = inverse_memory_index
|
||||||
let mut in_memory_order_b = IndexVec::<u32, FieldIdx>::new();
|
.iter()
|
||||||
for i in in_memory_order {
|
.filter_map(|&i| i.index().checked_sub(b_start.index()).map(FieldIdx::new))
|
||||||
if let Some(j) = i.index().checked_sub(b_start.index()) {
|
.collect();
|
||||||
in_memory_order_b.push(FieldIdx::new(j));
|
inverse_memory_index.raw.retain(|&i| i.index() < b_start.index());
|
||||||
} else {
|
let inverse_memory_index_a = inverse_memory_index;
|
||||||
in_memory_order_a.push(i);
|
|
||||||
}
|
// 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 =
|
let outer_fields =
|
||||||
FieldsShape::Arbitrary { offsets: offsets_a, in_memory_order: in_memory_order_a };
|
FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a };
|
||||||
(outer_fields, offsets_b, in_memory_order_b.invert_bijective_mapping())
|
(outer_fields, offsets_b, memory_index_b)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
@ -232,7 +236,7 @@ pub(super) fn layout<
|
||||||
)?;
|
)?;
|
||||||
variant.variants = Variants::Single { index };
|
variant.variants = Variants::Single { index };
|
||||||
|
|
||||||
let FieldsShape::Arbitrary { offsets, in_memory_order } = variant.fields else {
|
let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -245,9 +249,8 @@ pub(super) fn layout<
|
||||||
// promoted fields were being used, but leave the elements not in 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
|
// subset as `invalid_field_idx`, which we can filter out later to
|
||||||
// obtain a valid (bijective) mapping.
|
// obtain a valid (bijective) mapping.
|
||||||
let memory_index = in_memory_order.invert_bijective_mapping();
|
|
||||||
let invalid_field_idx = promoted_memory_index.len() + memory_index.len();
|
let invalid_field_idx = promoted_memory_index.len() + memory_index.len();
|
||||||
let mut combined_in_memory_order =
|
let mut combined_inverse_memory_index =
|
||||||
IndexVec::from_elem_n(FieldIdx::new(invalid_field_idx), invalid_field_idx);
|
IndexVec::from_elem_n(FieldIdx::new(invalid_field_idx), invalid_field_idx);
|
||||||
|
|
||||||
let mut offsets_and_memory_index = iter::zip(offsets, memory_index);
|
let mut offsets_and_memory_index = iter::zip(offsets, memory_index);
|
||||||
|
|
@ -265,18 +268,19 @@ pub(super) fn layout<
|
||||||
(promoted_offsets[field_idx], promoted_memory_index[field_idx])
|
(promoted_offsets[field_idx], promoted_memory_index[field_idx])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
combined_in_memory_order[memory_index] = i;
|
combined_inverse_memory_index[memory_index] = i;
|
||||||
offset
|
offset
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Remove the unused slots to obtain the combined `in_memory_order`
|
// Remove the unused slots and invert the mapping to obtain the
|
||||||
// (also see previous comment).
|
// combined `memory_index` (also see previous comment).
|
||||||
combined_in_memory_order.raw.retain(|&i| i.index() != invalid_field_idx);
|
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 {
|
variant.fields = FieldsShape::Arbitrary {
|
||||||
offsets: combined_offsets,
|
offsets: combined_offsets,
|
||||||
in_memory_order: combined_in_memory_order,
|
memory_index: combined_memory_index,
|
||||||
};
|
};
|
||||||
|
|
||||||
size = size.max(variant.size);
|
size = size.max(variant.size);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||||
fields: FieldsShape::Arbitrary {
|
fields: FieldsShape::Arbitrary {
|
||||||
offsets: IndexVec::new(),
|
offsets: IndexVec::new(),
|
||||||
in_memory_order: IndexVec::new(),
|
memory_index: IndexVec::new(),
|
||||||
},
|
},
|
||||||
backend_repr: BackendRepr::Memory { sized },
|
backend_repr: BackendRepr::Memory { sized },
|
||||||
largest_niche: None,
|
largest_niche: None,
|
||||||
|
|
@ -108,7 +108,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||||
fields: FieldsShape::Arbitrary {
|
fields: FieldsShape::Arbitrary {
|
||||||
offsets: [Size::ZERO, b_offset].into(),
|
offsets: [Size::ZERO, b_offset].into(),
|
||||||
in_memory_order: [FieldIdx::new(0), FieldIdx::new(1)].into(),
|
memory_index: [0, 1].into(),
|
||||||
},
|
},
|
||||||
backend_repr: BackendRepr::ScalarPair(a, b),
|
backend_repr: BackendRepr::ScalarPair(a, b),
|
||||||
largest_niche,
|
largest_niche,
|
||||||
|
|
@ -133,7 +133,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
Some(fields) => FieldsShape::Union(fields),
|
Some(fields) => FieldsShape::Union(fields),
|
||||||
None => FieldsShape::Arbitrary {
|
None => FieldsShape::Arbitrary {
|
||||||
offsets: IndexVec::new(),
|
offsets: IndexVec::new(),
|
||||||
in_memory_order: IndexVec::new(),
|
memory_index: IndexVec::new(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
backend_repr: BackendRepr::Memory { sized: true },
|
backend_repr: BackendRepr::Memory { sized: true },
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
|
||||||
|
|
||||||
/// Trait that needs to be implemented by the higher-level type representation
|
/// Trait that needs to be implemented by the higher-level type representation
|
||||||
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
|
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
|
||||||
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
|
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
|
||||||
fn ty_and_layout_for_variant(
|
fn ty_and_layout_for_variant(
|
||||||
this: TyAndLayout<'a, Self>,
|
this: TyAndLayout<'a, Self>,
|
||||||
cx: &C,
|
cx: &C,
|
||||||
|
|
@ -172,7 +172,6 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
|
||||||
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
|
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
|
||||||
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
|
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
|
||||||
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
|
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
|
||||||
fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
|
|
||||||
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
||||||
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
|
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
|
||||||
}
|
}
|
||||||
|
|
@ -272,13 +271,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
Ty::is_transparent(self)
|
Ty::is_transparent(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_scalable_vector<C>(self) -> bool
|
|
||||||
where
|
|
||||||
Ty: TyAbiInterface<'a, C>,
|
|
||||||
{
|
|
||||||
Ty::is_scalable_vector(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If this method returns `true`, then this type should always have a `PassMode` of
|
/// If this method returns `true`, then this type should always have a `PassMode` of
|
||||||
/// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
|
/// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
|
||||||
/// non-Rustic ABI (this is true for structs annotated with the
|
/// non-Rustic ABI (this is true for structs annotated with the
|
||||||
|
|
@ -290,19 +282,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
/// function call isn't allowed (a.k.a. `va_list`).
|
/// function call isn't allowed (a.k.a. `va_list`).
|
||||||
///
|
///
|
||||||
/// This function handles transparent types automatically.
|
/// This function handles transparent types automatically.
|
||||||
pub fn pass_indirectly_in_non_rustic_abis<C>(self, cx: &C) -> bool
|
pub fn pass_indirectly_in_non_rustic_abis<C>(mut self, cx: &C) -> bool
|
||||||
where
|
|
||||||
Ty: TyAbiInterface<'a, C> + Copy,
|
|
||||||
{
|
|
||||||
let base = self.peel_transparent_wrappers(cx);
|
|
||||||
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Recursively peel away transparent wrappers, returning the inner value.
|
|
||||||
///
|
|
||||||
/// The return value is not `repr(transparent)` and/or does
|
|
||||||
/// not have a non-1zst field.
|
|
||||||
pub fn peel_transparent_wrappers<C>(mut self, cx: &C) -> Self
|
|
||||||
where
|
where
|
||||||
Ty: TyAbiInterface<'a, C> + Copy,
|
Ty: TyAbiInterface<'a, C> + Copy,
|
||||||
{
|
{
|
||||||
|
|
@ -312,7 +292,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
self = field;
|
self = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the one field that is not a 1-ZST.
|
/// Finds the one field that is not a 1-ZST.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![cfg_attr(all(feature = "nightly", bootstrap, test), feature(assert_matches))]
|
|
||||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||||
|
#![cfg_attr(feature = "nightly", feature(assert_matches))]
|
||||||
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
||||||
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
@ -96,11 +96,9 @@ bitflags! {
|
||||||
/// If true, the type is always passed indirectly by non-Rustic ABIs.
|
/// If true, the type is always passed indirectly by non-Rustic ABIs.
|
||||||
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
||||||
const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
|
const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
|
||||||
const IS_SCALABLE = 1 << 6;
|
/// Any of these flags being set prevent field reordering optimisation.
|
||||||
// Any of these flags being set prevent field reordering optimisation.
|
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
|
||||||
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
|
|
||||||
| ReprFlags::IS_SIMD.bits()
|
| ReprFlags::IS_SIMD.bits()
|
||||||
| ReprFlags::IS_SCALABLE.bits()
|
|
||||||
| ReprFlags::IS_LINEAR.bits();
|
| ReprFlags::IS_LINEAR.bits();
|
||||||
const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
|
const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
|
||||||
}
|
}
|
||||||
|
|
@ -137,19 +135,6 @@ impl IntegerType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "nightly",
|
|
||||||
derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
|
|
||||||
)]
|
|
||||||
pub enum ScalableElt {
|
|
||||||
/// `N` in `rustc_scalable_vector(N)` - the element count of the scalable vector
|
|
||||||
ElementCount(u16),
|
|
||||||
/// `rustc_scalable_vector` w/out `N`, used for tuple types of scalable vectors that only
|
|
||||||
/// contain other scalable vectors
|
|
||||||
Container,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the repr options provided by the user.
|
/// Represents the repr options provided by the user.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
|
|
@ -161,8 +146,6 @@ pub struct ReprOptions {
|
||||||
pub align: Option<Align>,
|
pub align: Option<Align>,
|
||||||
pub pack: Option<Align>,
|
pub pack: Option<Align>,
|
||||||
pub flags: ReprFlags,
|
pub flags: ReprFlags,
|
||||||
/// `#[rustc_scalable_vector]`
|
|
||||||
pub scalable: Option<ScalableElt>,
|
|
||||||
/// The seed to be used for randomizing a type's layout
|
/// The seed to be used for randomizing a type's layout
|
||||||
///
|
///
|
||||||
/// Note: This could technically be a `u128` which would
|
/// Note: This could technically be a `u128` which would
|
||||||
|
|
@ -179,11 +162,6 @@ impl ReprOptions {
|
||||||
self.flags.contains(ReprFlags::IS_SIMD)
|
self.flags.contains(ReprFlags::IS_SIMD)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn scalable(&self) -> bool {
|
|
||||||
self.flags.contains(ReprFlags::IS_SCALABLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn c(&self) -> bool {
|
pub fn c(&self) -> bool {
|
||||||
self.flags.contains(ReprFlags::IS_C)
|
self.flags.contains(ReprFlags::IS_C)
|
||||||
|
|
@ -1636,14 +1614,19 @@ pub enum FieldsShape<FieldIdx: Idx> {
|
||||||
// FIXME(eddyb) use small vector optimization for the common case.
|
// FIXME(eddyb) use small vector optimization for the common case.
|
||||||
offsets: IndexVec<FieldIdx, Size>,
|
offsets: IndexVec<FieldIdx, Size>,
|
||||||
|
|
||||||
/// Maps memory order field indices to source order indices,
|
/// Maps source order field indices to memory order indices,
|
||||||
/// depending on how the fields were reordered (if at all).
|
/// depending on how the fields were reordered (if at all).
|
||||||
/// This is a permutation, with both the source order and the
|
/// This is a permutation, with both the source order and the
|
||||||
/// memory order using the same (0..n) index ranges.
|
/// memory order using the same (0..n) index ranges.
|
||||||
///
|
///
|
||||||
|
/// Note that during computation of `memory_index`, sometimes
|
||||||
|
/// it is easier to operate on the inverse mapping (that is,
|
||||||
|
/// from memory order to source order), and that is usually
|
||||||
|
/// named `inverse_memory_index`.
|
||||||
|
///
|
||||||
// FIXME(eddyb) build a better abstraction for permutations, if possible.
|
// FIXME(eddyb) build a better abstraction for permutations, if possible.
|
||||||
// FIXME(camlorn) also consider small vector optimization here.
|
// FIXME(camlorn) also consider small vector optimization here.
|
||||||
in_memory_order: IndexVec<u32, FieldIdx>,
|
memory_index: IndexVec<FieldIdx, u32>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1677,17 +1660,51 @@ impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn memory_index(&self, i: usize) -> usize {
|
||||||
|
match *self {
|
||||||
|
FieldsShape::Primitive => {
|
||||||
|
unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
|
||||||
|
}
|
||||||
|
FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
|
||||||
|
FieldsShape::Arbitrary { ref memory_index, .. } => {
|
||||||
|
memory_index[FieldIdx::new(i)].try_into().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets source indices of the fields by increasing offsets.
|
/// Gets source indices of the fields by increasing offsets.
|
||||||
#[inline]
|
#[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();
|
||||||
|
|
||||||
|
// We have to write this logic twice in order to keep the array small.
|
||||||
|
if let FieldsShape::Arbitrary { ref memory_index, .. } = *self {
|
||||||
|
if use_small {
|
||||||
|
for (field_idx, &mem_idx) in memory_index.iter_enumerated() {
|
||||||
|
inverse_small[mem_idx as usize] = field_idx.index() as u8;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inverse_big = memory_index.invert_bijective_mapping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Primitives don't really have fields in the way that structs do,
|
// Primitives don't really have fields in the way that structs do,
|
||||||
// but having this return an empty iterator for them is unhelpful
|
// but having this return an empty iterator for them is unhelpful
|
||||||
// since that makes them look kinda like ZSTs, which they're not.
|
// since that makes them look kinda like ZSTs, which they're not.
|
||||||
let pseudofield_count = if let FieldsShape::Primitive = self { 1 } else { self.count() };
|
let pseudofield_count = if let FieldsShape::Primitive = self { 1 } else { self.count() };
|
||||||
|
|
||||||
(0..pseudofield_count).map(move |i| match self {
|
(0..pseudofield_count).map(move |i| match *self {
|
||||||
FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
|
FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
|
||||||
FieldsShape::Arbitrary { in_memory_order, .. } => in_memory_order[i as u32].index(),
|
FieldsShape::Arbitrary { .. } => {
|
||||||
|
if use_small {
|
||||||
|
inverse_small[i] as usize
|
||||||
|
} else {
|
||||||
|
inverse_big[i as u32].index()
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1719,10 +1736,6 @@ impl AddressSpace {
|
||||||
pub enum BackendRepr {
|
pub enum BackendRepr {
|
||||||
Scalar(Scalar),
|
Scalar(Scalar),
|
||||||
ScalarPair(Scalar, Scalar),
|
ScalarPair(Scalar, Scalar),
|
||||||
ScalableVector {
|
|
||||||
element: Scalar,
|
|
||||||
count: u64,
|
|
||||||
},
|
|
||||||
SimdVector {
|
SimdVector {
|
||||||
element: Scalar,
|
element: Scalar,
|
||||||
count: u64,
|
count: u64,
|
||||||
|
|
@ -1741,12 +1754,6 @@ impl BackendRepr {
|
||||||
match *self {
|
match *self {
|
||||||
BackendRepr::Scalar(_)
|
BackendRepr::Scalar(_)
|
||||||
| BackendRepr::ScalarPair(..)
|
| BackendRepr::ScalarPair(..)
|
||||||
// FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
|
|
||||||
// `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
|
|
||||||
// fully implemented, scalable vectors will remain `Sized`, they just won't be
|
|
||||||
// `const Sized` - whether `is_unsized` continues to return `false` at that point will
|
|
||||||
// need to be revisited and will depend on what `is_unsized` is used for.
|
|
||||||
| BackendRepr::ScalableVector { .. }
|
|
||||||
| BackendRepr::SimdVector { .. } => false,
|
| BackendRepr::SimdVector { .. } => false,
|
||||||
BackendRepr::Memory { sized } => !sized,
|
BackendRepr::Memory { sized } => !sized,
|
||||||
}
|
}
|
||||||
|
|
@ -1787,9 +1794,7 @@ impl BackendRepr {
|
||||||
BackendRepr::Scalar(s) => Some(s.align(cx).abi),
|
BackendRepr::Scalar(s) => Some(s.align(cx).abi),
|
||||||
BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.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
|
// The align of a Vector can vary in surprising ways
|
||||||
BackendRepr::SimdVector { .. }
|
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
|
||||||
| BackendRepr::Memory { .. }
|
|
||||||
| BackendRepr::ScalableVector { .. } => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1811,9 +1816,7 @@ impl BackendRepr {
|
||||||
Some(size)
|
Some(size)
|
||||||
}
|
}
|
||||||
// The size of a Vector can vary in surprising ways
|
// The size of a Vector can vary in surprising ways
|
||||||
BackendRepr::SimdVector { .. }
|
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
|
||||||
| BackendRepr::Memory { .. }
|
|
||||||
| BackendRepr::ScalableVector { .. } => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1828,9 +1831,6 @@ impl BackendRepr {
|
||||||
BackendRepr::SimdVector { element: element.to_union(), count }
|
BackendRepr::SimdVector { element: element.to_union(), count }
|
||||||
}
|
}
|
||||||
BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
|
BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
|
||||||
BackendRepr::ScalableVector { element, count } => {
|
|
||||||
BackendRepr::ScalableVector { element: element.to_union(), count }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2071,9 +2071,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
|
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
|
||||||
pub fn is_aggregate(&self) -> bool {
|
pub fn is_aggregate(&self) -> bool {
|
||||||
match self.backend_repr {
|
match self.backend_repr {
|
||||||
BackendRepr::Scalar(_)
|
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false,
|
||||||
| BackendRepr::SimdVector { .. }
|
|
||||||
| BackendRepr::ScalableVector { .. } => false,
|
|
||||||
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
|
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2167,19 +2165,6 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1
|
self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the size of the type is only known at runtime.
|
|
||||||
pub fn is_runtime_sized(&self) -> bool {
|
|
||||||
matches!(self.backend_repr, BackendRepr::ScalableVector { .. })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the elements count of a scalable vector.
|
|
||||||
pub fn scalable_vector_element_count(&self) -> Option<u64> {
|
|
||||||
match self.backend_repr {
|
|
||||||
BackendRepr::ScalableVector { count, .. } => Some(count),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the type is a ZST and not unsized.
|
/// Returns `true` if the type is a ZST and not unsized.
|
||||||
///
|
///
|
||||||
/// Note that this does *not* imply that the type is irrelevant for layout! It can still have
|
/// Note that this does *not* imply that the type is irrelevant for layout! It can still have
|
||||||
|
|
@ -2188,7 +2173,6 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
match self.backend_repr {
|
match self.backend_repr {
|
||||||
BackendRepr::Scalar(_)
|
BackendRepr::Scalar(_)
|
||||||
| BackendRepr::ScalarPair(..)
|
| BackendRepr::ScalarPair(..)
|
||||||
| BackendRepr::ScalableVector { .. }
|
|
||||||
| BackendRepr::SimdVector { .. } => false,
|
| BackendRepr::SimdVector { .. } => false,
|
||||||
BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
|
BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,11 @@
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![allow(clippy::mut_from_ref)] // Arena allocators are one place where this pattern is fine.
|
#![allow(clippy::mut_from_ref)] // Arena allocators are one place where this pattern is fine.
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
|
#![cfg_attr(bootstrap, feature(maybe_uninit_slice))]
|
||||||
#![cfg_attr(test, feature(test))]
|
#![cfg_attr(test, feature(test))]
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
#![doc(test(no_crate_inject, attr(deny(warnings), allow(internal_features))))]
|
#![doc(test(no_crate_inject, attr(deny(warnings), allow(internal_features))))]
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(dropck_eyepatch)]
|
#![feature(dropck_eyepatch)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
|
@ -25,7 +27,7 @@ use std::cell::{Cell, RefCell};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem::{self, MaybeUninit};
|
use std::mem::{self, MaybeUninit};
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
use std::{cmp, hint, slice};
|
use std::{cmp, intrinsics, slice};
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
|
@ -171,22 +173,8 @@ impl<T> TypedArena<T> {
|
||||||
available_bytes >= additional_bytes
|
available_bytes >= additional_bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates storage for `len >= 1` values in this arena, and returns a
|
|
||||||
/// raw pointer to the first value's storage.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Caller must initialize each of the `len` slots to a droppable value
|
|
||||||
/// before the arena is dropped.
|
|
||||||
///
|
|
||||||
/// In practice, this typically means that the caller must be able to
|
|
||||||
/// raw-copy `len` already-initialized values into the slice without any
|
|
||||||
/// possibility of panicking.
|
|
||||||
///
|
|
||||||
/// FIXME(Zalathar): This is *very* fragile; perhaps we need a different
|
|
||||||
/// approach to arena-allocating slices of droppable values.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T {
|
fn alloc_raw_slice(&self, len: usize) -> *mut T {
|
||||||
assert!(size_of::<T>() != 0);
|
assert!(size_of::<T>() != 0);
|
||||||
assert!(len != 0);
|
assert!(len != 0);
|
||||||
|
|
||||||
|
|
@ -221,7 +209,7 @@ impl<T> TypedArena<T> {
|
||||||
&self,
|
&self,
|
||||||
iter: impl IntoIterator<Item = Result<T, E>>,
|
iter: impl IntoIterator<Item = Result<T, E>>,
|
||||||
) -> Result<&mut [T], E> {
|
) -> Result<&mut [T], E> {
|
||||||
// Despite the similarity with `DroplessArena`, we cannot reuse their fast case. The reason
|
// Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason
|
||||||
// is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a
|
// is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a
|
||||||
// reference to `self` and adding elements to the arena during iteration.
|
// reference to `self` and adding elements to the arena during iteration.
|
||||||
//
|
//
|
||||||
|
|
@ -242,15 +230,9 @@ impl<T> TypedArena<T> {
|
||||||
}
|
}
|
||||||
// Move the content to the arena by copying and then forgetting it.
|
// Move the content to the arena by copying and then forgetting it.
|
||||||
let len = vec.len();
|
let len = vec.len();
|
||||||
|
let start_ptr = self.alloc_raw_slice(len);
|
||||||
// SAFETY: After allocating raw storage for exactly `len` values, we
|
|
||||||
// must fully initialize the storage without panicking, and we must
|
|
||||||
// also prevent the stale values in the vec from being dropped.
|
|
||||||
Ok(unsafe {
|
Ok(unsafe {
|
||||||
let start_ptr = self.alloc_raw_slice(len);
|
|
||||||
// Initialize the newly-allocated storage without panicking.
|
|
||||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||||
// Prevent the stale values in the vec from being dropped.
|
|
||||||
vec.set_len(0);
|
vec.set_len(0);
|
||||||
slice::from_raw_parts_mut(start_ptr, len)
|
slice::from_raw_parts_mut(start_ptr, len)
|
||||||
})
|
})
|
||||||
|
|
@ -451,7 +433,7 @@ impl DroplessArena {
|
||||||
let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT);
|
let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT);
|
||||||
|
|
||||||
// Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT.
|
// Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT.
|
||||||
unsafe { hint::assert_unchecked(end == align_down(end, DROPLESS_ALIGNMENT)) };
|
unsafe { intrinsics::assume(end == align_down(end, DROPLESS_ALIGNMENT)) };
|
||||||
|
|
||||||
if let Some(sub) = end.checked_sub(bytes) {
|
if let Some(sub) = end.checked_sub(bytes) {
|
||||||
let new_end = align_down(sub, layout.align());
|
let new_end = align_down(sub, layout.align());
|
||||||
|
|
@ -509,6 +491,19 @@ impl DroplessArena {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used by `Lift` to check whether this slice is allocated
|
||||||
|
/// in this arena.
|
||||||
|
#[inline]
|
||||||
|
pub fn contains_slice<T>(&self, slice: &[T]) -> bool {
|
||||||
|
for chunk in self.chunks.borrow_mut().iter_mut() {
|
||||||
|
let ptr = slice.as_ptr().cast::<u8>().cast_mut();
|
||||||
|
if chunk.start() <= ptr && chunk.end() >= ptr {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Allocates a string slice that is copied into the `DroplessArena`, returning a
|
/// Allocates a string slice that is copied into the `DroplessArena`, returning a
|
||||||
/// reference to it. Will panic if passed an empty string.
|
/// reference to it. Will panic if passed an empty string.
|
||||||
///
|
///
|
||||||
|
|
@ -590,7 +585,7 @@ impl DroplessArena {
|
||||||
&self,
|
&self,
|
||||||
iter: impl IntoIterator<Item = Result<T, E>>,
|
iter: impl IntoIterator<Item = Result<T, E>>,
|
||||||
) -> Result<&mut [T], E> {
|
) -> Result<&mut [T], E> {
|
||||||
// Despite the similarity with `alloc_from_iter`, we cannot reuse their fast case, as we
|
// Despite the similarlty with `alloc_from_iter`, we cannot reuse their fast case, as we
|
||||||
// cannot know the minimum length of the iterator in this case.
|
// cannot know the minimum length of the iterator in this case.
|
||||||
assert!(size_of::<T>() != 0);
|
assert!(size_of::<T>() != 0);
|
||||||
|
|
||||||
|
|
@ -624,7 +619,7 @@ impl DroplessArena {
|
||||||
/// - Types that are `!Copy` and `Drop`: these must be specified in the
|
/// - Types that are `!Copy` and `Drop`: these must be specified in the
|
||||||
/// arguments. The `TypedArena` will be used for them.
|
/// arguments. The `TypedArena` will be used for them.
|
||||||
///
|
///
|
||||||
#[rustc_macro_transparency = "semiopaque"]
|
#[rustc_macro_transparency = "semitransparent"]
|
||||||
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
|
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Arena<'tcx> {
|
pub struct Arena<'tcx> {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ edition = "2024"
|
||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
bitflags = "2.4.1"
|
bitflags = "2.4.1"
|
||||||
memchr = "2.7.6"
|
memchr = "2.7.6"
|
||||||
rustc-literal-escaper = "0.0.7"
|
rustc-literal-escaper = "0.0.5"
|
||||||
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ use rustc_span::source_map::{Spanned, respan};
|
||||||
use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
||||||
use thin_vec::{ThinVec, thin_vec};
|
use thin_vec::{ThinVec, thin_vec};
|
||||||
|
|
||||||
use crate::attr::data_structures::CfgEntry;
|
|
||||||
pub use crate::format::*;
|
pub use crate::format::*;
|
||||||
use crate::token::{self, CommentKind, Delimiter};
|
use crate::token::{self, CommentKind, Delimiter};
|
||||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||||
|
|
@ -142,11 +141,16 @@ impl Path {
|
||||||
/// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_
|
/// 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.
|
/// be represented without an anon const in the HIR.
|
||||||
///
|
///
|
||||||
/// Returns true iff the path has exactly one segment, and it has no generic args
|
/// 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).
|
/// (i.e., it is _potentially_ a const parameter).
|
||||||
#[tracing::instrument(level = "debug", ret)]
|
#[tracing::instrument(level = "debug", ret)]
|
||||||
pub fn is_potential_trivial_const_arg(&self) -> bool {
|
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
|
||||||
self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none())
|
allow_mgca_arg
|
||||||
|
|| self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -656,7 +660,11 @@ impl Pat {
|
||||||
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
|
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
|
||||||
// assuming `T0` to `Tn` are all syntactically valid as types.
|
// assuming `T0` to `Tn` are all syntactically valid as types.
|
||||||
PatKind::Tuple(pats) => {
|
PatKind::Tuple(pats) => {
|
||||||
let tys = pats.iter().map(|pat| pat.to_ty()).collect::<Option<ThinVec<_>>>()?;
|
let mut tys = ThinVec::with_capacity(pats.len());
|
||||||
|
// FIXME(#48994) - could just be collected into an Option<Vec>
|
||||||
|
for pat in pats {
|
||||||
|
tys.push(pat.to_ty()?);
|
||||||
|
}
|
||||||
TyKind::Tup(tys)
|
TyKind::Tup(tys)
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
|
@ -1251,19 +1259,6 @@ pub enum StmtKind {
|
||||||
MacCall(Box<MacCallStmt>),
|
MacCall(Box<MacCallStmt>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StmtKind {
|
|
||||||
pub fn descr(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
StmtKind::Let(_) => "local",
|
|
||||||
StmtKind::Item(_) => "item",
|
|
||||||
StmtKind::Expr(_) => "expression",
|
|
||||||
StmtKind::Semi(_) => "statement",
|
|
||||||
StmtKind::Empty => "semicolon",
|
|
||||||
StmtKind::MacCall(_) => "macro call",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||||
pub struct MacCallStmt {
|
pub struct MacCallStmt {
|
||||||
pub mac: Box<MacCall>,
|
pub mac: Box<MacCall>,
|
||||||
|
|
@ -1377,15 +1372,6 @@ pub enum UnsafeSource {
|
||||||
UserProvided,
|
UserProvided,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Track whether under `feature(min_generic_const_args)` this anon const
|
|
||||||
/// was explicitly disambiguated as an anon const or not through the use of
|
|
||||||
/// `const { ... }` syntax.
|
|
||||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Walkable)]
|
|
||||||
pub enum MgcaDisambiguation {
|
|
||||||
AnonConst,
|
|
||||||
Direct,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A constant (expression) that's not an item or associated item,
|
/// A constant (expression) that's not an item or associated item,
|
||||||
/// but needs its own `DefId` for type-checking, const-eval, etc.
|
/// but needs its own `DefId` for type-checking, const-eval, etc.
|
||||||
/// These are usually found nested inside types (e.g., array lengths)
|
/// These are usually found nested inside types (e.g., array lengths)
|
||||||
|
|
@ -1395,7 +1381,6 @@ pub enum MgcaDisambiguation {
|
||||||
pub struct AnonConst {
|
pub struct AnonConst {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub value: Box<Expr>,
|
pub value: Box<Expr>,
|
||||||
pub mgca_disambiguation: MgcaDisambiguation,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An expression.
|
/// An expression.
|
||||||
|
|
@ -1414,20 +1399,26 @@ impl Expr {
|
||||||
///
|
///
|
||||||
/// This will unwrap at most one block level (curly braces). After that, if the expression
|
/// 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`].
|
/// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`].
|
||||||
|
/// See there for more info about `allow_mgca_arg`.
|
||||||
///
|
///
|
||||||
/// This function will only allow paths with no qself, before dispatching to the `Path`
|
/// The only additional thing to note is that when `allow_mgca_arg` is false, this function
|
||||||
/// function of the same name.
|
/// 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.
|
/// 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.
|
/// This also does not consider macros, so it's only correct after macro-expansion.
|
||||||
pub fn is_potential_trivial_const_arg(&self) -> bool {
|
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
|
||||||
let this = self.maybe_unwrap_block();
|
let this = self.maybe_unwrap_block();
|
||||||
if let ExprKind::Path(None, path) = &this.kind
|
if allow_mgca_arg {
|
||||||
&& path.is_potential_trivial_const_arg()
|
matches!(this.kind, ExprKind::Path(..))
|
||||||
{
|
|
||||||
true
|
|
||||||
} else {
|
} else {
|
||||||
false
|
if let ExprKind::Path(None, path) = &this.kind
|
||||||
|
&& path.is_potential_trivial_const_arg(allow_mgca_arg)
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1530,10 +1521,11 @@ impl Expr {
|
||||||
// then type of result is trait object.
|
// then type of result is trait object.
|
||||||
// Otherwise we don't assume the result type.
|
// Otherwise we don't assume the result type.
|
||||||
ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => {
|
ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => {
|
||||||
let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) else {
|
if let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) {
|
||||||
|
TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None)
|
||||||
|
} else {
|
||||||
return None;
|
return None;
|
||||||
};
|
}
|
||||||
TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Underscore => TyKind::Infer,
|
ExprKind::Underscore => TyKind::Infer,
|
||||||
|
|
@ -1807,21 +1799,15 @@ pub enum ExprKind {
|
||||||
/// or a `gen` block (`gen move { ... }`).
|
/// or a `gen` block (`gen move { ... }`).
|
||||||
///
|
///
|
||||||
/// The span is the "decl", which is the header before the body `{ }`
|
/// The span is the "decl", which is the header before the body `{ }`
|
||||||
/// including the `async`/`gen` keywords and possibly `move`.
|
/// including the `asyng`/`gen` keywords and possibly `move`.
|
||||||
Gen(CaptureBy, Box<Block>, GenBlockKind, Span),
|
Gen(CaptureBy, Box<Block>, GenBlockKind, Span),
|
||||||
/// An await expression (`my_future.await`). Span is of await keyword.
|
/// An await expression (`my_future.await`). Span is of await keyword.
|
||||||
Await(Box<Expr>, Span),
|
Await(Box<Expr>, Span),
|
||||||
/// A use expression (`x.use`). Span is of use keyword.
|
/// A use expression (`x.use`). Span is of use keyword.
|
||||||
Use(Box<Expr>, Span),
|
Use(Box<Expr>, Span),
|
||||||
|
|
||||||
/// A try block (`try { ... }`), if the type is `None`, or
|
/// A try block (`try { ... }`).
|
||||||
/// A try block (`try bikeshed Ty { ... }`) if the type is `Some`.
|
TryBlock(Box<Block>),
|
||||||
///
|
|
||||||
/// Note that `try bikeshed` is a *deliberately ridiculous* placeholder
|
|
||||||
/// syntax to avoid deciding what keyword or symbol should go there.
|
|
||||||
/// It's that way for experimentation only; an RFC to decide the final
|
|
||||||
/// semantics and syntax would be needed to put it on stabilization-track.
|
|
||||||
TryBlock(Box<Block>, Option<Box<Ty>>),
|
|
||||||
|
|
||||||
/// An assignment (`a = foo()`).
|
/// An assignment (`a = foo()`).
|
||||||
/// The `Span` argument is the span of the `=` token.
|
/// The `Span` argument is the span of the `=` token.
|
||||||
|
|
@ -2104,20 +2090,6 @@ pub struct MacroDef {
|
||||||
pub body: Box<DelimArgs>,
|
pub body: Box<DelimArgs>,
|
||||||
/// `true` if macro was defined with `macro_rules`.
|
/// `true` if macro was defined with `macro_rules`.
|
||||||
pub macro_rules: bool,
|
pub macro_rules: bool,
|
||||||
|
|
||||||
/// Corresponds to `#[eii_declaration(...)]`.
|
|
||||||
/// `#[eii_declaration(...)]` is a built-in attribute macro, not a built-in attribute,
|
|
||||||
/// because we require some name resolution to occur in the parameters of this attribute.
|
|
||||||
/// Name resolution isn't possible in attributes otherwise, so we encode it in the AST.
|
|
||||||
/// During ast lowering, we turn it back into an attribute again
|
|
||||||
pub eii_declaration: Option<EiiDecl>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
|
||||||
pub struct EiiDecl {
|
|
||||||
/// path to the extern item we're targeting
|
|
||||||
pub foreign_item: Path,
|
|
||||||
pub impl_unsafe: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
|
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
|
||||||
|
|
@ -2392,7 +2364,7 @@ impl FnSig {
|
||||||
/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
|
/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
|
||||||
/// * the `A: Bound` in `Trait<A: Bound>`
|
/// * the `A: Bound` in `Trait<A: Bound>`
|
||||||
/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
|
/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
|
||||||
/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `min_generic_const_args`)
|
/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
|
||||||
/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
|
/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||||
pub struct AssocItemConstraint {
|
pub struct AssocItemConstraint {
|
||||||
|
|
@ -3131,16 +3103,8 @@ pub enum Const {
|
||||||
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
||||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
||||||
pub enum Defaultness {
|
pub enum Defaultness {
|
||||||
/// Item is unmarked. Implicitly determined based off of position.
|
|
||||||
/// For impls, this is `final`; for traits, this is `default`.
|
|
||||||
///
|
|
||||||
/// If you're expanding an item in a built-in macro or parsing an item
|
|
||||||
/// by hand, you probably want to use this.
|
|
||||||
Implicit,
|
|
||||||
/// `default`
|
|
||||||
Default(Span),
|
Default(Span),
|
||||||
/// `final`; per RFC 3678, only trait items may be *explicitly* marked final.
|
Final,
|
||||||
Final(Span),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||||
|
|
@ -3352,8 +3316,7 @@ impl UseTree {
|
||||||
/// Distinguishes between `Attribute`s that decorate items and Attributes that
|
/// Distinguishes between `Attribute`s that decorate items and Attributes that
|
||||||
/// are contained as statements within items. These two cases need to be
|
/// are contained as statements within items. These two cases need to be
|
||||||
/// distinguished for pretty-printing.
|
/// distinguished for pretty-printing.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
|
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic, Walkable)]
|
||||||
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
|
|
||||||
pub enum AttrStyle {
|
pub enum AttrStyle {
|
||||||
Outer,
|
Outer,
|
||||||
Inner,
|
Inner,
|
||||||
|
|
@ -3397,7 +3360,7 @@ impl NormalAttr {
|
||||||
item: AttrItem {
|
item: AttrItem {
|
||||||
unsafety: Safety::Default,
|
unsafety: Safety::Default,
|
||||||
path: Path::from_ident(ident),
|
path: Path::from_ident(ident),
|
||||||
args: AttrItemKind::Unparsed(AttrArgs::Empty),
|
args: AttrArgs::Empty,
|
||||||
tokens: None,
|
tokens: None,
|
||||||
},
|
},
|
||||||
tokens: None,
|
tokens: None,
|
||||||
|
|
@ -3409,53 +3372,11 @@ impl NormalAttr {
|
||||||
pub struct AttrItem {
|
pub struct AttrItem {
|
||||||
pub unsafety: Safety,
|
pub unsafety: Safety,
|
||||||
pub path: Path,
|
pub path: Path,
|
||||||
pub args: AttrItemKind,
|
pub args: AttrArgs,
|
||||||
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
|
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
|
||||||
pub tokens: Option<LazyAttrTokenStream>,
|
pub tokens: Option<LazyAttrTokenStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Some attributes are stored in a parsed form, for performance reasons.
|
|
||||||
/// Their arguments don't have to be reparsed everytime they're used
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
|
||||||
pub enum AttrItemKind {
|
|
||||||
Parsed(EarlyParsedAttribute),
|
|
||||||
Unparsed(AttrArgs),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AttrItemKind {
|
|
||||||
pub fn unparsed(self) -> Option<AttrArgs> {
|
|
||||||
match self {
|
|
||||||
AttrItemKind::Unparsed(args) => Some(args),
|
|
||||||
AttrItemKind::Parsed(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unparsed_ref(&self) -> Option<&AttrArgs> {
|
|
||||||
match self {
|
|
||||||
AttrItemKind::Unparsed(args) => Some(args),
|
|
||||||
AttrItemKind::Parsed(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn span(&self) -> Option<Span> {
|
|
||||||
match self {
|
|
||||||
AttrItemKind::Unparsed(args) => args.span(),
|
|
||||||
AttrItemKind::Parsed(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Some attributes are stored in parsed form in the AST.
|
|
||||||
/// This is done for performance reasons, so the attributes don't need to be reparsed on every use.
|
|
||||||
///
|
|
||||||
/// Currently all early parsed attributes are excluded from pretty printing at rustc_ast_pretty::pprust::state::print_attribute_inline.
|
|
||||||
/// When adding new early parsed attributes, consider whether they should be pretty printed.
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
|
||||||
pub enum EarlyParsedAttribute {
|
|
||||||
CfgTrace(CfgEntry),
|
|
||||||
CfgAttrTrace,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AttrItem {
|
impl AttrItem {
|
||||||
pub fn is_valid_for_outer_style(&self) -> bool {
|
pub fn is_valid_for_outer_style(&self) -> bool {
|
||||||
self.path == sym::cfg_attr
|
self.path == sym::cfg_attr
|
||||||
|
|
@ -3630,7 +3551,6 @@ impl Item {
|
||||||
pub fn opt_generics(&self) -> Option<&Generics> {
|
pub fn opt_generics(&self) -> Option<&Generics> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
ItemKind::ExternCrate(..)
|
ItemKind::ExternCrate(..)
|
||||||
| ItemKind::ConstBlock(_)
|
|
||||||
| ItemKind::Use(_)
|
| ItemKind::Use(_)
|
||||||
| ItemKind::Mod(..)
|
| ItemKind::Mod(..)
|
||||||
| ItemKind::ForeignMod(_)
|
| ItemKind::ForeignMod(_)
|
||||||
|
|
@ -3809,34 +3729,6 @@ pub struct Fn {
|
||||||
pub contract: Option<Box<FnContract>>,
|
pub contract: Option<Box<FnContract>>,
|
||||||
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
||||||
pub body: Option<Box<Block>>,
|
pub body: Option<Box<Block>>,
|
||||||
|
|
||||||
/// This function is an implementation of an externally implementable item (EII).
|
|
||||||
/// This means, there was an EII declared somewhere and this function is the
|
|
||||||
/// implementation that should be run when the declaration is called.
|
|
||||||
pub eii_impls: ThinVec<EiiImpl>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
|
||||||
pub struct EiiImpl {
|
|
||||||
pub node_id: NodeId,
|
|
||||||
pub eii_macro_path: Path,
|
|
||||||
/// This field is an implementation detail that prevents a lot of bugs.
|
|
||||||
/// See <https://github.com/rust-lang/rust/issues/149981> for an example.
|
|
||||||
///
|
|
||||||
/// The problem is, that if we generate a declaration *together* with its default,
|
|
||||||
/// we generate both a declaration and an implementation. The generated implementation
|
|
||||||
/// uses the same mechanism to register itself as a user-defined implementation would,
|
|
||||||
/// despite being invisible to users. What does happen is a name resolution step.
|
|
||||||
/// The invisible default implementation has to find the declaration.
|
|
||||||
/// Both are generated at the same time, so we can skip that name resolution step.
|
|
||||||
///
|
|
||||||
/// This field is that shortcut: we prefill the extern target to skip a name resolution step,
|
|
||||||
/// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user.
|
|
||||||
pub known_eii_macro_resolution: Option<EiiDecl>,
|
|
||||||
pub impl_safety: Safety,
|
|
||||||
pub span: Span,
|
|
||||||
pub inner_span: Span,
|
|
||||||
pub is_default: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||||
|
|
@ -3877,55 +3769,27 @@ pub struct ConstItem {
|
||||||
pub ident: Ident,
|
pub ident: Ident,
|
||||||
pub generics: Generics,
|
pub generics: Generics,
|
||||||
pub ty: Box<Ty>,
|
pub ty: Box<Ty>,
|
||||||
pub rhs_kind: ConstItemRhsKind,
|
pub rhs: Option<ConstItemRhs>,
|
||||||
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||||
pub enum ConstItemRhsKind {
|
pub enum ConstItemRhs {
|
||||||
Body { rhs: Option<Box<Expr>> },
|
TypeConst(AnonConst),
|
||||||
TypeConst { rhs: Option<AnonConst> },
|
Body(Box<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstItemRhsKind {
|
impl ConstItemRhs {
|
||||||
pub fn new_body(rhs: Box<Expr>) -> Self {
|
pub fn span(&self) -> Span {
|
||||||
Self::Body { rhs: Some(rhs) }
|
self.expr().span
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn span(&self) -> Option<Span> {
|
pub fn expr(&self) -> &Expr {
|
||||||
Some(self.expr()?.span)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expr(&self) -> Option<&Expr> {
|
|
||||||
match self {
|
match self {
|
||||||
Self::Body { rhs: Some(body) } => Some(&body),
|
ConstItemRhs::TypeConst(anon_const) => &anon_const.value,
|
||||||
Self::TypeConst { rhs: Some(anon) } => Some(&anon.value),
|
ConstItemRhs::Body(expr) => expr,
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_expr(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Body { rhs: Some(_) } => true,
|
|
||||||
Self::TypeConst { rhs: Some(_) } => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_type_const(&self) -> bool {
|
|
||||||
matches!(self, &Self::TypeConst { .. })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
|
||||||
pub struct ConstBlockItem {
|
|
||||||
pub id: NodeId,
|
|
||||||
pub span: Span,
|
|
||||||
pub block: Box<Block>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConstBlockItem {
|
|
||||||
pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
||||||
|
|
@ -3947,11 +3811,6 @@ pub enum ItemKind {
|
||||||
///
|
///
|
||||||
/// E.g., `const FOO: i32 = 42;`.
|
/// E.g., `const FOO: i32 = 42;`.
|
||||||
Const(Box<ConstItem>),
|
Const(Box<ConstItem>),
|
||||||
/// A module-level const block.
|
|
||||||
/// Equivalent to `const _: () = const { ... };`.
|
|
||||||
///
|
|
||||||
/// E.g., `const { assert!(true) }`.
|
|
||||||
ConstBlock(ConstBlockItem),
|
|
||||||
/// A function declaration (`fn`).
|
/// A function declaration (`fn`).
|
||||||
///
|
///
|
||||||
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
|
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
|
||||||
|
|
@ -4028,8 +3887,6 @@ impl ItemKind {
|
||||||
| ItemKind::MacroDef(ident, _)
|
| ItemKind::MacroDef(ident, _)
|
||||||
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
|
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
|
||||||
|
|
||||||
ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT),
|
|
||||||
|
|
||||||
ItemKind::Use(_)
|
ItemKind::Use(_)
|
||||||
| ItemKind::ForeignMod(_)
|
| ItemKind::ForeignMod(_)
|
||||||
| ItemKind::GlobalAsm(_)
|
| ItemKind::GlobalAsm(_)
|
||||||
|
|
@ -4043,9 +3900,9 @@ impl ItemKind {
|
||||||
pub fn article(&self) -> &'static str {
|
pub fn article(&self) -> &'static str {
|
||||||
use ItemKind::*;
|
use ItemKind::*;
|
||||||
match self {
|
match self {
|
||||||
Use(..) | Static(..) | Const(..) | ConstBlock(..) | Fn(..) | Mod(..)
|
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
||||||
| GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..)
|
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
||||||
| MacroDef(..) | Delegation(..) | DelegationMac(..) => "a",
|
| Delegation(..) | DelegationMac(..) => "a",
|
||||||
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4056,7 +3913,6 @@ impl ItemKind {
|
||||||
ItemKind::Use(..) => "`use` import",
|
ItemKind::Use(..) => "`use` import",
|
||||||
ItemKind::Static(..) => "static item",
|
ItemKind::Static(..) => "static item",
|
||||||
ItemKind::Const(..) => "constant item",
|
ItemKind::Const(..) => "constant item",
|
||||||
ItemKind::ConstBlock(..) => "const block",
|
|
||||||
ItemKind::Fn(..) => "function",
|
ItemKind::Fn(..) => "function",
|
||||||
ItemKind::Mod(..) => "module",
|
ItemKind::Mod(..) => "module",
|
||||||
ItemKind::ForeignMod(..) => "extern block",
|
ItemKind::ForeignMod(..) => "extern block",
|
||||||
|
|
@ -4086,18 +3942,7 @@ impl ItemKind {
|
||||||
| Self::Trait(box Trait { generics, .. })
|
| Self::Trait(box Trait { generics, .. })
|
||||||
| Self::TraitAlias(box TraitAlias { generics, .. })
|
| Self::TraitAlias(box TraitAlias { generics, .. })
|
||||||
| Self::Impl(Impl { generics, .. }) => Some(generics),
|
| Self::Impl(Impl { generics, .. }) => Some(generics),
|
||||||
|
_ => None,
|
||||||
Self::ExternCrate(..)
|
|
||||||
| Self::Use(..)
|
|
||||||
| Self::Static(..)
|
|
||||||
| Self::ConstBlock(..)
|
|
||||||
| Self::Mod(..)
|
|
||||||
| Self::ForeignMod(..)
|
|
||||||
| Self::GlobalAsm(..)
|
|
||||||
| Self::MacCall(..)
|
|
||||||
| Self::MacroDef(..)
|
|
||||||
| Self::Delegation(..)
|
|
||||||
| Self::DelegationMac(..) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4148,7 +3993,7 @@ impl AssocItemKind {
|
||||||
| Self::Fn(box Fn { defaultness, .. })
|
| Self::Fn(box Fn { defaultness, .. })
|
||||||
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
||||||
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
||||||
Defaultness::Implicit
|
Defaultness::Final
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4250,7 +4095,7 @@ mod size_asserts {
|
||||||
static_assert_size!(Block, 32);
|
static_assert_size!(Block, 32);
|
||||||
static_assert_size!(Expr, 72);
|
static_assert_size!(Expr, 72);
|
||||||
static_assert_size!(ExprKind, 40);
|
static_assert_size!(ExprKind, 40);
|
||||||
static_assert_size!(Fn, 192);
|
static_assert_size!(Fn, 184);
|
||||||
static_assert_size!(ForeignItem, 80);
|
static_assert_size!(ForeignItem, 80);
|
||||||
static_assert_size!(ForeignItemKind, 16);
|
static_assert_size!(ForeignItemKind, 16);
|
||||||
static_assert_size!(GenericArg, 24);
|
static_assert_size!(GenericArg, 24);
|
||||||
|
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
|
||||||
use rustc_span::{Span, Symbol};
|
|
||||||
use thin_vec::ThinVec;
|
|
||||||
|
|
||||||
use crate::attr::version::RustcVersion;
|
|
||||||
|
|
||||||
#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
|
|
||||||
pub enum CfgEntry {
|
|
||||||
All(ThinVec<CfgEntry>, Span),
|
|
||||||
Any(ThinVec<CfgEntry>, Span),
|
|
||||||
Not(Box<CfgEntry>, Span),
|
|
||||||
Bool(bool, Span),
|
|
||||||
NameValue { name: Symbol, value: Option<Symbol>, span: Span },
|
|
||||||
Version(Option<RustcVersion>, Span),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CfgEntry {
|
|
||||||
pub fn lower_spans(&mut self, lower_span: impl Copy + Fn(Span) -> Span) {
|
|
||||||
match self {
|
|
||||||
CfgEntry::All(subs, span) | CfgEntry::Any(subs, span) => {
|
|
||||||
*span = lower_span(*span);
|
|
||||||
subs.iter_mut().for_each(|sub| sub.lower_spans(lower_span));
|
|
||||||
}
|
|
||||||
CfgEntry::Not(sub, span) => {
|
|
||||||
*span = lower_span(*span);
|
|
||||||
sub.lower_spans(lower_span);
|
|
||||||
}
|
|
||||||
CfgEntry::Bool(_, span)
|
|
||||||
| CfgEntry::NameValue { span, .. }
|
|
||||||
| CfgEntry::Version(_, span) => {
|
|
||||||
*span = lower_span(*span);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn span(&self) -> Span {
|
|
||||||
let (Self::All(_, span)
|
|
||||||
| Self::Any(_, span)
|
|
||||||
| Self::Not(_, span)
|
|
||||||
| Self::Bool(_, span)
|
|
||||||
| Self::NameValue { span, .. }
|
|
||||||
| Self::Version(_, span)) = self;
|
|
||||||
*span
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as `PartialEq` but doesn't check spans and ignore order of cfgs.
|
|
||||||
pub fn is_equivalent_to(&self, other: &Self) -> bool {
|
|
||||||
match (self, other) {
|
|
||||||
(Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => {
|
|
||||||
a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b)))
|
|
||||||
}
|
|
||||||
(Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b),
|
|
||||||
(Self::Bool(a, _), Self::Bool(b, _)) => a == b,
|
|
||||||
(
|
|
||||||
Self::NameValue { name: name1, value: value1, .. },
|
|
||||||
Self::NameValue { name: name2, value: value2, .. },
|
|
||||||
) => name1 == name2 && value1 == value2,
|
|
||||||
(Self::Version(a, _), Self::Version(b, _)) => a == b,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for CfgEntry {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fn write_entries(
|
|
||||||
name: &str,
|
|
||||||
entries: &[CfgEntry],
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
write!(f, "{name}(")?;
|
|
||||||
for (nb, entry) in entries.iter().enumerate() {
|
|
||||||
if nb != 0 {
|
|
||||||
f.write_str(", ")?;
|
|
||||||
}
|
|
||||||
entry.fmt(f)?;
|
|
||||||
}
|
|
||||||
f.write_str(")")
|
|
||||||
}
|
|
||||||
match self {
|
|
||||||
Self::All(entries, _) => write_entries("all", entries, f),
|
|
||||||
Self::Any(entries, _) => write_entries("any", entries, f),
|
|
||||||
Self::Not(entry, _) => write!(f, "not({entry})"),
|
|
||||||
Self::Bool(value, _) => write!(f, "{value}"),
|
|
||||||
Self::NameValue { name, value, .. } => {
|
|
||||||
match value {
|
|
||||||
// We use `as_str` and debug display to have characters escaped and `"`
|
|
||||||
// characters surrounding the string.
|
|
||||||
Some(value) => write!(f, "{name} = {:?}", value.as_str()),
|
|
||||||
None => write!(f, "{name}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self::Version(version, _) => match version {
|
|
||||||
Some(version) => write!(f, "{version}"),
|
|
||||||
None => Ok(()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
//! Functions dealing with attributes and meta items.
|
//! Functions dealing with attributes and meta items.
|
||||||
|
|
||||||
pub mod data_structures;
|
|
||||||
pub mod version;
|
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
|
|
@ -11,15 +8,12 @@ use rustc_span::{Ident, Span, Symbol, sym};
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
use thin_vec::{ThinVec, thin_vec};
|
use thin_vec::{ThinVec, thin_vec};
|
||||||
|
|
||||||
use crate::AttrItemKind;
|
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
|
AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
|
||||||
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
|
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
|
||||||
PathSegment, Safety,
|
PathSegment, Safety,
|
||||||
};
|
};
|
||||||
use crate::token::{
|
use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token};
|
||||||
self, CommentKind, Delimiter, DocFragmentKind, InvisibleOrigin, MetaVarKind, Token,
|
|
||||||
};
|
|
||||||
use crate::tokenstream::{
|
use crate::tokenstream::{
|
||||||
DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
|
DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
|
||||||
};
|
};
|
||||||
|
|
@ -66,15 +60,6 @@ impl Attribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the arguments of this attribute with new arguments `AttrItemKind`.
|
|
||||||
/// This is useful for making this attribute into a trace attribute, and should otherwise be avoided.
|
|
||||||
pub fn replace_args(&mut self, new_args: AttrItemKind) {
|
|
||||||
match &mut self.kind {
|
|
||||||
AttrKind::Normal(normal) => normal.item.args = new_args,
|
|
||||||
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unwrap_normal_item(self) -> AttrItem {
|
pub fn unwrap_normal_item(self) -> AttrItem {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
AttrKind::Normal(normal) => normal.item,
|
AttrKind::Normal(normal) => normal.item,
|
||||||
|
|
@ -90,7 +75,7 @@ impl AttributeExt for Attribute {
|
||||||
|
|
||||||
fn value_span(&self) -> Option<Span> {
|
fn value_span(&self) -> Option<Span> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? {
|
AttrKind::Normal(normal) => match &normal.item.args {
|
||||||
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
@ -109,11 +94,11 @@ impl AttributeExt for Attribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
|
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
|
||||||
fn name(&self) -> Option<Symbol> {
|
fn ident(&self) -> Option<Ident> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
AttrKind::Normal(normal) => {
|
AttrKind::Normal(normal) => {
|
||||||
if let [ident] = &*normal.item.path.segments {
|
if let [ident] = &*normal.item.path.segments {
|
||||||
Some(ident.ident.name)
|
Some(ident.ident)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -122,18 +107,9 @@ impl AttributeExt for Attribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
|
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
AttrKind::Normal(p) => {
|
AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()),
|
||||||
Some(p.item.path.segments.iter().map(|i| i.ident.name).collect())
|
|
||||||
}
|
|
||||||
AttrKind::DocComment(_, _) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path_span(&self) -> Option<Span> {
|
|
||||||
match &self.kind {
|
|
||||||
AttrKind::Normal(attr) => Some(attr.item.path.span),
|
|
||||||
AttrKind::DocComment(_, _) => None,
|
AttrKind::DocComment(_, _) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +136,7 @@ impl AttributeExt for Attribute {
|
||||||
|
|
||||||
fn is_word(&self) -> bool {
|
fn is_word(&self) -> bool {
|
||||||
if let AttrKind::Normal(normal) = &self.kind {
|
if let AttrKind::Normal(normal) = &self.kind {
|
||||||
matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty))
|
matches!(normal.item.args, AttrArgs::Empty)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
@ -203,21 +179,15 @@ impl AttributeExt for Attribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
|
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
|
||||||
/// * `///doc` returns `Some(("doc", DocFragmentKind::Sugared(CommentKind::Line)))`.
|
/// * `///doc` returns `Some(("doc", CommentKind::Line))`.
|
||||||
/// * `/** doc */` returns `Some(("doc", DocFragmentKind::Sugared(CommentKind::Block)))`.
|
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
|
||||||
/// * `#[doc = "doc"]` returns `Some(("doc", DocFragmentKind::Raw))`.
|
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
|
||||||
/// * `#[doc(...)]` returns `None`.
|
/// * `#[doc(...)]` returns `None`.
|
||||||
fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
|
fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
AttrKind::DocComment(kind, data) => Some((*data, DocFragmentKind::Sugared(*kind))),
|
AttrKind::DocComment(kind, data) => Some((*data, *kind)),
|
||||||
AttrKind::Normal(normal) if normal.item.path == sym::doc => {
|
AttrKind::Normal(normal) if normal.item.path == sym::doc => {
|
||||||
if let Some(value) = normal.item.value_str()
|
normal.item.value_str().map(|s| (s, CommentKind::Line))
|
||||||
&& let Some(value_span) = normal.item.value_span()
|
|
||||||
{
|
|
||||||
Some((value, DocFragmentKind::Raw(value_span)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
@ -235,34 +205,6 @@ impl AttributeExt for Attribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deprecation_note(&self) -> Option<Ident> {
|
|
||||||
match &self.kind {
|
|
||||||
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
|
|
||||||
let meta = &normal.item;
|
|
||||||
|
|
||||||
// #[deprecated = "..."]
|
|
||||||
if let Some(s) = meta.value_str() {
|
|
||||||
return Some(Ident { name: s, span: meta.span() });
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[deprecated(note = "...")]
|
|
||||||
if let Some(list) = meta.meta_item_list() {
|
|
||||||
for nested in list {
|
|
||||||
if let Some(mi) = nested.meta_item()
|
|
||||||
&& mi.path == sym::note
|
|
||||||
&& let Some(s) = mi.value_str()
|
|
||||||
{
|
|
||||||
return Some(Ident { name: s, span: mi.span });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
|
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
AttrKind::DocComment(..) => Some(self.style),
|
AttrKind::DocComment(..) => Some(self.style),
|
||||||
|
|
@ -278,24 +220,6 @@ impl AttributeExt for Attribute {
|
||||||
fn is_automatically_derived_attr(&self) -> bool {
|
fn is_automatically_derived_attr(&self) -> bool {
|
||||||
self.has_name(sym::automatically_derived)
|
self.has_name(sym::automatically_derived)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_doc_hidden(&self) -> bool {
|
|
||||||
self.has_name(sym::doc)
|
|
||||||
&& self.meta_item_list().is_some_and(|l| list_contains_name(&l, sym::hidden))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_doc_keyword_or_attribute(&self) -> bool {
|
|
||||||
if self.has_name(sym::doc)
|
|
||||||
&& let Some(items) = self.meta_item_list()
|
|
||||||
{
|
|
||||||
for item in items {
|
|
||||||
if item.has_name(sym::keyword) || item.has_name(sym::attribute) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attribute {
|
impl Attribute {
|
||||||
|
|
@ -305,7 +229,6 @@ impl Attribute {
|
||||||
|
|
||||||
pub fn may_have_doc_links(&self) -> bool {
|
pub fn may_have_doc_links(&self) -> bool {
|
||||||
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|
||||||
|| self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts the MetaItem from inside this Attribute.
|
/// Extracts the MetaItem from inside this Attribute.
|
||||||
|
|
@ -345,7 +268,7 @@ impl AttrItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||||
match &self.args.unparsed_ref()? {
|
match &self.args {
|
||||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||||
MetaItemKind::list_from_tokens(args.tokens.clone())
|
MetaItemKind::list_from_tokens(args.tokens.clone())
|
||||||
}
|
}
|
||||||
|
|
@ -366,7 +289,7 @@ impl AttrItem {
|
||||||
/// #[attr("value")]
|
/// #[attr("value")]
|
||||||
/// ```
|
/// ```
|
||||||
fn value_str(&self) -> Option<Symbol> {
|
fn value_str(&self) -> Option<Symbol> {
|
||||||
match &self.args.unparsed_ref()? {
|
match &self.args {
|
||||||
AttrArgs::Eq { expr, .. } => match expr.kind {
|
AttrArgs::Eq { expr, .. } => match expr.kind {
|
||||||
ExprKind::Lit(token_lit) => {
|
ExprKind::Lit(token_lit) => {
|
||||||
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
|
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
|
||||||
|
|
@ -377,25 +300,6 @@ impl AttrItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the span in:
|
|
||||||
///
|
|
||||||
/// ```text
|
|
||||||
/// #[attribute = "value"]
|
|
||||||
/// ^^^^^^^
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// It returns `None` in any other cases like:
|
|
||||||
///
|
|
||||||
/// ```text
|
|
||||||
/// #[attr("value")]
|
|
||||||
/// ```
|
|
||||||
fn value_span(&self) -> Option<Span> {
|
|
||||||
match &self.args.unparsed_ref()? {
|
|
||||||
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
|
||||||
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn meta(&self, span: Span) -> Option<MetaItem> {
|
pub fn meta(&self, span: Span) -> Option<MetaItem> {
|
||||||
Some(MetaItem {
|
Some(MetaItem {
|
||||||
unsafety: Safety::Default,
|
unsafety: Safety::Default,
|
||||||
|
|
@ -406,7 +310,7 @@ impl AttrItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn meta_kind(&self) -> Option<MetaItemKind> {
|
pub fn meta_kind(&self) -> Option<MetaItemKind> {
|
||||||
MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
|
MetaItemKind::from_attr_args(&self.args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -498,17 +402,20 @@ impl MetaItem {
|
||||||
thin_vec![PathSegment::path_root(span)]
|
thin_vec![PathSegment::path_root(span)]
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
|
if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
|
||||||
iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
|
iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
|
||||||
else {
|
{
|
||||||
|
segments.push(PathSegment::from_ident(Ident::new(name, span)));
|
||||||
|
} else {
|
||||||
return None;
|
return None;
|
||||||
};
|
}
|
||||||
segments.push(PathSegment::from_ident(Ident::new(name, span)));
|
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
|
||||||
let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
|
iter.peek()
|
||||||
else {
|
{
|
||||||
|
iter.next();
|
||||||
|
} else {
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
iter.next();
|
|
||||||
}
|
}
|
||||||
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
|
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
|
||||||
Path { span, segments, tokens: None }
|
Path { span, segments, tokens: None }
|
||||||
|
|
@ -741,13 +648,7 @@ fn mk_attr(
|
||||||
args: AttrArgs,
|
args: AttrArgs,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Attribute {
|
) -> Attribute {
|
||||||
mk_attr_from_item(
|
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
|
||||||
g,
|
|
||||||
AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
|
|
||||||
None,
|
|
||||||
style,
|
|
||||||
span,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mk_attr_from_item(
|
pub fn mk_attr_from_item(
|
||||||
|
|
@ -851,7 +752,9 @@ pub trait AttributeExt: Debug {
|
||||||
|
|
||||||
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
|
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
|
||||||
/// return the name of the attribute; otherwise, returns `None`.
|
/// return the name of the attribute; otherwise, returns `None`.
|
||||||
fn name(&self) -> Option<Symbol>;
|
fn name(&self) -> Option<Symbol> {
|
||||||
|
self.ident().map(|ident| ident.name)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the meta item list, `#[attr(meta item list)]`
|
/// Get the meta item list, `#[attr(meta item list)]`
|
||||||
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
|
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
|
||||||
|
|
@ -862,6 +765,9 @@ pub trait AttributeExt: Debug {
|
||||||
/// Gets the span of the value literal, as string, when using `#[attr = value]`
|
/// Gets the span of the value literal, as string, when using `#[attr = value]`
|
||||||
fn value_span(&self) -> Option<Span>;
|
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.
|
/// Checks whether the path of this attribute matches the name.
|
||||||
///
|
///
|
||||||
/// Matches one segment of the path to each element in `name`
|
/// Matches one segment of the path to each element in `name`
|
||||||
|
|
@ -874,7 +780,7 @@ pub trait AttributeExt: Debug {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_name(&self, name: Symbol) -> bool {
|
fn has_name(&self, name: Symbol) -> bool {
|
||||||
self.name().map(|x| x == name).unwrap_or(false)
|
self.ident().map(|x| x.name == name).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -888,13 +794,13 @@ pub trait AttributeExt: Debug {
|
||||||
fn is_word(&self) -> bool;
|
fn is_word(&self) -> bool;
|
||||||
|
|
||||||
fn path(&self) -> SmallVec<[Symbol; 1]> {
|
fn path(&self) -> SmallVec<[Symbol; 1]> {
|
||||||
self.symbol_path().unwrap_or(smallvec![sym::doc])
|
self.ident_path()
|
||||||
|
.map(|i| i.into_iter().map(|i| i.name).collect())
|
||||||
|
.unwrap_or(smallvec![sym::doc])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_span(&self) -> Option<Span>;
|
|
||||||
|
|
||||||
/// Returns None for doc comments
|
/// Returns None for doc comments
|
||||||
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
|
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
|
||||||
|
|
||||||
/// Returns the documentation if this is a doc comment or a sugared doc comment.
|
/// Returns the documentation if this is a doc comment or a sugared doc comment.
|
||||||
/// * `///doc` returns `Some("doc")`.
|
/// * `///doc` returns `Some("doc")`.
|
||||||
|
|
@ -902,11 +808,6 @@ pub trait AttributeExt: Debug {
|
||||||
/// * `#[doc(...)]` returns `None`.
|
/// * `#[doc(...)]` returns `None`.
|
||||||
fn doc_str(&self) -> Option<Symbol>;
|
fn doc_str(&self) -> Option<Symbol>;
|
||||||
|
|
||||||
/// Returns the deprecation note if this is deprecation attribute.
|
|
||||||
/// * `#[deprecated = "note"]` returns `Some("note")`.
|
|
||||||
/// * `#[deprecated(note = "note", ...)]` returns `Some("note")`.
|
|
||||||
fn deprecation_note(&self) -> Option<Ident>;
|
|
||||||
|
|
||||||
fn is_proc_macro_attr(&self) -> bool {
|
fn is_proc_macro_attr(&self) -> bool {
|
||||||
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
|
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -919,7 +820,7 @@ pub trait AttributeExt: Debug {
|
||||||
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
|
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
|
||||||
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
|
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
|
||||||
/// * `#[doc(...)]` returns `None`.
|
/// * `#[doc(...)]` returns `None`.
|
||||||
fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)>;
|
fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>;
|
||||||
|
|
||||||
/// Returns outer or inner if this is a doc attribute or a sugared doc
|
/// Returns outer or inner if this is a doc attribute or a sugared doc
|
||||||
/// comment, otherwise None.
|
/// comment, otherwise None.
|
||||||
|
|
@ -929,12 +830,6 @@ pub trait AttributeExt: Debug {
|
||||||
/// commented module (for inner doc) vs within its parent module (for outer
|
/// commented module (for inner doc) vs within its parent module (for outer
|
||||||
/// doc).
|
/// doc).
|
||||||
fn doc_resolution_scope(&self) -> Option<AttrStyle>;
|
fn doc_resolution_scope(&self) -> Option<AttrStyle>;
|
||||||
|
|
||||||
/// Returns `true` if this attribute contains `doc(hidden)`.
|
|
||||||
fn is_doc_hidden(&self) -> bool;
|
|
||||||
|
|
||||||
/// Returns `true` is this attribute contains `doc(keyword)` or `doc(attribute)`.
|
|
||||||
fn is_doc_keyword_or_attribute(&self) -> bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(fn_delegation): use function delegation instead of manually forwarding
|
// FIXME(fn_delegation): use function delegation instead of manually forwarding
|
||||||
|
|
@ -960,6 +855,10 @@ impl Attribute {
|
||||||
AttributeExt::value_span(self)
|
AttributeExt::value_span(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ident(&self) -> Option<Ident> {
|
||||||
|
AttributeExt::ident(self)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn path_matches(&self, name: &[Symbol]) -> bool {
|
pub fn path_matches(&self, name: &[Symbol]) -> bool {
|
||||||
AttributeExt::path_matches(self, name)
|
AttributeExt::path_matches(self, name)
|
||||||
}
|
}
|
||||||
|
|
@ -991,6 +890,10 @@ impl Attribute {
|
||||||
AttributeExt::path(self)
|
AttributeExt::path(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
|
||||||
|
AttributeExt::ident_path(self)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn doc_str(&self) -> Option<Symbol> {
|
pub fn doc_str(&self) -> Option<Symbol> {
|
||||||
AttributeExt::doc_str(self)
|
AttributeExt::doc_str(self)
|
||||||
}
|
}
|
||||||
|
|
@ -999,7 +902,7 @@ impl Attribute {
|
||||||
AttributeExt::is_proc_macro_attr(self)
|
AttributeExt::is_proc_macro_attr(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
|
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
|
||||||
AttributeExt::doc_str_and_fragment_kind(self)
|
AttributeExt::doc_str_and_comment_kind(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
use std::fmt::{self, Display};
|
|
||||||
use std::sync::OnceLock;
|
|
||||||
|
|
||||||
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, current_rustc_version};
|
|
||||||
|
|
||||||
#[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
#[derive(HashStable_Generic)]
|
|
||||||
pub struct RustcVersion {
|
|
||||||
pub major: u16,
|
|
||||||
pub minor: u16,
|
|
||||||
pub patch: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RustcVersion {
|
|
||||||
pub const CURRENT: Self = current_rustc_version!();
|
|
||||||
pub fn current_overridable() -> Self {
|
|
||||||
*CURRENT_OVERRIDABLE.get_or_init(|| {
|
|
||||||
if let Ok(override_var) = std::env::var("RUSTC_OVERRIDE_VERSION_STRING")
|
|
||||||
&& let Some(override_) = Self::parse_str(&override_var)
|
|
||||||
{
|
|
||||||
override_
|
|
||||||
} else {
|
|
||||||
Self::CURRENT
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn parse_str(value: &str) -> Option<Self> {
|
|
||||||
// Ignore any suffixes such as "-dev" or "-nightly".
|
|
||||||
let mut components = value.split('-').next().unwrap().splitn(3, '.');
|
|
||||||
let major = components.next()?.parse().ok()?;
|
|
||||||
let minor = components.next()?.parse().ok()?;
|
|
||||||
let patch = components.next().unwrap_or("0").parse().ok()?;
|
|
||||||
Some(RustcVersion { major, minor, patch })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CURRENT_OVERRIDABLE: OnceLock<RustcVersion> = OnceLock::new();
|
|
||||||
|
|
||||||
impl Display for RustcVersion {
|
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
||||||
|
#![feature(array_windows)]
|
||||||
#![feature(associated_type_defaults)]
|
#![feature(associated_type_defaults)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
|
|
|
||||||
|
|
@ -16,37 +16,13 @@ use rustc_span::{Ident, Symbol};
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
use crate::util::case::Case;
|
use crate::util::case::Case;
|
||||||
|
|
||||||
/// Represents the kind of doc comment it is, ie `///` or `#[doc = ""]`.
|
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
|
|
||||||
pub enum DocFragmentKind {
|
|
||||||
/// A sugared doc comment: `///` or `//!` or `/**` or `/*!`.
|
|
||||||
Sugared(CommentKind),
|
|
||||||
/// A "raw" doc comment: `#[doc = ""]`. The `Span` represents the string literal.
|
|
||||||
Raw(Span),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DocFragmentKind {
|
|
||||||
pub fn is_sugared(self) -> bool {
|
|
||||||
matches!(self, Self::Sugared(_))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If it is `Sugared`, it will return its associated `CommentKind`, otherwise it will return
|
|
||||||
/// `CommentKind::Line`.
|
|
||||||
pub fn comment_kind(self) -> CommentKind {
|
|
||||||
match self {
|
|
||||||
Self::Sugared(kind) => kind,
|
|
||||||
Self::Raw(_) => CommentKind::Line,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
|
||||||
pub enum CommentKind {
|
pub enum CommentKind {
|
||||||
Line,
|
Line,
|
||||||
Block,
|
Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
|
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||||
pub enum InvisibleOrigin {
|
pub enum InvisibleOrigin {
|
||||||
// From the expansion of a metavariable in a declarative macro.
|
// From the expansion of a metavariable in a declarative macro.
|
||||||
MetaVar(MetaVarKind),
|
MetaVar(MetaVarKind),
|
||||||
|
|
@ -123,7 +99,7 @@ impl fmt::Display for MetaVarKind {
|
||||||
/// Describes how a sequence of token trees is delimited.
|
/// Describes how a sequence of token trees is delimited.
|
||||||
/// Cannot use `proc_macro::Delimiter` directly because this
|
/// Cannot use `proc_macro::Delimiter` directly because this
|
||||||
/// structure should implement some additional traits.
|
/// structure should implement some additional traits.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||||
pub enum Delimiter {
|
pub enum Delimiter {
|
||||||
/// `( ... )`
|
/// `( ... )`
|
||||||
Parenthesis,
|
Parenthesis,
|
||||||
|
|
@ -186,7 +162,7 @@ impl Delimiter {
|
||||||
// type. This means that float literals like `1f32` are classified by this type
|
// type. This means that float literals like `1f32` are classified by this type
|
||||||
// as `Int`. Only upon conversion to `ast::LitKind` will such a literal be
|
// as `Int`. Only upon conversion to `ast::LitKind` will such a literal be
|
||||||
// given the `Float` kind.
|
// given the `Float` kind.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
pub enum LitKind {
|
pub enum LitKind {
|
||||||
Bool, // AST only, must never appear in a `Token`
|
Bool, // AST only, must never appear in a `Token`
|
||||||
Byte,
|
Byte,
|
||||||
|
|
@ -203,7 +179,7 @@ pub enum LitKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A literal token.
|
/// A literal token.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
pub struct Lit {
|
pub struct Lit {
|
||||||
pub kind: LitKind,
|
pub kind: LitKind,
|
||||||
pub symbol: Symbol,
|
pub symbol: Symbol,
|
||||||
|
|
@ -349,7 +325,7 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
|
||||||
.contains(&name)
|
.contains(&name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy, Clone, HashStable_Generic)]
|
#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)]
|
||||||
pub enum IdentIsRaw {
|
pub enum IdentIsRaw {
|
||||||
No,
|
No,
|
||||||
Yes,
|
Yes,
|
||||||
|
|
@ -376,7 +352,7 @@ impl From<bool> for IdentIsRaw {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
pub enum TokenKind {
|
pub enum TokenKind {
|
||||||
/* Expression-operator symbols. */
|
/* Expression-operator symbols. */
|
||||||
/// `=`
|
/// `=`
|
||||||
|
|
@ -526,7 +502,7 @@ pub enum TokenKind {
|
||||||
Eof,
|
Eof,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub kind: TokenKind,
|
pub kind: TokenKind,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -625,12 +601,12 @@ impl TokenKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
pub const fn new(kind: TokenKind, span: Span) -> Self {
|
pub fn new(kind: TokenKind, span: Span) -> Self {
|
||||||
Token { kind, span }
|
Token { kind, span }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Some token that will be thrown away later.
|
/// Some token that will be thrown away later.
|
||||||
pub const fn dummy() -> Self {
|
pub fn dummy() -> Self {
|
||||||
Token::new(TokenKind::Question, DUMMY_SP)
|
Token::new(TokenKind::Question, DUMMY_SP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
//! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens.
|
//! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::hash::Hash;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{cmp, fmt, iter, mem};
|
use std::{cmp, fmt, iter, mem};
|
||||||
|
|
@ -23,7 +22,7 @@ use crate::token::{self, Delimiter, Token, TokenKind};
|
||||||
use crate::{AttrVec, Attribute};
|
use crate::{AttrVec, Attribute};
|
||||||
|
|
||||||
/// Part of a `TokenStream`.
|
/// Part of a `TokenStream`.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||||
pub enum TokenTree {
|
pub enum TokenTree {
|
||||||
/// A single token. Should never be `OpenDelim` or `CloseDelim`, because
|
/// A single token. Should never be `OpenDelim` or `CloseDelim`, because
|
||||||
/// delimiters are implicitly represented by `Delimited`.
|
/// delimiters are implicitly represented by `Delimited`.
|
||||||
|
|
@ -354,13 +353,7 @@ fn make_attr_token_stream(
|
||||||
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
|
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
|
||||||
));
|
));
|
||||||
} else if let Some(delim) = kind.close_delim() {
|
} else if let Some(delim) = kind.close_delim() {
|
||||||
// If there's no matching opening delimiter, the token stream is malformed,
|
let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
|
||||||
// likely due to a improper delimiter positions in the source code.
|
|
||||||
// It's not delimiter mismatch, and lexer can not detect it, so we just ignore it here.
|
|
||||||
let Some(frame) = stack_rest.pop() else {
|
|
||||||
return AttrTokenStream::new(stack_top.inner);
|
|
||||||
};
|
|
||||||
let frame_data = mem::replace(&mut stack_top, frame);
|
|
||||||
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
|
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
open_delim.eq_ignoring_invisible_origin(&delim),
|
open_delim.eq_ignoring_invisible_origin(&delim),
|
||||||
|
|
@ -545,7 +538,7 @@ pub struct AttrsTarget {
|
||||||
/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to
|
/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to
|
||||||
/// guide pretty-printing, which is where the `JointHidden` value (which isn't
|
/// guide pretty-printing, which is where the `JointHidden` value (which isn't
|
||||||
/// part of `proc_macro::Spacing`) comes in useful.
|
/// part of `proc_macro::Spacing`) comes in useful.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||||
pub enum Spacing {
|
pub enum Spacing {
|
||||||
/// The token cannot join with the following token to form a compound
|
/// The token cannot join with the following token to form a compound
|
||||||
/// token.
|
/// token.
|
||||||
|
|
@ -602,7 +595,7 @@ pub enum Spacing {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
|
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Encodable, Decodable)]
|
#[derive(Clone, Debug, Default, Encodable, Decodable)]
|
||||||
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
|
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
|
||||||
|
|
||||||
impl TokenStream {
|
impl TokenStream {
|
||||||
|
|
@ -818,6 +811,14 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq<TokenStream> for TokenStream {
|
||||||
|
fn eq(&self, other: &TokenStream) -> bool {
|
||||||
|
self.iter().eq(other.iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for TokenStream {}
|
||||||
|
|
||||||
impl FromIterator<TokenTree> for TokenStream {
|
impl FromIterator<TokenTree> for TokenStream {
|
||||||
fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
|
fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
|
||||||
TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
|
TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
|
||||||
|
|
@ -969,8 +970,7 @@ impl TokenCursor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||||
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
|
|
||||||
pub struct DelimSpan {
|
pub struct DelimSpan {
|
||||||
pub open: Span,
|
pub open: Span,
|
||||||
pub close: Span,
|
pub close: Span,
|
||||||
|
|
@ -994,7 +994,7 @@ impl DelimSpan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||||
pub struct DelimSpacing {
|
pub struct DelimSpacing {
|
||||||
pub open: Spacing,
|
pub open: Spacing,
|
||||||
pub close: Spacing,
|
pub close: Spacing,
|
||||||
|
|
|
||||||
|
|
@ -366,7 +366,6 @@ macro_rules! common_visitor_and_walkers {
|
||||||
crate::token::LitKind,
|
crate::token::LitKind,
|
||||||
crate::tokenstream::LazyAttrTokenStream,
|
crate::tokenstream::LazyAttrTokenStream,
|
||||||
crate::tokenstream::TokenStream,
|
crate::tokenstream::TokenStream,
|
||||||
EarlyParsedAttribute,
|
|
||||||
Movability,
|
Movability,
|
||||||
Mutability,
|
Mutability,
|
||||||
Pinnedness,
|
Pinnedness,
|
||||||
|
|
@ -394,7 +393,6 @@ macro_rules! common_visitor_and_walkers {
|
||||||
ThinVec<Pat>,
|
ThinVec<Pat>,
|
||||||
ThinVec<Box<Ty>>,
|
ThinVec<Box<Ty>>,
|
||||||
ThinVec<TyPat>,
|
ThinVec<TyPat>,
|
||||||
ThinVec<EiiImpl>,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable`
|
// This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable`
|
||||||
|
|
@ -417,7 +415,6 @@ macro_rules! common_visitor_and_walkers {
|
||||||
UnsafeBinderCastKind,
|
UnsafeBinderCastKind,
|
||||||
BinOpKind,
|
BinOpKind,
|
||||||
BlockCheckMode,
|
BlockCheckMode,
|
||||||
MgcaDisambiguation,
|
|
||||||
BorrowKind,
|
BorrowKind,
|
||||||
BoundAsyncness,
|
BoundAsyncness,
|
||||||
BoundConstness,
|
BoundConstness,
|
||||||
|
|
@ -425,9 +422,8 @@ macro_rules! common_visitor_and_walkers {
|
||||||
ByRef,
|
ByRef,
|
||||||
Closure,
|
Closure,
|
||||||
Const,
|
Const,
|
||||||
ConstBlockItem,
|
|
||||||
ConstItem,
|
ConstItem,
|
||||||
ConstItemRhsKind,
|
ConstItemRhs,
|
||||||
Defaultness,
|
Defaultness,
|
||||||
Delegation,
|
Delegation,
|
||||||
DelegationMac,
|
DelegationMac,
|
||||||
|
|
@ -459,7 +455,6 @@ macro_rules! common_visitor_and_walkers {
|
||||||
ModSpans,
|
ModSpans,
|
||||||
MutTy,
|
MutTy,
|
||||||
NormalAttr,
|
NormalAttr,
|
||||||
AttrItemKind,
|
|
||||||
Parens,
|
Parens,
|
||||||
ParenthesizedArgs,
|
ParenthesizedArgs,
|
||||||
PatFieldsRest,
|
PatFieldsRest,
|
||||||
|
|
@ -490,8 +485,6 @@ macro_rules! common_visitor_and_walkers {
|
||||||
WhereEqPredicate,
|
WhereEqPredicate,
|
||||||
WhereRegionPredicate,
|
WhereRegionPredicate,
|
||||||
YieldKind,
|
YieldKind,
|
||||||
EiiDecl,
|
|
||||||
EiiImpl,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Each method of this trait is a hook to be potentially
|
/// Each method of this trait is a hook to be potentially
|
||||||
|
|
@ -826,8 +819,6 @@ macro_rules! common_visitor_and_walkers {
|
||||||
visit_visitable!($($mut)? vis, use_tree),
|
visit_visitable!($($mut)? vis, use_tree),
|
||||||
ItemKind::Static(item) =>
|
ItemKind::Static(item) =>
|
||||||
visit_visitable!($($mut)? vis, item),
|
visit_visitable!($($mut)? vis, item),
|
||||||
ItemKind::ConstBlock(item) =>
|
|
||||||
visit_visitable!($($mut)? vis, item),
|
|
||||||
ItemKind::Const(item) =>
|
ItemKind::Const(item) =>
|
||||||
visit_visitable!($($mut)? vis, item),
|
visit_visitable!($($mut)? vis, item),
|
||||||
ItemKind::Mod(safety, ident, mod_kind) =>
|
ItemKind::Mod(safety, ident, mod_kind) =>
|
||||||
|
|
@ -928,13 +919,13 @@ macro_rules! common_visitor_and_walkers {
|
||||||
_ctxt,
|
_ctxt,
|
||||||
// Visibility is visited as a part of the item.
|
// Visibility is visited as a part of the item.
|
||||||
_vis,
|
_vis,
|
||||||
Fn { defaultness, ident, sig, generics, contract, body, define_opaque, eii_impls },
|
Fn { defaultness, ident, sig, generics, contract, body, define_opaque },
|
||||||
) => {
|
) => {
|
||||||
let FnSig { header, decl, span } = sig;
|
let FnSig { header, decl, span } = sig;
|
||||||
visit_visitable!($($mut)? vis,
|
visit_visitable!($($mut)? vis,
|
||||||
defaultness, ident, header, generics, decl,
|
defaultness, ident, header, generics, decl,
|
||||||
contract, body, span, define_opaque, eii_impls
|
contract, body, span, define_opaque
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
FnKind::Closure(binder, coroutine_kind, decl, body) =>
|
FnKind::Closure(binder, coroutine_kind, decl, body) =>
|
||||||
visit_visitable!($($mut)? vis, binder, coroutine_kind, decl, body),
|
visit_visitable!($($mut)? vis, binder, coroutine_kind, decl, body),
|
||||||
|
|
@ -1057,8 +1048,8 @@ macro_rules! common_visitor_and_walkers {
|
||||||
visit_visitable!($($mut)? vis, kind),
|
visit_visitable!($($mut)? vis, kind),
|
||||||
ExprKind::Try(subexpression) =>
|
ExprKind::Try(subexpression) =>
|
||||||
visit_visitable!($($mut)? vis, subexpression),
|
visit_visitable!($($mut)? vis, subexpression),
|
||||||
ExprKind::TryBlock(body, optional_type) =>
|
ExprKind::TryBlock(body) =>
|
||||||
visit_visitable!($($mut)? vis, body, optional_type),
|
visit_visitable!($($mut)? vis, body),
|
||||||
ExprKind::Lit(token) =>
|
ExprKind::Lit(token) =>
|
||||||
visit_visitable!($($mut)? vis, token),
|
visit_visitable!($($mut)? vis, token),
|
||||||
ExprKind::IncludedBytes(bytes) =>
|
ExprKind::IncludedBytes(bytes) =>
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
|
|
|
||||||
188
compiler/rustc_ast_lowering/messages.ftl
Normal file
188
compiler/rustc_ast_lowering/messages.ftl
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
ast_lowering_abi_specified_multiple_times =
|
||||||
|
`{$prev_name}` ABI specified multiple times
|
||||||
|
.label = previously specified here
|
||||||
|
.note = these ABIs are equivalent on the current target
|
||||||
|
|
||||||
|
ast_lowering_arbitrary_expression_in_pattern =
|
||||||
|
arbitrary expressions aren't allowed in patterns
|
||||||
|
.pattern_from_macro_note = the `expr` fragment specifier forces the metavariable's content to be an expression
|
||||||
|
|
||||||
|
ast_lowering_argument = argument
|
||||||
|
|
||||||
|
ast_lowering_assoc_ty_binding_in_dyn =
|
||||||
|
associated type bounds are not allowed in `dyn` types
|
||||||
|
.suggestion = use `impl Trait` to introduce a type instead
|
||||||
|
|
||||||
|
ast_lowering_assoc_ty_parentheses =
|
||||||
|
parenthesized generic arguments cannot be used in associated type constraints
|
||||||
|
|
||||||
|
ast_lowering_async_bound_not_on_trait =
|
||||||
|
`async` bound modifier only allowed on trait, not `{$descr}`
|
||||||
|
|
||||||
|
ast_lowering_async_bound_only_for_fn_traits =
|
||||||
|
`async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits
|
||||||
|
|
||||||
|
ast_lowering_async_coroutines_not_supported =
|
||||||
|
`async` coroutines are not yet supported
|
||||||
|
|
||||||
|
ast_lowering_att_syntax_only_x86 =
|
||||||
|
the `att_syntax` option is only supported on x86
|
||||||
|
|
||||||
|
ast_lowering_await_only_in_async_fn_and_blocks =
|
||||||
|
`await` is only allowed inside `async` functions and blocks
|
||||||
|
.label = only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
|
ast_lowering_bad_return_type_notation_inputs =
|
||||||
|
argument types not allowed with return type notation
|
||||||
|
.suggestion = remove the input types
|
||||||
|
|
||||||
|
ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..`
|
||||||
|
.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
|
||||||
|
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_clobber_abi_not_supported =
|
||||||
|
`clobber_abi` is not supported on this target
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ast_lowering_extra_double_dot =
|
||||||
|
`..` can only be used once per {$ctx} pattern
|
||||||
|
.label = can only be used once per {$ctx} pattern
|
||||||
|
|
||||||
|
ast_lowering_functional_record_update_destructuring_assignment =
|
||||||
|
functional record updates are not allowed in destructuring assignments
|
||||||
|
.suggestion = consider removing the trailing pattern
|
||||||
|
|
||||||
|
ast_lowering_generic_param_default_in_binder =
|
||||||
|
defaults for generic parameters are not allowed in `for<...>` binders
|
||||||
|
|
||||||
|
ast_lowering_generic_type_with_parentheses =
|
||||||
|
parenthesized type parameters may only be used with a `Fn` trait
|
||||||
|
.label = only `Fn` traits may use parentheses
|
||||||
|
|
||||||
|
ast_lowering_inclusive_range_with_no_end = inclusive range with no end
|
||||||
|
|
||||||
|
ast_lowering_inline_asm_unsupported_target =
|
||||||
|
inline assembly is unsupported on this target
|
||||||
|
|
||||||
|
ast_lowering_invalid_abi =
|
||||||
|
invalid ABI: found `{$abi}`
|
||||||
|
.label = invalid ABI
|
||||||
|
.note = invoke `{$command}` for a full list of supported calling conventions
|
||||||
|
|
||||||
|
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 = there's a similarly named valid ABI `{$suggestion}`
|
||||||
|
|
||||||
|
ast_lowering_invalid_asm_template_modifier_const =
|
||||||
|
asm template modifiers are not allowed for `const` arguments
|
||||||
|
|
||||||
|
ast_lowering_invalid_asm_template_modifier_label =
|
||||||
|
asm template modifiers are not allowed for `label` arguments
|
||||||
|
|
||||||
|
ast_lowering_invalid_asm_template_modifier_reg_class =
|
||||||
|
invalid asm template modifier for this register 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}`: 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
|
||||||
|
.suggestion = add a body after the pattern
|
||||||
|
|
||||||
|
ast_lowering_misplaced_double_dot =
|
||||||
|
`..` patterns are not allowed here
|
||||||
|
.note = only allowed in tuple, tuple struct, and slice patterns
|
||||||
|
|
||||||
|
ast_lowering_misplaced_impl_trait =
|
||||||
|
`impl Trait` is not allowed in {$position}
|
||||||
|
.note = `impl Trait` is only allowed in arguments and return types of functions and methods
|
||||||
|
|
||||||
|
ast_lowering_never_pattern_with_body =
|
||||||
|
a never pattern is always unreachable
|
||||||
|
.label = this will never be executed
|
||||||
|
.suggestion = remove this expression
|
||||||
|
|
||||||
|
ast_lowering_never_pattern_with_guard =
|
||||||
|
a guard on a never pattern will never be run
|
||||||
|
.suggestion = remove this guard
|
||||||
|
|
||||||
|
ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
|
||||||
|
|
||||||
|
ast_lowering_previously_used_here = previously used here
|
||||||
|
|
||||||
|
ast_lowering_register1 = register `{$reg1_name}`
|
||||||
|
|
||||||
|
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}`
|
||||||
|
.help = use `lateout` instead of `out` to avoid conflict
|
||||||
|
|
||||||
|
ast_lowering_remove_parentheses = remove these parentheses
|
||||||
|
|
||||||
|
ast_lowering_sub_tuple_binding =
|
||||||
|
`{$ident_name} @` is not allowed in a {$ctx}
|
||||||
|
.label = this is only allowed in slice patterns
|
||||||
|
.help = remove this and bind each tuple field independently
|
||||||
|
|
||||||
|
ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields
|
||||||
|
|
||||||
|
ast_lowering_support_modifiers =
|
||||||
|
the `{$class_name}` register class supports the following template modifiers: {$modifiers}
|
||||||
|
|
||||||
|
ast_lowering_template_modifier = template modifier
|
||||||
|
|
||||||
|
ast_lowering_this_not_async = this is not `async`
|
||||||
|
|
||||||
|
ast_lowering_underscore_expr_lhs_assign =
|
||||||
|
in expressions, `_` can only be used on the left-hand side of an assignment
|
||||||
|
.label = `_` not allowed here
|
||||||
|
|
||||||
|
ast_lowering_union_default_field_values = unions cannot have default field values
|
||||||
|
|
||||||
|
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
|
||||||
|
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
|
||||||
|
|
||||||
|
ast_lowering_yield = yield syntax is experimental
|
||||||
|
ast_lowering_yield_in_closure =
|
||||||
|
`yield` can only be used in `#[coroutine]` closures, or `gen` blocks
|
||||||
|
.suggestion = use `#[coroutine]` to make this closure a coroutine
|
||||||
|
|
@ -3,7 +3,6 @@ use std::fmt::Write;
|
||||||
|
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||||
use rustc_errors::msg;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
|
|
@ -20,7 +19,8 @@ use super::errors::{
|
||||||
RegisterConflict,
|
RegisterConflict,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt,
|
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
|
||||||
|
ResolverAstLoweringExt, fluent_generated as fluent,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
@ -51,23 +51,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
| asm::InlineAsmArch::LoongArch32
|
| asm::InlineAsmArch::LoongArch32
|
||||||
| asm::InlineAsmArch::LoongArch64
|
| asm::InlineAsmArch::LoongArch64
|
||||||
| asm::InlineAsmArch::S390x
|
| asm::InlineAsmArch::S390x
|
||||||
| asm::InlineAsmArch::PowerPC
|
|
||||||
| asm::InlineAsmArch::PowerPC64
|
|
||||||
);
|
);
|
||||||
if !is_stable
|
if !is_stable && !self.tcx.features().asm_experimental_arch() {
|
||||||
&& !self.tcx.features().asm_experimental_arch()
|
|
||||||
&& sp
|
|
||||||
.ctxt()
|
|
||||||
.outer_expn_data()
|
|
||||||
.allow_internal_unstable
|
|
||||||
.filter(|features| features.contains(&sym::asm_experimental_arch))
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
feature_err(
|
feature_err(
|
||||||
&self.tcx.sess,
|
&self.tcx.sess,
|
||||||
sym::asm_experimental_arch,
|
sym::asm_experimental_arch,
|
||||||
sp,
|
sp,
|
||||||
msg!("inline assembly is not stable yet on this architecture"),
|
fluent::ast_lowering_unstable_inline_assembly,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +74,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
&self.tcx.sess,
|
&self.tcx.sess,
|
||||||
sym::asm_unwind,
|
sym::asm_unwind,
|
||||||
sp,
|
sp,
|
||||||
msg!("the `may_unwind` option is unstable"),
|
fluent::ast_lowering_unstable_may_unwind,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -499,7 +489,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
sess,
|
sess,
|
||||||
sym::asm_goto_with_outputs,
|
sym::asm_goto_with_outputs,
|
||||||
*op_sp,
|
*op_sp,
|
||||||
msg!("using both label and output operands for inline assembly is unstable"),
|
fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// Let statements are allowed to have impl trait in bindings.
|
// Let statements are allowed to have impl trait in bindings.
|
||||||
let super_ = l.super_.map(|span| self.lower_span(span));
|
let super_ = l.super_.map(|span| self.lower_span(span));
|
||||||
let ty = l.ty.as_ref().map(|t| {
|
let ty = l.ty.as_ref().map(|t| {
|
||||||
self.lower_ty_alloc(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||||
});
|
});
|
||||||
let init = l.kind.init().map(|init| self.lower_expr(init));
|
let init = l.kind.init().map(|init| self.lower_expr(init));
|
||||||
let hir_id = self.lower_node_id(l.id);
|
let hir_id = self.lower_node_id(l.id);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// The order in which things are lowered is important! I.e to
|
// The order in which things are lowered is important! I.e to
|
||||||
// refer to variables in contract_decls from postcond/precond,
|
// refer to variables in contract_decls from postcond/precond,
|
||||||
// we must lower it first!
|
// we must lower it first!
|
||||||
let contract_decls = self.lower_decls(contract);
|
let contract_decls = self.lower_stmts(&contract.declarations).0;
|
||||||
|
|
||||||
match (&contract.requires, &contract.ensures) {
|
match (&contract.requires, &contract.ensures) {
|
||||||
(Some(req), Some(ens)) => {
|
(Some(req), Some(ens)) => {
|
||||||
|
|
@ -124,18 +124,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_decls(&mut self, contract: &rustc_ast::FnContract) -> &'hir [rustc_hir::Stmt<'hir>] {
|
|
||||||
let (decls, decls_tail) = self.lower_stmts(&contract.declarations);
|
|
||||||
|
|
||||||
if let Some(e) = decls_tail {
|
|
||||||
// include the tail expression in the declaration statements
|
|
||||||
let tail = self.stmt_expr(e.span, *e);
|
|
||||||
self.arena.alloc_from_iter(decls.into_iter().map(|d| *d).chain([tail].into_iter()))
|
|
||||||
} else {
|
|
||||||
decls
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lower the precondition check intrinsic.
|
/// Lower the precondition check intrinsic.
|
||||||
fn lower_precond(&mut self, req: &Box<rustc_ast::Expr>) -> rustc_hir::Stmt<'hir> {
|
fn lower_precond(&mut self, req: &Box<rustc_ast::Expr>) -> rustc_hir::Stmt<'hir> {
|
||||||
let lowered_req = self.lower_expr_mut(&req);
|
let lowered_req = self.lower_expr_mut(&req);
|
||||||
|
|
|
||||||
|
|
@ -43,21 +43,15 @@ use hir::def::{DefKind, PartialRes, Res};
|
||||||
use hir::{BodyId, HirId};
|
use hir::{BodyId, HirId};
|
||||||
use rustc_abi::ExternAbi;
|
use rustc_abi::ExternAbi;
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir::Target;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs, ResolverAstLowering};
|
use rustc_middle::ty::{Asyncness, ResolverAstLowering};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::kw;
|
||||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
|
use rustc_span::{Ident, Span, Symbol};
|
||||||
use smallvec::SmallVec;
|
|
||||||
use {rustc_ast as ast, rustc_hir as hir};
|
use {rustc_ast as ast, rustc_hir as hir};
|
||||||
|
|
||||||
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
|
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
|
||||||
use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
|
|
||||||
use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
|
use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
|
||||||
|
|
||||||
pub(crate) struct DelegationResults<'hir> {
|
pub(crate) struct DelegationResults<'hir> {
|
||||||
|
|
@ -67,68 +61,6 @@ pub(crate) struct DelegationResults<'hir> {
|
||||||
pub generics: &'hir hir::Generics<'hir>,
|
pub generics: &'hir hir::Generics<'hir>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AttrAdditionInfo {
|
|
||||||
pub equals: fn(&hir::Attribute) -> bool,
|
|
||||||
pub kind: AttrAdditionKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AttrAdditionKind {
|
|
||||||
Default { factory: fn(Span) -> hir::Attribute },
|
|
||||||
Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
|
|
||||||
}
|
|
||||||
|
|
||||||
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
|
|
||||||
|
|
||||||
static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
|
|
||||||
AttrAdditionInfo {
|
|
||||||
equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })),
|
|
||||||
kind: AttrAdditionKind::Inherit {
|
|
||||||
factory: |span, original_attr| {
|
|
||||||
let reason = match original_attr {
|
|
||||||
hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason,
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
|
|
||||||
},
|
|
||||||
flag: DelegationFnSigAttrs::MUST_USE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AttrAdditionInfo {
|
|
||||||
equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))),
|
|
||||||
kind: AttrAdditionKind::Default {
|
|
||||||
factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
type DelegationIdsVec = SmallVec<[DefId; 1]>;
|
|
||||||
|
|
||||||
// As delegations can now refer to another delegation, we have a delegation path
|
|
||||||
// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
|
|
||||||
// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
|
|
||||||
struct DelegationIds {
|
|
||||||
path: DelegationIdsVec,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DelegationIds {
|
|
||||||
fn new(path: DelegationIdsVec) -> Self {
|
|
||||||
assert!(!path.is_empty());
|
|
||||||
Self { path }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Id of the first function in (non)local crate that is being reused
|
|
||||||
fn root_function_id(&self) -> DefId {
|
|
||||||
*self.path.last().expect("Ids vector can't be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Id of the first definition which is being reused,
|
|
||||||
// can be either function, in this case `root_id == delegee_id`, or other delegation
|
|
||||||
fn delegee_id(&self) -> DefId {
|
|
||||||
*self.path.first().expect("Ids vector can't be empty")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'hir> LoweringContext<'_, 'hir> {
|
impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
fn is_method(&self, def_id: DefId, span: Span) -> bool {
|
fn is_method(&self, def_id: DefId, span: Span) -> bool {
|
||||||
match self.tcx.def_kind(def_id) {
|
match self.tcx.def_kind(def_id) {
|
||||||
|
|
@ -149,50 +81,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&mut self,
|
&mut self,
|
||||||
delegation: &Delegation,
|
delegation: &Delegation,
|
||||||
item_id: NodeId,
|
item_id: NodeId,
|
||||||
|
is_in_trait_impl: bool,
|
||||||
) -> DelegationResults<'hir> {
|
) -> DelegationResults<'hir> {
|
||||||
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
||||||
|
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl);
|
||||||
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
|
match sig_id {
|
||||||
let ids = if let Some(delegation_info) =
|
Ok(sig_id) => {
|
||||||
self.resolver.delegation_infos.get(&self.local_def_id(item_id))
|
let is_method = self.is_method(sig_id, span);
|
||||||
{
|
let (param_count, c_variadic) = self.param_count(sig_id);
|
||||||
self.get_delegation_ids(delegation_info.resolution_node, span)
|
let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span);
|
||||||
} else {
|
let sig = self.lower_delegation_sig(sig_id, decl, span);
|
||||||
return self.generate_delegation_error(
|
|
||||||
self.dcx().span_delayed_bug(
|
|
||||||
span,
|
|
||||||
format!("LoweringContext: the delegation {:?} is unresolved", item_id),
|
|
||||||
),
|
|
||||||
span,
|
|
||||||
delegation,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
match ids {
|
|
||||||
Ok(ids) => {
|
|
||||||
self.add_attrs_if_needed(span, &ids);
|
|
||||||
|
|
||||||
let delegee_id = ids.delegee_id();
|
|
||||||
let root_function_id = ids.root_function_id();
|
|
||||||
|
|
||||||
// `is_method` is used to choose the name of the first parameter (`self` or `arg0`),
|
|
||||||
// if the original function is not a method (without `self`), then it can not be added
|
|
||||||
// during chain of reuses, so we use `root_function_id` here
|
|
||||||
let is_method = self.is_method(root_function_id, span);
|
|
||||||
|
|
||||||
// Here we use `root_function_id` as we can not get params information out of potential delegation reuse,
|
|
||||||
// we need a function to extract this information
|
|
||||||
let (param_count, c_variadic) = self.param_count(root_function_id);
|
|
||||||
|
|
||||||
// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
|
|
||||||
// inheritance, and we want this id to point on a delegee, not on the original
|
|
||||||
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
|
|
||||||
let decl = self.lower_delegation_decl(delegee_id, param_count, c_variadic, span);
|
|
||||||
|
|
||||||
// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
|
|
||||||
// from the root function that started delegation
|
|
||||||
let sig = self.lower_delegation_sig(root_function_id, decl, span);
|
|
||||||
|
|
||||||
let body_id = self.lower_delegation_body(delegation, is_method, param_count, span);
|
let body_id = self.lower_delegation_body(delegation, is_method, param_count, span);
|
||||||
let ident = self.lower_ident(delegation.ident);
|
let ident = self.lower_ident(delegation.ident);
|
||||||
let generics = self.lower_delegation_generics(span);
|
let generics = self.lower_delegation_generics(span);
|
||||||
|
|
@ -202,163 +100,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
|
fn get_delegation_sig_id(
|
||||||
let new_attrs =
|
|
||||||
self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
|
|
||||||
|
|
||||||
if new_attrs.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_arena_allocated_attrs = match self.attrs.get(&PARENT_ID) {
|
|
||||||
Some(existing_attrs) => self.arena.alloc_from_iter(
|
|
||||||
existing_attrs.iter().map(|a| a.clone()).chain(new_attrs.into_iter()),
|
|
||||||
),
|
|
||||||
None => self.arena.alloc_from_iter(new_attrs.into_iter()),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.attrs.insert(PARENT_ID, new_arena_allocated_attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_new_attrs(
|
|
||||||
&self,
|
&self,
|
||||||
candidate_additions: &[AttrAdditionInfo],
|
item_id: NodeId,
|
||||||
|
path_id: NodeId,
|
||||||
span: Span,
|
span: Span,
|
||||||
ids: &DelegationIds,
|
is_in_trait_impl: bool,
|
||||||
existing_attrs: Option<&&[hir::Attribute]>,
|
) -> Result<DefId, ErrorGuaranteed> {
|
||||||
) -> Vec<hir::Attribute> {
|
let sig_id = if is_in_trait_impl { item_id } else { path_id };
|
||||||
let defs_orig_attrs = ids
|
self.get_resolution_id(sig_id, span)
|
||||||
.path
|
|
||||||
.iter()
|
|
||||||
.map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
candidate_additions
|
|
||||||
.iter()
|
|
||||||
.filter_map(|addition_info| {
|
|
||||||
if let Some(existing_attrs) = existing_attrs
|
|
||||||
&& existing_attrs
|
|
||||||
.iter()
|
|
||||||
.any(|existing_attr| (addition_info.equals)(existing_attr))
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match addition_info.kind {
|
|
||||||
AttrAdditionKind::Default { factory } => Some(factory(span)),
|
|
||||||
AttrAdditionKind::Inherit { flag, factory } => {
|
|
||||||
for (def_id, orig_attrs) in &defs_orig_attrs {
|
|
||||||
let original_attr = match def_id.as_local() {
|
|
||||||
Some(local_id) => self
|
|
||||||
.get_attrs(local_id)
|
|
||||||
.flags
|
|
||||||
.contains(flag)
|
|
||||||
.then(|| {
|
|
||||||
orig_attrs
|
|
||||||
.as_ref()
|
|
||||||
.map(|attrs| {
|
|
||||||
attrs.iter().find(|base_attr| {
|
|
||||||
(addition_info.equals)(base_attr)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
})
|
|
||||||
.flatten(),
|
|
||||||
None => self
|
|
||||||
.tcx
|
|
||||||
.get_all_attrs(*def_id)
|
|
||||||
.iter()
|
|
||||||
.find(|base_attr| (addition_info.equals)(base_attr)),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(original_attr) = original_attr {
|
|
||||||
return Some(factory(span, original_attr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
|
fn get_resolution_id(&self, node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
|
||||||
if let Some(local_id) = def_id.as_local() {
|
let def_id =
|
||||||
let attrs = &self.get_attrs(local_id).to_inherit;
|
self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id());
|
||||||
|
def_id.ok_or_else(|| {
|
||||||
if !attrs.is_empty() {
|
self.tcx.dcx().span_delayed_bug(
|
||||||
return Some(AttributeParser::parse_limited_all(
|
span,
|
||||||
self.tcx.sess,
|
format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id),
|
||||||
attrs,
|
)
|
||||||
None,
|
})
|
||||||
Target::Fn,
|
|
||||||
DUMMY_SP,
|
|
||||||
DUMMY_NODE_ID,
|
|
||||||
Some(self.tcx.features()),
|
|
||||||
ShouldEmit::Nothing,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
|
|
||||||
// local_id can correspond either to a function or other delegation
|
|
||||||
if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) {
|
|
||||||
&fn_sig.attrs
|
|
||||||
} else {
|
|
||||||
&self.resolver.delegation_infos[&local_id].attrs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_delegation_ids(
|
|
||||||
&self,
|
|
||||||
mut node_id: NodeId,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<DelegationIds, ErrorGuaranteed> {
|
|
||||||
let mut visited: FxHashSet<NodeId> = Default::default();
|
|
||||||
let mut path: DelegationIdsVec = Default::default();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
visited.insert(node_id);
|
|
||||||
|
|
||||||
let Some(def_id) = self.get_resolution_id(node_id) else {
|
|
||||||
return Err(self.tcx.dcx().span_delayed_bug(
|
|
||||||
span,
|
|
||||||
format!(
|
|
||||||
"LoweringContext: couldn't resolve node {:?} in delegation item",
|
|
||||||
node_id
|
|
||||||
),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
path.push(def_id);
|
|
||||||
|
|
||||||
// If def_id is in local crate and it corresponds to another delegation
|
|
||||||
// it means that we refer to another delegation as a callee, so in order to obtain
|
|
||||||
// a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
|
|
||||||
if let Some(local_id) = def_id.as_local()
|
|
||||||
&& let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id)
|
|
||||||
{
|
|
||||||
node_id = delegation_info.resolution_node;
|
|
||||||
if visited.contains(&node_id) {
|
|
||||||
// We encountered a cycle in the resolution, or delegation callee refers to non-existent
|
|
||||||
// entity, in this case emit an error.
|
|
||||||
return Err(match visited.len() {
|
|
||||||
1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }),
|
|
||||||
_ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Ok(DelegationIds::new(path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
|
|
||||||
self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
|
fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
|
||||||
|
|
@ -372,14 +133,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function parameter count, including C variadic `...` if present.
|
// Function parameter count, including C variadic `...` if present.
|
||||||
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
|
fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) {
|
||||||
if let Some(local_sig_id) = def_id.as_local() {
|
if let Some(local_sig_id) = sig_id.as_local() {
|
||||||
|
// Map may be filled incorrectly due to recursive delegation.
|
||||||
|
// Error will be emitted later during HIR ty lowering.
|
||||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
||||||
Some(sig) => (sig.param_count, sig.c_variadic),
|
Some(sig) => (sig.param_count, sig.c_variadic),
|
||||||
None => (0, false),
|
None => (0, false),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
|
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
|
||||||
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
|
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -429,9 +192,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
|
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
|
||||||
// and here we need the hir attributes.
|
// and here we need the hir attributes.
|
||||||
let default_safety =
|
let default_safety =
|
||||||
if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
|
if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod {
|
||||||
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
|
|
||||||
{
|
|
||||||
hir::Safety::Unsafe
|
hir::Safety::Unsafe
|
||||||
} else {
|
} else {
|
||||||
hir::Safety::Safe
|
hir::Safety::Safe
|
||||||
|
|
@ -590,8 +351,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
|
delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
|
||||||
|
|
||||||
let call = if self
|
let call = if self
|
||||||
.get_resolution_id(delegation.id)
|
.get_resolution_id(delegation.id, span)
|
||||||
.map(|def_id| self.is_method(def_id, span))
|
.and_then(|def_id| Ok(self.is_method(def_id, span)))
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
&& delegation.qself.is_none()
|
&& delegation.qself.is_none()
|
||||||
&& !has_generic_args
|
&& !has_generic_args
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_span::{Ident, Span, Symbol};
|
use rustc_span::{Ident, Span, Symbol};
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("parenthesized type parameters may only be used with a `Fn` trait", code = E0214)]
|
#[diag(ast_lowering_generic_type_with_parentheses, code = E0214)]
|
||||||
pub(crate) struct GenericTypeWithParentheses {
|
pub(crate) struct GenericTypeWithParentheses {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("only `Fn` traits may use parentheses")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub sub: Option<UseAngleBrackets>,
|
pub sub: Option<UseAngleBrackets>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion("use angle brackets instead", applicability = "maybe-incorrect")]
|
#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")]
|
||||||
pub(crate) struct UseAngleBrackets {
|
pub(crate) struct UseAngleBrackets {
|
||||||
#[suggestion_part(code = "<")]
|
#[suggestion_part(code = "<")]
|
||||||
pub open_param: Span,
|
pub open_param: Span,
|
||||||
|
|
@ -23,11 +23,11 @@ pub(crate) struct UseAngleBrackets {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid ABI: found `{$abi}`", code = E0703)]
|
#[diag(ast_lowering_invalid_abi, code = E0703)]
|
||||||
#[note("invoke `{$command}` for a full list of supported calling conventions")]
|
#[note]
|
||||||
pub(crate) struct InvalidAbi {
|
pub(crate) struct InvalidAbi {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("invalid ABI")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub abi: Symbol,
|
pub abi: Symbol,
|
||||||
pub command: String,
|
pub command: String,
|
||||||
|
|
@ -36,16 +36,16 @@ pub(crate) struct InvalidAbi {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("default fields are not supported in tuple structs")]
|
#[diag(ast_lowering_default_field_in_tuple)]
|
||||||
pub(crate) struct TupleStructWithDefault {
|
pub(crate) struct TupleStructWithDefault {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("default fields are only supported on structs")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
"there's a similarly named valid ABI `{$suggestion}`",
|
ast_lowering_invalid_abi_suggestion,
|
||||||
code = "\"{suggestion}\"",
|
code = "\"{suggestion}\"",
|
||||||
applicability = "maybe-incorrect",
|
applicability = "maybe-incorrect",
|
||||||
style = "verbose"
|
style = "verbose"
|
||||||
|
|
@ -57,7 +57,7 @@ pub(crate) struct InvalidAbiSuggestion {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("parenthesized generic arguments cannot be used in associated type constraints")]
|
#[diag(ast_lowering_assoc_ty_parentheses)]
|
||||||
pub(crate) struct AssocTyParentheses {
|
pub(crate) struct AssocTyParentheses {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -67,12 +67,12 @@ pub(crate) struct AssocTyParentheses {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum AssocTyParenthesesSub {
|
pub(crate) enum AssocTyParenthesesSub {
|
||||||
#[multipart_suggestion("remove these parentheses")]
|
#[multipart_suggestion(ast_lowering_remove_parentheses)]
|
||||||
Empty {
|
Empty {
|
||||||
#[suggestion_part(code = "")]
|
#[suggestion_part(code = "")]
|
||||||
parentheses_span: Span,
|
parentheses_span: Span,
|
||||||
},
|
},
|
||||||
#[multipart_suggestion("use angle brackets instead")]
|
#[multipart_suggestion(ast_lowering_use_angle_brackets)]
|
||||||
NotEmpty {
|
NotEmpty {
|
||||||
#[suggestion_part(code = "<")]
|
#[suggestion_part(code = "<")]
|
||||||
open_param: Span,
|
open_param: Span,
|
||||||
|
|
@ -82,8 +82,8 @@ pub(crate) enum AssocTyParenthesesSub {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`impl Trait` is not allowed in {$position}", code = E0562)]
|
#[diag(ast_lowering_misplaced_impl_trait, code = E0562)]
|
||||||
#[note("`impl Trait` is only allowed in arguments and return types of functions and methods")]
|
#[note]
|
||||||
pub(crate) struct MisplacedImplTrait<'a> {
|
pub(crate) struct MisplacedImplTrait<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -91,106 +91,97 @@ pub(crate) struct MisplacedImplTrait<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("associated type bounds are not allowed in `dyn` types")]
|
#[diag(ast_lowering_assoc_ty_binding_in_dyn)]
|
||||||
pub(crate) struct MisplacedAssocTyBinding {
|
pub(crate) struct MisplacedAssocTyBinding {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[suggestion(
|
#[suggestion(code = " = impl", applicability = "maybe-incorrect", style = "verbose")]
|
||||||
"use `impl Trait` to introduce a type instead",
|
|
||||||
code = " = impl",
|
|
||||||
applicability = "maybe-incorrect",
|
|
||||||
style = "verbose"
|
|
||||||
)]
|
|
||||||
pub suggestion: Option<Span>,
|
pub suggestion: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("in expressions, `_` can only be used on the left-hand side of an assignment")]
|
#[diag(ast_lowering_underscore_expr_lhs_assign)]
|
||||||
pub(crate) struct UnderscoreExprLhsAssign {
|
pub(crate) struct UnderscoreExprLhsAssign {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("`_` not allowed here")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`await` is only allowed inside `async` functions and blocks", code = E0728)]
|
#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)]
|
||||||
pub(crate) struct AwaitOnlyInAsyncFnAndBlocks {
|
pub(crate) struct AwaitOnlyInAsyncFnAndBlocks {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("only allowed inside `async` functions and blocks")]
|
#[label]
|
||||||
pub await_kw_span: Span,
|
pub await_kw_span: Span,
|
||||||
#[label("this is not `async`")]
|
#[label(ast_lowering_this_not_async)]
|
||||||
pub item_span: Option<Span>,
|
pub item_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("too many parameters for a coroutine (expected 0 or 1 parameters)", code = E0628)]
|
#[diag(ast_lowering_coroutine_too_many_parameters, code = E0628)]
|
||||||
pub(crate) struct CoroutineTooManyParameters {
|
pub(crate) struct CoroutineTooManyParameters {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub fn_decl_span: Span,
|
pub fn_decl_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("closures cannot be static", code = E0697)]
|
#[diag(ast_lowering_closure_cannot_be_static, code = E0697)]
|
||||||
pub(crate) struct ClosureCannotBeStatic {
|
pub(crate) struct ClosureCannotBeStatic {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub fn_decl_span: Span,
|
pub fn_decl_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("functional record updates are not allowed in destructuring assignments")]
|
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||||
pub(crate) struct FunctionalRecordUpdateDestructuringAssignment {
|
pub(crate) struct FunctionalRecordUpdateDestructuringAssignment {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion(
|
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||||
"consider removing the trailing pattern",
|
|
||||||
code = "",
|
|
||||||
applicability = "machine-applicable"
|
|
||||||
)]
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`async` coroutines are not yet supported", code = E0727)]
|
#[diag(ast_lowering_async_coroutines_not_supported, code = E0727)]
|
||||||
pub(crate) struct AsyncCoroutinesNotSupported {
|
pub(crate) struct AsyncCoroutinesNotSupported {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("inline assembly is unsupported on this target", code = E0472)]
|
#[diag(ast_lowering_inline_asm_unsupported_target, code = E0472)]
|
||||||
pub(crate) struct InlineAsmUnsupportedTarget {
|
pub(crate) struct InlineAsmUnsupportedTarget {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("the `att_syntax` option is only supported on x86")]
|
#[diag(ast_lowering_att_syntax_only_x86)]
|
||||||
pub(crate) struct AttSyntaxOnlyX86 {
|
pub(crate) struct AttSyntaxOnlyX86 {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`{$prev_name}` ABI specified multiple times")]
|
#[diag(ast_lowering_abi_specified_multiple_times)]
|
||||||
pub(crate) struct AbiSpecifiedMultipleTimes {
|
pub(crate) struct AbiSpecifiedMultipleTimes {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub abi_span: Span,
|
pub abi_span: Span,
|
||||||
pub prev_name: Symbol,
|
pub prev_name: Symbol,
|
||||||
#[label("previously specified here")]
|
#[label]
|
||||||
pub prev_span: Span,
|
pub prev_span: Span,
|
||||||
#[note("these ABIs are equivalent on the current target")]
|
#[note]
|
||||||
pub equivalent: bool,
|
pub equivalent: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`clobber_abi` is not supported on this target")]
|
#[diag(ast_lowering_clobber_abi_not_supported)]
|
||||||
pub(crate) struct ClobberAbiNotSupported {
|
pub(crate) struct ClobberAbiNotSupported {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub abi_span: Span,
|
pub abi_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[note("the following ABIs are supported on this target: {$supported_abis}")]
|
#[note]
|
||||||
#[diag("invalid ABI for `clobber_abi`")]
|
#[diag(ast_lowering_invalid_abi_clobber_abi)]
|
||||||
pub(crate) struct InvalidAbiClobberAbi {
|
pub(crate) struct InvalidAbiClobberAbi {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub abi_span: Span,
|
pub abi_span: Span,
|
||||||
|
|
@ -198,7 +189,7 @@ pub(crate) struct InvalidAbiClobberAbi {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid register `{$reg}`: {$error}")]
|
#[diag(ast_lowering_invalid_register)]
|
||||||
pub(crate) struct InvalidRegister<'a> {
|
pub(crate) struct InvalidRegister<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
|
|
@ -207,10 +198,8 @@ pub(crate) struct InvalidRegister<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[note(
|
#[note]
|
||||||
"the following register classes are supported on this target: {$supported_register_classes}"
|
#[diag(ast_lowering_invalid_register_class)]
|
||||||
)]
|
|
||||||
#[diag("invalid register class `{$reg_class}`: unknown register class")]
|
|
||||||
pub(crate) struct InvalidRegisterClass {
|
pub(crate) struct InvalidRegisterClass {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
|
|
@ -219,12 +208,12 @@ pub(crate) struct InvalidRegisterClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid asm template modifier for this register class")]
|
#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)]
|
||||||
pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("template modifier")]
|
#[label(ast_lowering_template_modifier)]
|
||||||
pub placeholder_span: Span,
|
pub placeholder_span: Span,
|
||||||
#[label("argument")]
|
#[label(ast_lowering_argument)]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub sub: InvalidAsmTemplateModifierRegClassSub,
|
pub sub: InvalidAsmTemplateModifierRegClassSub,
|
||||||
|
|
@ -232,48 +221,44 @@ pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum InvalidAsmTemplateModifierRegClassSub {
|
pub(crate) enum InvalidAsmTemplateModifierRegClassSub {
|
||||||
#[note(
|
#[note(ast_lowering_support_modifiers)]
|
||||||
"the `{$class_name}` register class supports the following template modifiers: {$modifiers}"
|
|
||||||
)]
|
|
||||||
SupportModifier { class_name: Symbol, modifiers: String },
|
SupportModifier { class_name: Symbol, modifiers: String },
|
||||||
#[note("the `{$class_name}` register class does not support template modifiers")]
|
#[note(ast_lowering_does_not_support_modifiers)]
|
||||||
DoesNotSupportModifier { class_name: Symbol },
|
DoesNotSupportModifier { class_name: Symbol },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("asm template modifiers are not allowed for `const` arguments")]
|
#[diag(ast_lowering_invalid_asm_template_modifier_const)]
|
||||||
pub(crate) struct InvalidAsmTemplateModifierConst {
|
pub(crate) struct InvalidAsmTemplateModifierConst {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("template modifier")]
|
#[label(ast_lowering_template_modifier)]
|
||||||
pub placeholder_span: Span,
|
pub placeholder_span: Span,
|
||||||
#[label("argument")]
|
#[label(ast_lowering_argument)]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("asm template modifiers are not allowed for `sym` arguments")]
|
#[diag(ast_lowering_invalid_asm_template_modifier_sym)]
|
||||||
pub(crate) struct InvalidAsmTemplateModifierSym {
|
pub(crate) struct InvalidAsmTemplateModifierSym {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("template modifier")]
|
#[label(ast_lowering_template_modifier)]
|
||||||
pub placeholder_span: Span,
|
pub placeholder_span: Span,
|
||||||
#[label("argument")]
|
#[label(ast_lowering_argument)]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("asm template modifiers are not allowed for `label` arguments")]
|
#[diag(ast_lowering_invalid_asm_template_modifier_label)]
|
||||||
pub(crate) struct InvalidAsmTemplateModifierLabel {
|
pub(crate) struct InvalidAsmTemplateModifierLabel {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("template modifier")]
|
#[label(ast_lowering_template_modifier)]
|
||||||
pub placeholder_span: Span,
|
pub placeholder_span: Span,
|
||||||
#[label("argument")]
|
#[label(ast_lowering_argument)]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(
|
#[diag(ast_lowering_register_class_only_clobber)]
|
||||||
"register class `{$reg_class_name}` can only be used as a clobber, not as an input or output"
|
|
||||||
)]
|
|
||||||
pub(crate) struct RegisterClassOnlyClobber {
|
pub(crate) struct RegisterClassOnlyClobber {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
|
|
@ -281,7 +266,7 @@ pub(crate) struct RegisterClassOnlyClobber {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("register class `{$reg_class_name}` can only be used as a clobber in stable")]
|
#[diag(ast_lowering_register_class_only_clobber_stable)]
|
||||||
pub(crate) struct RegisterClassOnlyClobberStable {
|
pub(crate) struct RegisterClassOnlyClobberStable {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
|
|
@ -289,27 +274,27 @@ pub(crate) struct RegisterClassOnlyClobberStable {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("register `{$reg1_name}` conflicts with register `{$reg2_name}`")]
|
#[diag(ast_lowering_register_conflict)]
|
||||||
pub(crate) struct RegisterConflict<'a> {
|
pub(crate) struct RegisterConflict<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("register `{$reg1_name}`")]
|
#[label(ast_lowering_register1)]
|
||||||
pub op_span1: Span,
|
pub op_span1: Span,
|
||||||
#[label("register `{$reg2_name}`")]
|
#[label(ast_lowering_register2)]
|
||||||
pub op_span2: Span,
|
pub op_span2: Span,
|
||||||
pub reg1_name: &'a str,
|
pub reg1_name: &'a str,
|
||||||
pub reg2_name: &'a str,
|
pub reg2_name: &'a str,
|
||||||
#[help("use `lateout` instead of `out` to avoid conflict")]
|
#[help]
|
||||||
pub in_out: Option<Span>,
|
pub in_out: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[help("remove this and bind each tuple field independently")]
|
#[help]
|
||||||
#[diag("`{$ident_name} @` is not allowed in a {$ctx}")]
|
#[diag(ast_lowering_sub_tuple_binding)]
|
||||||
pub(crate) struct SubTupleBinding<'a> {
|
pub(crate) struct SubTupleBinding<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("this is only allowed in slice patterns")]
|
#[label]
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
"if you don't need to use the contents of {$ident}, discard the tuple's remaining fields",
|
ast_lowering_sub_tuple_binding_suggestion,
|
||||||
style = "verbose",
|
style = "verbose",
|
||||||
code = "..",
|
code = "..",
|
||||||
applicability = "maybe-incorrect"
|
applicability = "maybe-incorrect"
|
||||||
|
|
@ -321,67 +306,61 @@ pub(crate) struct SubTupleBinding<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`..` can only be used once per {$ctx} pattern")]
|
#[diag(ast_lowering_extra_double_dot)]
|
||||||
pub(crate) struct ExtraDoubleDot<'a> {
|
pub(crate) struct ExtraDoubleDot<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("can only be used once per {$ctx} pattern")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[label("previously used here")]
|
#[label(ast_lowering_previously_used_here)]
|
||||||
pub prev_span: Span,
|
pub prev_span: Span,
|
||||||
pub ctx: &'a str,
|
pub ctx: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[note("only allowed in tuple, tuple struct, and slice patterns")]
|
#[note]
|
||||||
#[diag("`..` patterns are not allowed here")]
|
#[diag(ast_lowering_misplaced_double_dot)]
|
||||||
pub(crate) struct MisplacedDoubleDot {
|
pub(crate) struct MisplacedDoubleDot {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`match` arm with no body")]
|
#[diag(ast_lowering_match_arm_with_no_body)]
|
||||||
pub(crate) struct MatchArmWithNoBody {
|
pub(crate) struct MatchArmWithNoBody {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[suggestion(
|
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
|
||||||
"add a body after the pattern",
|
|
||||||
code = " => todo!(),",
|
|
||||||
applicability = "has-placeholders"
|
|
||||||
)]
|
|
||||||
pub suggestion: Span,
|
pub suggestion: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("a never pattern is always unreachable")]
|
#[diag(ast_lowering_never_pattern_with_body)]
|
||||||
pub(crate) struct NeverPatternWithBody {
|
pub(crate) struct NeverPatternWithBody {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("this will never be executed")]
|
#[label]
|
||||||
#[suggestion("remove this expression", code = "", applicability = "maybe-incorrect")]
|
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("a guard on a never pattern will never be run")]
|
#[diag(ast_lowering_never_pattern_with_guard)]
|
||||||
pub(crate) struct NeverPatternWithGuard {
|
pub(crate) struct NeverPatternWithGuard {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion("remove this guard", code = "", applicability = "maybe-incorrect")]
|
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("arbitrary expressions aren't allowed in patterns")]
|
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
|
||||||
pub(crate) struct ArbitraryExpressionInPattern {
|
pub(crate) struct ArbitraryExpressionInPattern {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[note("the `expr` fragment specifier forces the metavariable's content to be an expression")]
|
#[note(ast_lowering_pattern_from_macro_note)]
|
||||||
pub pattern_from_macro_note: bool,
|
pub pattern_from_macro_note: bool,
|
||||||
#[help("use a named `const`-item or an `if`-guard (`x if x == const {\"{ ... }\"}`) instead")]
|
|
||||||
pub const_block_in_pattern_help: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("inclusive range with no end")]
|
#[diag(ast_lowering_inclusive_range_with_no_end)]
|
||||||
pub(crate) struct InclusiveRangeWithNoEnd {
|
pub(crate) struct InclusiveRangeWithNoEnd {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -389,7 +368,7 @@ pub(crate) struct InclusiveRangeWithNoEnd {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(
|
||||||
"use the right argument notation and remove the return type",
|
ast_lowering_bad_return_type_notation_output_suggestion,
|
||||||
applicability = "machine-applicable",
|
applicability = "machine-applicable",
|
||||||
style = "verbose"
|
style = "verbose"
|
||||||
)]
|
)]
|
||||||
|
|
@ -403,36 +382,26 @@ pub(crate) struct RTNSuggestion {
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
pub(crate) enum BadReturnTypeNotation {
|
pub(crate) enum BadReturnTypeNotation {
|
||||||
#[diag("argument types not allowed with return type notation")]
|
#[diag(ast_lowering_bad_return_type_notation_inputs)]
|
||||||
Inputs {
|
Inputs {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion(
|
#[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
|
||||||
"remove the input types",
|
|
||||||
code = "(..)",
|
|
||||||
applicability = "machine-applicable",
|
|
||||||
style = "verbose"
|
|
||||||
)]
|
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[diag("return type not allowed with return type notation")]
|
#[diag(ast_lowering_bad_return_type_notation_output)]
|
||||||
Output {
|
Output {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
suggestion: RTNSuggestion,
|
suggestion: RTNSuggestion,
|
||||||
},
|
},
|
||||||
#[diag("return type notation arguments must be elided with `..`")]
|
#[diag(ast_lowering_bad_return_type_notation_needs_dots)]
|
||||||
NeedsDots {
|
NeedsDots {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion(
|
#[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
|
||||||
"use the correct syntax by adding `..` to the arguments",
|
|
||||||
code = "(..)",
|
|
||||||
applicability = "machine-applicable",
|
|
||||||
style = "verbose"
|
|
||||||
)]
|
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[diag("return type notation not allowed in this position yet")]
|
#[diag(ast_lowering_bad_return_type_notation_position)]
|
||||||
Position {
|
Position {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -440,14 +409,14 @@ pub(crate) enum BadReturnTypeNotation {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("defaults for generic parameters are not allowed in `for<...>` binders")]
|
#[diag(ast_lowering_generic_param_default_in_binder)]
|
||||||
pub(crate) struct GenericParamDefaultInBinder {
|
pub(crate) struct GenericParamDefaultInBinder {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`async` bound modifier only allowed on trait, not `{$descr}`")]
|
#[diag(ast_lowering_async_bound_not_on_trait)]
|
||||||
pub(crate) struct AsyncBoundNotOnTrait {
|
pub(crate) struct AsyncBoundNotOnTrait {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -455,37 +424,30 @@ pub(crate) struct AsyncBoundNotOnTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits")]
|
#[diag(ast_lowering_async_bound_only_for_fn_traits)]
|
||||||
pub(crate) struct AsyncBoundOnlyForFnTraits {
|
pub(crate) struct AsyncBoundOnlyForFnTraits {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`use<...>` precise capturing syntax not allowed in argument-position `impl Trait`")]
|
#[diag(ast_lowering_no_precise_captures_on_apit)]
|
||||||
pub(crate) struct NoPreciseCapturesOnApit {
|
pub(crate) struct NoPreciseCapturesOnApit {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`yield` can only be used in `#[coroutine]` closures, or `gen` blocks")]
|
#[diag(ast_lowering_yield_in_closure)]
|
||||||
pub(crate) struct YieldInClosure {
|
pub(crate) struct YieldInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[suggestion(
|
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
|
||||||
"use `#[coroutine]` to make this closure a coroutine",
|
|
||||||
code = "#[coroutine] ",
|
|
||||||
applicability = "maybe-incorrect",
|
|
||||||
style = "verbose"
|
|
||||||
)]
|
|
||||||
pub suggestion: Option<Span>,
|
pub suggestion: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(
|
#[diag(ast_lowering_invalid_legacy_const_generic_arg)]
|
||||||
"invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items"
|
|
||||||
)]
|
|
||||||
pub(crate) struct InvalidLegacyConstGenericArg {
|
pub(crate) struct InvalidLegacyConstGenericArg {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -495,7 +457,7 @@ pub(crate) struct InvalidLegacyConstGenericArg {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(
|
||||||
"try using a const generic argument instead",
|
ast_lowering_invalid_legacy_const_generic_arg_suggestion,
|
||||||
applicability = "maybe-incorrect"
|
applicability = "maybe-incorrect"
|
||||||
)]
|
)]
|
||||||
pub(crate) struct UseConstGenericArg {
|
pub(crate) struct UseConstGenericArg {
|
||||||
|
|
@ -508,22 +470,8 @@ pub(crate) struct UseConstGenericArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("unions cannot have default field values")]
|
#[diag(ast_lowering_union_default_field_values)]
|
||||||
pub(crate) struct UnionWithDefault {
|
pub(crate) struct UnionWithDefault {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("failed to resolve delegation callee")]
|
|
||||||
pub(crate) struct UnresolvedDelegationCallee {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("encountered a cycle during delegation signature resolution")]
|
|
||||||
pub(crate) struct CycleInDelegationSignatureResolution {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
use std::mem;
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_ast_pretty::pprust::expr_to_string;
|
use rustc_ast_pretty::pprust::expr_to_string;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::msg;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::attrs::AttributeKind;
|
use rustc_hir::attrs::AttributeKind;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
|
@ -29,7 +27,7 @@ use super::{
|
||||||
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||||
};
|
};
|
||||||
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
||||||
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope};
|
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated};
|
||||||
|
|
||||||
struct WillCreateDefIdsVisitor {}
|
struct WillCreateDefIdsVisitor {}
|
||||||
|
|
||||||
|
|
@ -113,8 +111,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
|
ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
|
||||||
ExprKind::Call(f, args) => {
|
ExprKind::Call(f, args) => {
|
||||||
if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f, self.tcx)
|
if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
|
||||||
{
|
|
||||||
self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
|
self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
|
||||||
} else {
|
} else {
|
||||||
let f = self.lower_expr(f);
|
let f = self.lower_expr(f);
|
||||||
|
|
@ -157,14 +154,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
ExprKind::Cast(expr, ty) => {
|
ExprKind::Cast(expr, ty) => {
|
||||||
let expr = self.lower_expr(expr);
|
let expr = self.lower_expr(expr);
|
||||||
let ty = self
|
let ty =
|
||||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||||
hir::ExprKind::Cast(expr, ty)
|
hir::ExprKind::Cast(expr, ty)
|
||||||
}
|
}
|
||||||
ExprKind::Type(expr, ty) => {
|
ExprKind::Type(expr, ty) => {
|
||||||
let expr = self.lower_expr(expr);
|
let expr = self.lower_expr(expr);
|
||||||
let ty = self
|
let ty =
|
||||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||||
hir::ExprKind::Type(expr, ty)
|
hir::ExprKind::Type(expr, ty)
|
||||||
}
|
}
|
||||||
ExprKind::AddrOf(k, m, ohs) => {
|
ExprKind::AddrOf(k, m, ohs) => {
|
||||||
|
|
@ -202,9 +199,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::TryBlock(body, opt_ty) => {
|
ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
|
||||||
self.lower_expr_try_block(body, opt_ty.as_deref())
|
|
||||||
}
|
|
||||||
ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
|
ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
|
||||||
self.lower_expr(expr),
|
self.lower_expr(expr),
|
||||||
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
|
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
|
||||||
|
|
@ -334,7 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
|
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
|
||||||
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
|
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
|
||||||
self.lower_ty_alloc(
|
self.lower_ty(
|
||||||
container,
|
container,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
|
ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
|
||||||
),
|
),
|
||||||
|
|
@ -370,10 +365,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
*kind,
|
*kind,
|
||||||
self.lower_expr(expr),
|
self.lower_expr(expr),
|
||||||
ty.as_ref().map(|ty| {
|
ty.as_ref().map(|ty| {
|
||||||
self.lower_ty_alloc(
|
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
|
||||||
ty,
|
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Cast),
|
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
@ -492,11 +484,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
arg
|
arg
|
||||||
};
|
};
|
||||||
|
|
||||||
let anon_const = AnonConst {
|
let anon_const = AnonConst { id: node_id, value: const_value };
|
||||||
id: node_id,
|
|
||||||
value: const_value,
|
|
||||||
mgca_disambiguation: MgcaDisambiguation::AnonConst,
|
|
||||||
};
|
|
||||||
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
|
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
|
||||||
} else {
|
} else {
|
||||||
real_args.push(arg);
|
real_args.push(arg);
|
||||||
|
|
@ -574,14 +562,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
|
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
|
||||||
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`
|
/// `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.
|
/// 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, opt_ty: Option<&Ty>) -> hir::ExprKind<'hir> {
|
fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
|
||||||
let body_hir_id = self.lower_node_id(body.id);
|
let body_hir_id = self.lower_node_id(body.id);
|
||||||
let new_scope = if opt_ty.is_some() {
|
self.with_catch_scope(body_hir_id, |this| {
|
||||||
TryBlockScope::Heterogeneous(body_hir_id)
|
|
||||||
} else {
|
|
||||||
TryBlockScope::Homogeneous(body_hir_id)
|
|
||||||
};
|
|
||||||
let whole_block = self.with_try_block_scope(new_scope, |this| {
|
|
||||||
let mut block = this.lower_block_noalloc(body_hir_id, body, true);
|
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
|
// Final expression of the block (if present) or `()` with span at the end of block
|
||||||
|
|
@ -615,16 +598,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ok_wrapped_span,
|
ok_wrapped_span,
|
||||||
));
|
));
|
||||||
|
|
||||||
this.arena.alloc(block)
|
hir::ExprKind::Block(this.arena.alloc(block), None)
|
||||||
});
|
})
|
||||||
|
|
||||||
if let Some(ty) = opt_ty {
|
|
||||||
let ty = self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));
|
|
||||||
let block_expr = self.arena.alloc(self.expr_block(whole_block));
|
|
||||||
hir::ExprKind::Type(block_expr, ty)
|
|
||||||
} else {
|
|
||||||
hir::ExprKind::Block(whole_block, None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_in_try_constructor(
|
fn wrap_in_try_constructor(
|
||||||
|
|
@ -966,14 +941,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
||||||
this.arena.alloc(this.expr(gen_future_span, expr_break))
|
this.arena.alloc(this.expr(gen_future_span, expr_break))
|
||||||
});
|
});
|
||||||
self.arm(ready_pat, break_x, span)
|
self.arm(ready_pat, break_x)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `::std::task::Poll::Pending => {}`
|
// `::std::task::Poll::Pending => {}`
|
||||||
let pending_arm = {
|
let pending_arm = {
|
||||||
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
|
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
|
||||||
let empty_block = self.expr_block_empty(span);
|
let empty_block = self.expr_block_empty(span);
|
||||||
self.arm(pending_pat, empty_block, span)
|
self.arm(pending_pat, empty_block)
|
||||||
};
|
};
|
||||||
|
|
||||||
let inner_match_stmt = {
|
let inner_match_stmt = {
|
||||||
|
|
@ -1027,7 +1002,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// mut __awaitee => loop { ... }
|
// mut __awaitee => loop { ... }
|
||||||
let awaitee_arm = self.arm(awaitee_pat, loop_expr, span);
|
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
|
||||||
|
|
||||||
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
|
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
|
||||||
let into_future_expr = match await_kind {
|
let into_future_expr = match await_kind {
|
||||||
|
|
@ -1642,14 +1617,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_try_block_scope<T>(
|
fn with_catch_scope<T>(&mut self, catch_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||||
&mut self,
|
let old_scope = self.catch_scope.replace(catch_id);
|
||||||
scope: TryBlockScope,
|
|
||||||
f: impl FnOnce(&mut Self) -> T,
|
|
||||||
) -> T {
|
|
||||||
let old_scope = mem::replace(&mut self.try_block_scope, scope);
|
|
||||||
let result = f(self);
|
let result = f(self);
|
||||||
self.try_block_scope = old_scope;
|
self.catch_scope = old_scope;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1702,7 +1673,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&self.tcx.sess,
|
&self.tcx.sess,
|
||||||
sym::yield_expr,
|
sym::yield_expr,
|
||||||
span,
|
span,
|
||||||
msg!("yield syntax is experimental"),
|
fluent_generated::ast_lowering_yield,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -1817,7 +1788,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let break_expr =
|
let break_expr =
|
||||||
self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
|
self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
|
||||||
let pat = self.pat_none(for_span);
|
let pat = self.pat_none(for_span);
|
||||||
self.arm(pat, break_expr, for_span)
|
self.arm(pat, break_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Some(<pat>) => <body>,
|
// Some(<pat>) => <body>,
|
||||||
|
|
@ -1826,7 +1797,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let body_block =
|
let body_block =
|
||||||
self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
|
self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
|
||||||
let body_expr = self.arena.alloc(self.expr_block(body_block));
|
let body_expr = self.arena.alloc(self.expr_block(body_block));
|
||||||
self.arm(some_pat, body_expr, for_span)
|
self.arm(some_pat, body_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `mut iter`
|
// `mut iter`
|
||||||
|
|
@ -1885,7 +1856,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });
|
let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });
|
||||||
|
|
||||||
// `mut iter => { ... }`
|
// `mut iter => { ... }`
|
||||||
let iter_arm = self.arm(iter_pat, loop_expr, for_span);
|
let iter_arm = self.arm(iter_pat, loop_expr);
|
||||||
|
|
||||||
let match_expr = match loop_kind {
|
let match_expr = match loop_kind {
|
||||||
ForLoopKind::For => {
|
ForLoopKind::For => {
|
||||||
|
|
@ -1930,7 +1901,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir::LangItem::IntoAsyncIterIntoIter,
|
hir::LangItem::IntoAsyncIterIntoIter,
|
||||||
arena_vec![self; head],
|
arena_vec![self; head],
|
||||||
);
|
);
|
||||||
let iter_arm = self.arm(async_iter_pat, inner_match_expr, for_span);
|
let iter_arm = self.arm(async_iter_pat, inner_match_expr);
|
||||||
self.arena.alloc(self.expr_match(
|
self.arena.alloc(self.expr_match(
|
||||||
for_span,
|
for_span,
|
||||||
iter,
|
iter,
|
||||||
|
|
@ -1997,7 +1968,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
|
let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
|
||||||
self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);
|
self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);
|
||||||
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
|
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
|
||||||
self.arm(continue_pat, val_expr, try_span)
|
self.arm(continue_pat, val_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `ControlFlow::Break(residual) =>
|
// `ControlFlow::Break(residual) =>
|
||||||
|
|
@ -2007,25 +1978,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let residual_ident = Ident::with_dummy_span(sym::residual);
|
let residual_ident = Ident::with_dummy_span(sym::residual);
|
||||||
let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
|
let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
|
||||||
let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
|
let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
|
||||||
|
|
||||||
let (constructor_item, target_id) = match self.try_block_scope {
|
|
||||||
TryBlockScope::Function => {
|
|
||||||
(hir::LangItem::TryTraitFromResidual, Err(hir::LoopIdError::OutsideLoopScope))
|
|
||||||
}
|
|
||||||
TryBlockScope::Homogeneous(block_id) => {
|
|
||||||
(hir::LangItem::ResidualIntoTryType, Ok(block_id))
|
|
||||||
}
|
|
||||||
TryBlockScope::Heterogeneous(block_id) => {
|
|
||||||
(hir::LangItem::TryTraitFromResidual, Ok(block_id))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let from_residual_expr = self.wrap_in_try_constructor(
|
let from_residual_expr = self.wrap_in_try_constructor(
|
||||||
constructor_item,
|
if self.catch_scope.is_some() {
|
||||||
|
hir::LangItem::ResidualIntoTryType
|
||||||
|
} else {
|
||||||
|
hir::LangItem::TryTraitFromResidual
|
||||||
|
},
|
||||||
try_span,
|
try_span,
|
||||||
self.arena.alloc(residual_expr),
|
self.arena.alloc(residual_expr),
|
||||||
unstable_span,
|
unstable_span,
|
||||||
);
|
);
|
||||||
let ret_expr = if target_id.is_ok() {
|
let ret_expr = if let Some(catch_id) = self.catch_scope {
|
||||||
|
let target_id = Ok(catch_id);
|
||||||
self.arena.alloc(self.expr(
|
self.arena.alloc(self.expr(
|
||||||
try_span,
|
try_span,
|
||||||
hir::ExprKind::Break(
|
hir::ExprKind::Break(
|
||||||
|
|
@ -2040,7 +2004,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression);
|
self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression);
|
||||||
|
|
||||||
let break_pat = self.pat_cf_break(try_span, residual_local);
|
let break_pat = self.pat_cf_break(try_span, residual_local);
|
||||||
self.arm(break_pat, ret_expr, try_span)
|
self.arm(break_pat, ret_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
hir::ExprKind::Match(
|
hir::ExprKind::Match(
|
||||||
|
|
@ -2080,14 +2044,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
yeeted_span,
|
yeeted_span,
|
||||||
);
|
);
|
||||||
|
|
||||||
match self.try_block_scope {
|
if let Some(catch_id) = self.catch_scope {
|
||||||
TryBlockScope::Homogeneous(block_id) | TryBlockScope::Heterogeneous(block_id) => {
|
let target_id = Ok(catch_id);
|
||||||
hir::ExprKind::Break(
|
hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
|
||||||
hir::Destination { label: None, target_id: Ok(block_id) },
|
} else {
|
||||||
Some(from_yeet_expr),
|
self.checked_return(Some(from_yeet_expr))
|
||||||
)
|
|
||||||
}
|
|
||||||
TryBlockScope::Function => self.checked_return(Some(from_yeet_expr)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2368,13 +2329,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&mut self,
|
&mut self,
|
||||||
pat: &'hir hir::Pat<'hir>,
|
pat: &'hir hir::Pat<'hir>,
|
||||||
expr: &'hir hir::Expr<'hir>,
|
expr: &'hir hir::Expr<'hir>,
|
||||||
span: Span,
|
|
||||||
) -> hir::Arm<'hir> {
|
) -> hir::Arm<'hir> {
|
||||||
hir::Arm {
|
hir::Arm {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
pat,
|
pat,
|
||||||
guard: None,
|
guard: None,
|
||||||
span: self.lower_span(span),
|
span: self.lower_span(expr.span),
|
||||||
body: expr,
|
body: expr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -281,13 +281,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_const_arg_expr_field(&mut self, field: &'hir ConstArgExprField<'hir>) {
|
|
||||||
self.insert(field.span, field.hir_id, Node::ConstArgExprField(field));
|
|
||||||
self.with_parent(field.hir_id, |this| {
|
|
||||||
intravisit::walk_const_arg_expr_field(this, field);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
|
fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
|
||||||
self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
|
self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
|
||||||
|
|
||||||
|
|
@ -312,7 +305,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||||
|
|
||||||
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
|
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
|
||||||
self.insert(
|
self.insert(
|
||||||
const_arg.as_unambig_ct().span,
|
const_arg.as_unambig_ct().span(),
|
||||||
const_arg.hir_id,
|
const_arg.hir_id,
|
||||||
Node::ConstArg(const_arg.as_unambig_ct()),
|
Node::ConstArg(const_arg.as_unambig_ct()),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
|
||||||
use rustc_ast::visit::AssocCtxt;
|
use rustc_ast::visit::AssocCtxt;
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
||||||
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
|
use rustc_hir::attrs::AttributeKind;
|
||||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
|
|
@ -11,7 +11,6 @@ use rustc_hir::{
|
||||||
use rustc_index::{IndexSlice, IndexVec};
|
use rustc_index::{IndexSlice, IndexVec};
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||||
use rustc_span::def_id::DefId;
|
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
|
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
|
|
@ -134,108 +133,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_eii_decl(
|
|
||||||
&mut self,
|
|
||||||
id: NodeId,
|
|
||||||
name: Ident,
|
|
||||||
EiiDecl { foreign_item, impl_unsafe }: &EiiDecl,
|
|
||||||
) -> Option<hir::attrs::EiiDecl> {
|
|
||||||
self.lower_path_simple_eii(id, foreign_item).map(|did| hir::attrs::EiiDecl {
|
|
||||||
foreign_item: did,
|
|
||||||
impl_unsafe: *impl_unsafe,
|
|
||||||
name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_eii_impl(
|
|
||||||
&mut self,
|
|
||||||
EiiImpl {
|
|
||||||
node_id,
|
|
||||||
eii_macro_path,
|
|
||||||
impl_safety,
|
|
||||||
span,
|
|
||||||
inner_span,
|
|
||||||
is_default,
|
|
||||||
known_eii_macro_resolution,
|
|
||||||
}: &EiiImpl,
|
|
||||||
) -> hir::attrs::EiiImpl {
|
|
||||||
let resolution = if let Some(target) = known_eii_macro_resolution
|
|
||||||
&& let Some(decl) = self.lower_eii_decl(
|
|
||||||
*node_id,
|
|
||||||
// the expect is ok here since we always generate this path in the eii macro.
|
|
||||||
eii_macro_path.segments.last().expect("at least one segment").ident,
|
|
||||||
target,
|
|
||||||
) {
|
|
||||||
EiiImplResolution::Known(decl)
|
|
||||||
} else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) {
|
|
||||||
EiiImplResolution::Macro(macro_did)
|
|
||||||
} else {
|
|
||||||
EiiImplResolution::Error(
|
|
||||||
self.dcx().span_delayed_bug(*span, "eii never resolved without errors given"),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
hir::attrs::EiiImpl {
|
|
||||||
span: self.lower_span(*span),
|
|
||||||
inner_span: self.lower_span(*inner_span),
|
|
||||||
impl_marked_unsafe: self.lower_safety(*impl_safety, hir::Safety::Safe).is_unsafe(),
|
|
||||||
is_default: *is_default,
|
|
||||||
resolution,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_extra_attrs_for_item_kind(
|
|
||||||
&mut self,
|
|
||||||
id: NodeId,
|
|
||||||
i: &ItemKind,
|
|
||||||
) -> Vec<hir::Attribute> {
|
|
||||||
match i {
|
|
||||||
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
|
|
||||||
ItemKind::Fn(box Fn { eii_impls, .. }) => {
|
|
||||||
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
|
|
||||||
eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
|
|
||||||
))]
|
|
||||||
}
|
|
||||||
ItemKind::MacroDef(name, MacroDef { eii_declaration: Some(target), .. }) => self
|
|
||||||
.lower_eii_decl(id, *name, target)
|
|
||||||
.map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiDeclaration(decl))])
|
|
||||||
.unwrap_or_default(),
|
|
||||||
|
|
||||||
ItemKind::ExternCrate(..)
|
|
||||||
| ItemKind::Use(..)
|
|
||||||
| ItemKind::Static(..)
|
|
||||||
| ItemKind::Const(..)
|
|
||||||
| ItemKind::ConstBlock(..)
|
|
||||||
| ItemKind::Mod(..)
|
|
||||||
| ItemKind::ForeignMod(..)
|
|
||||||
| ItemKind::GlobalAsm(..)
|
|
||||||
| ItemKind::TyAlias(..)
|
|
||||||
| ItemKind::Enum(..)
|
|
||||||
| ItemKind::Struct(..)
|
|
||||||
| ItemKind::Union(..)
|
|
||||||
| ItemKind::Trait(..)
|
|
||||||
| ItemKind::TraitAlias(..)
|
|
||||||
| ItemKind::Impl(..)
|
|
||||||
| ItemKind::MacCall(..)
|
|
||||||
| ItemKind::MacroDef(..)
|
|
||||||
| ItemKind::Delegation(..)
|
|
||||||
| ItemKind::DelegationMac(..) => Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
|
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
|
||||||
let vis_span = self.lower_span(i.vis.span);
|
let vis_span = self.lower_span(i.vis.span);
|
||||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
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, Target::from_ast_item(i));
|
||||||
let extra_hir_attributes = self.generate_extra_attrs_for_item_kind(i.id, &i.kind);
|
|
||||||
let attrs = self.lower_attrs_with_extra(
|
|
||||||
hir_id,
|
|
||||||
&i.attrs,
|
|
||||||
i.span,
|
|
||||||
Target::from_ast_item(i),
|
|
||||||
&extra_hir_attributes,
|
|
||||||
);
|
|
||||||
|
|
||||||
let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind);
|
let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind);
|
||||||
let item = hir::Item {
|
let item = hir::Item {
|
||||||
owner_id: hir_id.expect_owner(),
|
owner_id: hir_id.expect_owner(),
|
||||||
|
|
@ -243,7 +144,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
vis_span,
|
vis_span,
|
||||||
span: self.lower_span(i.span),
|
span: self.lower_span(i.span),
|
||||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||||
eii: find_attr!(attrs, AttributeKind::EiiImpls(..) | AttributeKind::EiiDeclaration(..)),
|
|
||||||
};
|
};
|
||||||
self.arena.alloc(item)
|
self.arena.alloc(item)
|
||||||
}
|
}
|
||||||
|
|
@ -277,19 +177,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
define_opaque,
|
define_opaque,
|
||||||
}) => {
|
}) => {
|
||||||
let ident = self.lower_ident(*ident);
|
let ident = self.lower_ident(*ident);
|
||||||
let ty = self
|
let ty =
|
||||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||||
let body_id = self.lower_const_body(span, e.as_deref());
|
let body_id = self.lower_const_body(span, e.as_deref());
|
||||||
self.lower_define_opaque(hir_id, define_opaque);
|
self.lower_define_opaque(hir_id, define_opaque);
|
||||||
hir::ItemKind::Static(*m, ident, ty, body_id)
|
hir::ItemKind::Static(*m, ident, ty, body_id)
|
||||||
}
|
}
|
||||||
ItemKind::Const(box ConstItem {
|
ItemKind::Const(box ast::ConstItem {
|
||||||
defaultness: _,
|
ident, generics, ty, rhs, define_opaque, ..
|
||||||
ident,
|
|
||||||
generics,
|
|
||||||
ty,
|
|
||||||
rhs_kind,
|
|
||||||
define_opaque,
|
|
||||||
}) => {
|
}) => {
|
||||||
let ident = self.lower_ident(*ident);
|
let ident = self.lower_ident(*ident);
|
||||||
let (generics, (ty, rhs)) = self.lower_generics(
|
let (generics, (ty, rhs)) = self.lower_generics(
|
||||||
|
|
@ -297,30 +192,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
id,
|
id,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| {
|
|this| {
|
||||||
let ty = this.lower_ty_alloc(
|
let ty = this
|
||||||
ty,
|
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
|
||||||
);
|
|
||||||
let rhs = this.lower_const_item_rhs(rhs_kind, span);
|
|
||||||
(ty, rhs)
|
(ty, rhs)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.lower_define_opaque(hir_id, &define_opaque);
|
self.lower_define_opaque(hir_id, &define_opaque);
|
||||||
hir::ItemKind::Const(ident, generics, ty, rhs)
|
hir::ItemKind::Const(ident, generics, ty, rhs)
|
||||||
}
|
}
|
||||||
ItemKind::ConstBlock(ConstBlockItem { span, id, block }) => hir::ItemKind::Const(
|
|
||||||
self.lower_ident(ConstBlockItem::IDENT),
|
|
||||||
hir::Generics::empty(),
|
|
||||||
self.arena.alloc(self.ty_tup(DUMMY_SP, &[])),
|
|
||||||
hir::ConstItemRhs::Body({
|
|
||||||
let body = hir::Expr {
|
|
||||||
hir_id: self.lower_node_id(*id),
|
|
||||||
kind: hir::ExprKind::Block(self.lower_block(block, false), None),
|
|
||||||
span: self.lower_span(*span),
|
|
||||||
};
|
|
||||||
self.record_body(&[], body)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
ItemKind::Fn(box Fn {
|
ItemKind::Fn(box Fn {
|
||||||
sig: FnSig { decl, header, span: fn_sig_span },
|
sig: FnSig { decl, header, span: fn_sig_span },
|
||||||
ident,
|
ident,
|
||||||
|
|
@ -412,7 +292,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
|
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
|
||||||
}
|
}
|
||||||
Some(ty) => this.lower_ty_alloc(
|
Some(ty) => this.lower_ty(
|
||||||
ty,
|
ty,
|
||||||
ImplTraitContext::OpaqueTy {
|
ImplTraitContext::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias {
|
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||||
|
|
@ -486,7 +366,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.map(|of_trait| this.lower_trait_impl_header(of_trait));
|
.map(|of_trait| this.lower_trait_impl_header(of_trait));
|
||||||
|
|
||||||
let lowered_ty = this.lower_ty_alloc(
|
let lowered_ty = this.lower_ty(
|
||||||
ty,
|
ty,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
|
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
|
||||||
);
|
);
|
||||||
|
|
@ -555,7 +435,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
hir::ItemKind::TraitAlias(constness, ident, generics, bounds)
|
hir::ItemKind::TraitAlias(constness, ident, generics, bounds)
|
||||||
}
|
}
|
||||||
ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_declaration: _ }) => {
|
ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => {
|
||||||
let ident = self.lower_ident(*ident);
|
let ident = self.lower_ident(*ident);
|
||||||
let body = Box::new(self.lower_delim_args(body));
|
let body = Box::new(self.lower_delim_args(body));
|
||||||
let def_id = self.local_def_id(id);
|
let def_id = self.local_def_id(id);
|
||||||
|
|
@ -566,15 +446,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
def_kind.descr(def_id.to_def_id())
|
def_kind.descr(def_id.to_def_id())
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
let macro_def = self.arena.alloc(ast::MacroDef {
|
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
|
||||||
body,
|
|
||||||
macro_rules: *macro_rules,
|
|
||||||
eii_declaration: None,
|
|
||||||
});
|
|
||||||
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
|
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
|
||||||
}
|
}
|
||||||
ItemKind::Delegation(box delegation) => {
|
ItemKind::Delegation(box delegation) => {
|
||||||
let delegation_results = self.lower_delegation(delegation, id);
|
let delegation_results = self.lower_delegation(delegation, id, false);
|
||||||
hir::ItemKind::Fn {
|
hir::ItemKind::Fn {
|
||||||
sig: delegation_results.sig,
|
sig: delegation_results.sig,
|
||||||
ident: delegation_results.ident,
|
ident: delegation_results.ident,
|
||||||
|
|
@ -589,16 +465,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option<DefId> {
|
|
||||||
let res = self.resolver.get_partial_res(id)?;
|
|
||||||
let Some(did) = res.expect_full_res().opt_def_id() else {
|
|
||||||
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(did)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn lower_use_tree(
|
fn lower_use_tree(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -707,10 +573,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
vis_span,
|
vis_span,
|
||||||
span: this.lower_span(use_tree.span),
|
span: this.lower_span(use_tree.span),
|
||||||
has_delayed_lints: !this.delayed_lints.is_empty(),
|
has_delayed_lints: !this.delayed_lints.is_empty(),
|
||||||
eii: find_attr!(
|
|
||||||
attrs,
|
|
||||||
AttributeKind::EiiImpls(..) | AttributeKind::EiiDeclaration(..)
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
hir::OwnerNode::Item(this.arena.alloc(item))
|
hir::OwnerNode::Item(this.arena.alloc(item))
|
||||||
});
|
});
|
||||||
|
|
@ -791,8 +653,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
safety,
|
safety,
|
||||||
define_opaque,
|
define_opaque,
|
||||||
}) => {
|
}) => {
|
||||||
let ty = self
|
let ty =
|
||||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||||
let safety = self.lower_safety(*safety, hir::Safety::Unsafe);
|
let safety = self.lower_safety(*safety, hir::Safety::Unsafe);
|
||||||
if define_opaque.is_some() {
|
if define_opaque.is_some() {
|
||||||
self.dcx().span_err(i.span, "foreign statics cannot define opaque types");
|
self.dcx().span_err(i.span, "foreign statics cannot define opaque types");
|
||||||
|
|
@ -827,10 +689,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir_id,
|
hir_id,
|
||||||
def_id: self.local_def_id(v.id),
|
def_id: self.local_def_id(v.id),
|
||||||
data: self.lower_variant_data(hir_id, item_kind, &v.data),
|
data: self.lower_variant_data(hir_id, item_kind, &v.data),
|
||||||
disr_expr: v
|
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
|
||||||
.disr_expr
|
|
||||||
.as_ref()
|
|
||||||
.map(|e| self.lower_anon_const_to_anon_const(e, e.value.span)),
|
|
||||||
ident: self.lower_ident(v.ident),
|
ident: self.lower_ident(v.ident),
|
||||||
span: self.lower_span(v.span),
|
span: self.lower_span(v.span),
|
||||||
}
|
}
|
||||||
|
|
@ -906,8 +765,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&mut self,
|
&mut self,
|
||||||
(index, f): (usize, &FieldDef),
|
(index, f): (usize, &FieldDef),
|
||||||
) -> hir::FieldDef<'hir> {
|
) -> hir::FieldDef<'hir> {
|
||||||
let ty =
|
let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
|
||||||
self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
|
|
||||||
let hir_id = self.lower_node_id(f.id);
|
let hir_id = self.lower_node_id(f.id);
|
||||||
self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field);
|
self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field);
|
||||||
hir::FieldDef {
|
hir::FieldDef {
|
||||||
|
|
@ -920,10 +778,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
|
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
|
||||||
},
|
},
|
||||||
vis_span: self.lower_span(f.vis.span),
|
vis_span: self.lower_span(f.vis.span),
|
||||||
default: f
|
default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)),
|
||||||
.default
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| self.lower_anon_const_to_anon_const(v, v.value.span)),
|
|
||||||
ty,
|
ty,
|
||||||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||||
}
|
}
|
||||||
|
|
@ -939,36 +794,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
let trait_item_def_id = hir_id.expect_owner();
|
let trait_item_def_id = hir_id.expect_owner();
|
||||||
|
|
||||||
let (ident, generics, kind, has_value) = match &i.kind {
|
let (ident, generics, kind, has_default) = match &i.kind {
|
||||||
AssocItemKind::Const(box ConstItem {
|
AssocItemKind::Const(box ConstItem {
|
||||||
ident,
|
ident, generics, ty, rhs, define_opaque, ..
|
||||||
generics,
|
|
||||||
ty,
|
|
||||||
rhs_kind,
|
|
||||||
define_opaque,
|
|
||||||
..
|
|
||||||
}) => {
|
}) => {
|
||||||
let (generics, kind) = self.lower_generics(
|
let (generics, kind) = self.lower_generics(
|
||||||
generics,
|
generics,
|
||||||
i.id,
|
i.id,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| {
|
|this| {
|
||||||
let ty = this.lower_ty_alloc(
|
let ty = this
|
||||||
ty,
|
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
let rhs = rhs
|
||||||
);
|
.as_ref()
|
||||||
// Trait associated consts don't need an expression/body.
|
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
|
||||||
let rhs = if rhs_kind.has_expr() {
|
hir::TraitItemKind::Const(ty, rhs)
|
||||||
Some(this.lower_const_item_rhs(rhs_kind, i.span))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
hir::TraitItemKind::Const(ty, rhs, rhs_kind.is_type_const().into())
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if define_opaque.is_some() {
|
if define_opaque.is_some() {
|
||||||
if rhs_kind.has_expr() {
|
if rhs.is_some() {
|
||||||
self.lower_define_opaque(hir_id, &define_opaque);
|
self.lower_define_opaque(hir_id, &define_opaque);
|
||||||
} else {
|
} else {
|
||||||
self.dcx().span_err(
|
self.dcx().span_err(
|
||||||
|
|
@ -978,7 +823,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(*ident, generics, kind, rhs_kind.has_expr())
|
(*ident, generics, kind, rhs.is_some())
|
||||||
}
|
}
|
||||||
AssocItemKind::Fn(box Fn {
|
AssocItemKind::Fn(box Fn {
|
||||||
sig, ident, generics, body: None, define_opaque, ..
|
sig, ident, generics, body: None, define_opaque, ..
|
||||||
|
|
@ -1058,7 +903,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| {
|
|this| {
|
||||||
let ty = ty.as_ref().map(|x| {
|
let ty = ty.as_ref().map(|x| {
|
||||||
this.lower_ty_alloc(
|
this.lower_ty(
|
||||||
x,
|
x,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
|
ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
|
||||||
)
|
)
|
||||||
|
|
@ -1076,7 +921,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
(*ident, generics, kind, ty.is_some())
|
(*ident, generics, kind, ty.is_some())
|
||||||
}
|
}
|
||||||
AssocItemKind::Delegation(box delegation) => {
|
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(
|
let item_kind = hir::TraitItemKind::Fn(
|
||||||
delegation_results.sig,
|
delegation_results.sig,
|
||||||
hir::TraitFn::Provided(delegation_results.body_id),
|
hir::TraitFn::Provided(delegation_results.body_id),
|
||||||
|
|
@ -1088,17 +933,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value, || {
|
|
||||||
hir::Defaultness::Default { has_value }
|
|
||||||
});
|
|
||||||
|
|
||||||
let item = hir::TraitItem {
|
let item = hir::TraitItem {
|
||||||
owner_id: trait_item_def_id,
|
owner_id: trait_item_def_id,
|
||||||
ident: self.lower_ident(ident),
|
ident: self.lower_ident(ident),
|
||||||
generics,
|
generics,
|
||||||
kind,
|
kind,
|
||||||
span: self.lower_span(i.span),
|
span: self.lower_span(i.span),
|
||||||
defaultness,
|
defaultness: hir::Defaultness::Default { has_value: has_default },
|
||||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||||
};
|
};
|
||||||
self.arena.alloc(item)
|
self.arena.alloc(item)
|
||||||
|
|
@ -1126,8 +967,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
||||||
// to not cause an assertion failure inside the `lower_defaultness` function.
|
// to not cause an assertion failure inside the `lower_defaultness` function.
|
||||||
let has_val = true;
|
let has_val = true;
|
||||||
let (defaultness, defaultness_span) =
|
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
|
||||||
self.lower_defaultness(defaultness, has_val, || hir::Defaultness::Final);
|
|
||||||
let modifiers = TraitBoundModifiers {
|
let modifiers = TraitBoundModifiers {
|
||||||
constness: BoundConstness::Never,
|
constness: BoundConstness::Never,
|
||||||
asyncness: BoundAsyncness::Normal,
|
asyncness: BoundAsyncness::Normal,
|
||||||
|
|
@ -1156,8 +996,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
) -> &'hir hir::ImplItem<'hir> {
|
) -> &'hir hir::ImplItem<'hir> {
|
||||||
// Since `default impl` is not yet implemented, this is always true in impls.
|
// Since `default impl` is not yet implemented, this is always true in impls.
|
||||||
let has_value = true;
|
let has_value = true;
|
||||||
let (defaultness, _) =
|
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
||||||
self.lower_defaultness(i.kind.defaultness(), has_value, || hir::Defaultness::Final);
|
|
||||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||||
let attrs = self.lower_attrs(
|
let attrs = self.lower_attrs(
|
||||||
hir_id,
|
hir_id,
|
||||||
|
|
@ -1168,12 +1007,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
let (ident, (generics, kind)) = match &i.kind {
|
let (ident, (generics, kind)) = match &i.kind {
|
||||||
AssocItemKind::Const(box ConstItem {
|
AssocItemKind::Const(box ConstItem {
|
||||||
ident,
|
ident, generics, ty, rhs, define_opaque, ..
|
||||||
generics,
|
|
||||||
ty,
|
|
||||||
rhs_kind,
|
|
||||||
define_opaque,
|
|
||||||
..
|
|
||||||
}) => (
|
}) => (
|
||||||
*ident,
|
*ident,
|
||||||
self.lower_generics(
|
self.lower_generics(
|
||||||
|
|
@ -1181,12 +1015,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
i.id,
|
i.id,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||||
|this| {
|
|this| {
|
||||||
let ty = this.lower_ty_alloc(
|
let ty = this
|
||||||
ty,
|
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
|
||||||
);
|
|
||||||
this.lower_define_opaque(hir_id, &define_opaque);
|
this.lower_define_opaque(hir_id, &define_opaque);
|
||||||
let rhs = this.lower_const_item_rhs(rhs_kind, i.span);
|
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
|
||||||
hir::ImplItemKind::Const(ty, rhs)
|
hir::ImplItemKind::Const(ty, rhs)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -1243,7 +1075,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir::ImplItemKind::Type(ty)
|
hir::ImplItemKind::Type(ty)
|
||||||
}
|
}
|
||||||
Some(ty) => {
|
Some(ty) => {
|
||||||
let ty = this.lower_ty_alloc(
|
let ty = this.lower_ty(
|
||||||
ty,
|
ty,
|
||||||
ImplTraitContext::OpaqueTy {
|
ImplTraitContext::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias {
|
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||||
|
|
@ -1259,7 +1091,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
AssocItemKind::Delegation(box delegation) => {
|
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.ident,
|
delegation.ident,
|
||||||
(
|
(
|
||||||
|
|
@ -1310,14 +1142,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&self,
|
&self,
|
||||||
d: Defaultness,
|
d: Defaultness,
|
||||||
has_value: bool,
|
has_value: bool,
|
||||||
implicit: impl FnOnce() -> hir::Defaultness,
|
|
||||||
) -> (hir::Defaultness, Option<Span>) {
|
) -> (hir::Defaultness, Option<Span>) {
|
||||||
match d {
|
match d {
|
||||||
Defaultness::Implicit => (implicit(), None),
|
|
||||||
Defaultness::Default(sp) => {
|
Defaultness::Default(sp) => {
|
||||||
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
|
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
|
||||||
}
|
}
|
||||||
Defaultness::Final(sp) => (hir::Defaultness::Final, Some(self.lower_span(sp))),
|
Defaultness::Final => {
|
||||||
|
assert!(has_value);
|
||||||
|
(hir::Defaultness::Final, None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1415,7 +1248,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||||
// this as a special case.
|
// this as a special case.
|
||||||
return self.lower_fn_body(decl, contract, |this| {
|
return self.lower_fn_body(decl, contract, |this| {
|
||||||
if find_attr!(attrs, AttributeKind::RustcIntrinsic)
|
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
|
||||||
|| this.tcx.is_sdylib_interface_build()
|
|| this.tcx.is_sdylib_interface_build()
|
||||||
{
|
{
|
||||||
let span = this.lower_span(span);
|
let span = this.lower_span(span);
|
||||||
|
|
@ -1978,7 +1811,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
bound_generic_params,
|
bound_generic_params,
|
||||||
hir::GenericParamSource::Binder,
|
hir::GenericParamSource::Binder,
|
||||||
),
|
),
|
||||||
bounded_ty: self.lower_ty_alloc(
|
bounded_ty: self.lower_ty(
|
||||||
bounded_ty,
|
bounded_ty,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||||
),
|
),
|
||||||
|
|
@ -2007,14 +1840,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
|
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
|
||||||
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
||||||
lhs_ty: self.lower_ty_alloc(
|
lhs_ty: self
|
||||||
lhs_ty,
|
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
rhs_ty: self
|
||||||
),
|
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||||
rhs_ty: self.lower_ty_alloc(
|
|
||||||
rhs_ty,
|
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustc_ast::node_id::NodeMap;
|
use rustc_ast::node_id::NodeMap;
|
||||||
|
|
@ -47,14 +46,13 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_data_structures::sync::spawn;
|
use rustc_data_structures::sync::spawn;
|
||||||
use rustc_data_structures::tagged_ptr::TaggedRef;
|
use rustc_data_structures::tagged_ptr::TaggedRef;
|
||||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
|
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
|
||||||
use rustc_hir::attrs::AttributeKind;
|
|
||||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
||||||
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
|
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
|
||||||
use rustc_hir::lints::{AttributeLint, DelayedLint};
|
use rustc_hir::lints::DelayedLint;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
|
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
|
||||||
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
|
LifetimeSyntax, ParamName, Target, TraitCandidate,
|
||||||
};
|
};
|
||||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||||
use rustc_macros::extension;
|
use rustc_macros::extension;
|
||||||
|
|
@ -88,6 +86,8 @@ mod pat;
|
||||||
mod path;
|
mod path;
|
||||||
pub mod stability;
|
pub mod stability;
|
||||||
|
|
||||||
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
||||||
struct LoweringContext<'a, 'hir> {
|
struct LoweringContext<'a, 'hir> {
|
||||||
tcx: TyCtxt<'hir>,
|
tcx: TyCtxt<'hir>,
|
||||||
resolver: &'a mut ResolverAstLowering,
|
resolver: &'a mut ResolverAstLowering,
|
||||||
|
|
@ -117,7 +117,7 @@ struct LoweringContext<'a, 'hir> {
|
||||||
/// outside of an `async fn`.
|
/// outside of an `async fn`.
|
||||||
current_item: Option<Span>,
|
current_item: Option<Span>,
|
||||||
|
|
||||||
try_block_scope: TryBlockScope,
|
catch_scope: Option<HirId>,
|
||||||
loop_scope: Option<HirId>,
|
loop_scope: Option<HirId>,
|
||||||
is_in_loop_condition: bool,
|
is_in_loop_condition: bool,
|
||||||
is_in_dyn_type: bool,
|
is_in_dyn_type: bool,
|
||||||
|
|
@ -173,7 +173,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
trait_map: Default::default(),
|
trait_map: Default::default(),
|
||||||
|
|
||||||
// Lowering state.
|
// Lowering state.
|
||||||
try_block_scope: TryBlockScope::Function,
|
catch_scope: None,
|
||||||
loop_scope: None,
|
loop_scope: None,
|
||||||
is_in_loop_condition: false,
|
is_in_loop_condition: false,
|
||||||
is_in_dyn_type: false,
|
is_in_dyn_type: false,
|
||||||
|
|
@ -235,32 +235,29 @@ impl SpanLowerer {
|
||||||
|
|
||||||
#[extension(trait ResolverAstLoweringExt)]
|
#[extension(trait ResolverAstLoweringExt)]
|
||||||
impl ResolverAstLowering {
|
impl ResolverAstLowering {
|
||||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option<Vec<usize>> {
|
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
|
||||||
let ExprKind::Path(None, path) = &expr.kind else {
|
if let ExprKind::Path(None, path) = &expr.kind {
|
||||||
return None;
|
// Don't perform legacy const generics rewriting if the path already
|
||||||
};
|
// has generic arguments.
|
||||||
|
if path.segments.last().unwrap().args.is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// Don't perform legacy const generics rewriting if the path already
|
if let Res::Def(DefKind::Fn, def_id) = self.partial_res_map.get(&expr.id)?.full_res()? {
|
||||||
// has generic arguments.
|
// We only support cross-crate argument rewriting. Uses
|
||||||
if path.segments.last().unwrap().args.is_some() {
|
// within the same crate should be updated to use the new
|
||||||
return None;
|
// const generics style.
|
||||||
|
if def_id.is_local() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = self.legacy_const_generic_args.get(&def_id) {
|
||||||
|
return v.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?;
|
None
|
||||||
|
|
||||||
// We only support cross-crate argument rewriting. Uses
|
|
||||||
// within the same crate should be updated to use the new
|
|
||||||
// const generics style.
|
|
||||||
if def_id.is_local() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
find_attr!(
|
|
||||||
// we can use parsed attrs here since for other crates they're already available
|
|
||||||
tcx.get_all_attrs(def_id),
|
|
||||||
AttributeKind::RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes
|
|
||||||
)
|
|
||||||
.map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
|
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
|
||||||
|
|
@ -419,18 +416,6 @@ enum AstOwner<'a> {
|
||||||
ForeignItem(&'a ast::ForeignItem),
|
ForeignItem(&'a ast::ForeignItem),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
enum TryBlockScope {
|
|
||||||
/// There isn't a `try` block, so a `?` will use `return`.
|
|
||||||
Function,
|
|
||||||
/// We're inside a `try { … }` block, so a `?` will block-break
|
|
||||||
/// from that block using a type depending only on the argument.
|
|
||||||
Homogeneous(HirId),
|
|
||||||
/// We're inside a `try as _ { … }` block, so a `?` will block-break
|
|
||||||
/// from that block using the type specified.
|
|
||||||
Heterogeneous(HirId),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn index_crate<'a>(
|
fn index_crate<'a>(
|
||||||
node_id_to_def_id: &NodeMap<LocalDefId>,
|
node_id_to_def_id: &NodeMap<LocalDefId>,
|
||||||
krate: &'a Crate,
|
krate: &'a Crate,
|
||||||
|
|
@ -878,7 +863,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
|
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
|
||||||
}
|
}
|
||||||
LifetimeRes::Static { .. } | LifetimeRes::Error(..) => return None,
|
LifetimeRes::Static { .. } | LifetimeRes::Error => return None,
|
||||||
res => panic!(
|
res => panic!(
|
||||||
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
||||||
res, ident, ident.span
|
res, ident, ident.span
|
||||||
|
|
@ -951,10 +936,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
let old_contract = self.contract_ensures.take();
|
let old_contract = self.contract_ensures.take();
|
||||||
|
|
||||||
let try_block_scope = mem::replace(&mut self.try_block_scope, TryBlockScope::Function);
|
let catch_scope = self.catch_scope.take();
|
||||||
let loop_scope = self.loop_scope.take();
|
let loop_scope = self.loop_scope.take();
|
||||||
let ret = f(self);
|
let ret = f(self);
|
||||||
self.try_block_scope = try_block_scope;
|
self.catch_scope = catch_scope;
|
||||||
self.loop_scope = loop_scope;
|
self.loop_scope = loop_scope;
|
||||||
|
|
||||||
self.contract_ensures = old_contract;
|
self.contract_ensures = old_contract;
|
||||||
|
|
@ -973,23 +958,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
target_span: Span,
|
target_span: Span,
|
||||||
target: Target,
|
target: Target,
|
||||||
) -> &'hir [hir::Attribute] {
|
) -> &'hir [hir::Attribute] {
|
||||||
self.lower_attrs_with_extra(id, attrs, target_span, target, &[])
|
if attrs.is_empty() {
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_attrs_with_extra(
|
|
||||||
&mut self,
|
|
||||||
id: HirId,
|
|
||||||
attrs: &[Attribute],
|
|
||||||
target_span: Span,
|
|
||||||
target: Target,
|
|
||||||
extra_hir_attributes: &[hir::Attribute],
|
|
||||||
) -> &'hir [hir::Attribute] {
|
|
||||||
if attrs.is_empty() && extra_hir_attributes.is_empty() {
|
|
||||||
&[]
|
&[]
|
||||||
} else {
|
} else {
|
||||||
let mut lowered_attrs =
|
let lowered_attrs =
|
||||||
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
|
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
|
||||||
lowered_attrs.extend(extra_hir_attributes.iter().cloned());
|
|
||||||
|
|
||||||
assert_eq!(id.owner, self.current_hir_id_owner);
|
assert_eq!(id.owner, self.current_hir_id_owner);
|
||||||
let ret = self.arena.alloc_from_iter(lowered_attrs);
|
let ret = self.arena.alloc_from_iter(lowered_attrs);
|
||||||
|
|
@ -1020,16 +993,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
self.attribute_parser.parse_attribute_list(
|
self.attribute_parser.parse_attribute_list(
|
||||||
attrs,
|
attrs,
|
||||||
target_span,
|
target_span,
|
||||||
|
target_hir_id,
|
||||||
target,
|
target,
|
||||||
OmitDoc::Lower,
|
OmitDoc::Lower,
|
||||||
|s| l.lower(s),
|
|s| l.lower(s),
|
||||||
|lint_id, span, kind| {
|
|l| {
|
||||||
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
|
self.delayed_lints.push(DelayedLint::AttributeParsing(l));
|
||||||
lint_id,
|
|
||||||
id: target_hir_id,
|
|
||||||
span,
|
|
||||||
kind,
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1127,8 +1096,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let kind = match &constraint.kind {
|
let kind = match &constraint.kind {
|
||||||
AssocItemConstraintKind::Equality { term } => {
|
AssocItemConstraintKind::Equality { term } => {
|
||||||
let term = match term {
|
let term = match term {
|
||||||
Term::Ty(ty) => self.lower_ty_alloc(ty, itctx).into(),
|
Term::Ty(ty) => self.lower_ty(ty, itctx).into(),
|
||||||
Term::Const(c) => self.lower_anon_const_to_const_arg_and_alloc(c).into(),
|
Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(),
|
||||||
};
|
};
|
||||||
hir::AssocItemConstraintKind::Equality { term }
|
hir::AssocItemConstraintKind::Equality { term }
|
||||||
}
|
}
|
||||||
|
|
@ -1237,7 +1206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
.and_then(|partial_res| partial_res.full_res())
|
.and_then(|partial_res| partial_res.full_res())
|
||||||
{
|
{
|
||||||
if !res.matches_ns(Namespace::TypeNS)
|
if !res.matches_ns(Namespace::TypeNS)
|
||||||
&& path.is_potential_trivial_const_arg()
|
&& path.is_potential_trivial_const_arg(false)
|
||||||
{
|
{
|
||||||
debug!(
|
debug!(
|
||||||
"lower_generic_arg: Lowering type argument as const argument: {:?}",
|
"lower_generic_arg: Lowering type argument as const argument: {:?}",
|
||||||
|
|
@ -1252,17 +1221,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap())
|
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_and_alloc(ct).try_as_ambig_ct().unwrap(),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn lower_ty_alloc(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
|
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
|
||||||
self.arena.alloc(self.lower_ty(t, itctx))
|
self.arena.alloc(self.lower_ty_direct(t, itctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_path_ty(
|
fn lower_path_ty(
|
||||||
|
|
@ -1326,11 +1295,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
self.ty(span, hir::TyKind::Tup(tys))
|
self.ty(span, hir::TyKind::Tup(tys))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
||||||
let kind = match &t.kind {
|
let kind = match &t.kind {
|
||||||
TyKind::Infer => hir::TyKind::Infer(()),
|
TyKind::Infer => hir::TyKind::Infer(()),
|
||||||
TyKind::Err(guar) => hir::TyKind::Err(*guar),
|
TyKind::Err(guar) => hir::TyKind::Err(*guar),
|
||||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty_alloc(ty, itctx)),
|
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||||
TyKind::Ref(region, mt) => {
|
TyKind::Ref(region, mt) => {
|
||||||
let lifetime = self.lower_ty_direct_lifetime(t, *region);
|
let lifetime = self.lower_ty_direct_lifetime(t, *region);
|
||||||
|
|
@ -1364,15 +1333,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
||||||
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
|
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
|
||||||
generic_params,
|
generic_params,
|
||||||
inner_ty: self.lower_ty_alloc(&f.inner_ty, itctx),
|
inner_ty: self.lower_ty(&f.inner_ty, itctx),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
TyKind::Never => hir::TyKind::Never,
|
TyKind::Never => hir::TyKind::Never,
|
||||||
TyKind::Tup(tys) => hir::TyKind::Tup(
|
TyKind::Tup(tys) => hir::TyKind::Tup(
|
||||||
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty(ty, itctx))),
|
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
|
||||||
),
|
),
|
||||||
TyKind::Paren(ty) => {
|
TyKind::Paren(ty) => {
|
||||||
return self.lower_ty(ty, itctx);
|
return self.lower_ty_direct(ty, itctx);
|
||||||
}
|
}
|
||||||
TyKind::Path(qself, path) => {
|
TyKind::Path(qself, path) => {
|
||||||
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
|
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
|
||||||
|
|
@ -1395,7 +1364,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
TyKind::Array(ty, length) => hir::TyKind::Array(
|
TyKind::Array(ty, length) => hir::TyKind::Array(
|
||||||
self.lower_ty_alloc(ty, itctx),
|
self.lower_ty(ty, itctx),
|
||||||
self.lower_array_length_to_const_arg(length),
|
self.lower_array_length_to_const_arg(length),
|
||||||
),
|
),
|
||||||
TyKind::TraitObject(bounds, kind) => {
|
TyKind::TraitObject(bounds, kind) => {
|
||||||
|
|
@ -1495,7 +1464,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TyKind::Pat(ty, pat) => {
|
TyKind::Pat(ty, pat) => {
|
||||||
hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span))
|
hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span))
|
||||||
}
|
}
|
||||||
TyKind::MacCall(_) => {
|
TyKind::MacCall(_) => {
|
||||||
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
|
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
|
||||||
|
|
@ -1695,13 +1664,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
|
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.lower_ty(¶m.ty, itctx)
|
self.lower_ty_direct(¶m.ty, itctx)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let output = match coro {
|
let output = match coro {
|
||||||
Some(coro) => {
|
Some(coro) => {
|
||||||
let fn_def_id = self.local_def_id(fn_node_id);
|
let fn_def_id = self.local_def_id(fn_node_id);
|
||||||
self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind)
|
self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind, fn_span)
|
||||||
}
|
}
|
||||||
None => match &decl.output {
|
None => match &decl.output {
|
||||||
FnRetTy::Ty(ty) => {
|
FnRetTy::Ty(ty) => {
|
||||||
|
|
@ -1734,7 +1703,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn)
|
ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
hir::FnRetTy::Return(self.lower_ty_alloc(ty, itctx))
|
hir::FnRetTy::Return(self.lower_ty(ty, itctx))
|
||||||
}
|
}
|
||||||
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
|
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
|
||||||
},
|
},
|
||||||
|
|
@ -1786,8 +1755,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
fn_def_id: LocalDefId,
|
fn_def_id: LocalDefId,
|
||||||
coro: CoroutineKind,
|
coro: CoroutineKind,
|
||||||
fn_kind: FnDeclKind,
|
fn_kind: FnDeclKind,
|
||||||
|
fn_span: Span,
|
||||||
) -> hir::FnRetTy<'hir> {
|
) -> hir::FnRetTy<'hir> {
|
||||||
let span = self.lower_span(output.span());
|
let span = self.lower_span(fn_span);
|
||||||
|
|
||||||
let (opaque_ty_node_id, allowed_features) = match coro {
|
let (opaque_ty_node_id, allowed_features) = match coro {
|
||||||
CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None),
|
CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None),
|
||||||
|
|
@ -1845,7 +1815,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
|
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
|
||||||
// `impl Future` opaque type that `async fn` implicitly
|
// `impl Future` opaque type that `async fn` implicitly
|
||||||
// generates.
|
// generates.
|
||||||
self.lower_ty_alloc(ty, itctx)
|
self.lower_ty(ty, itctx)
|
||||||
}
|
}
|
||||||
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
|
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
|
||||||
};
|
};
|
||||||
|
|
@ -1931,29 +1901,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
source: LifetimeSource,
|
source: LifetimeSource,
|
||||||
syntax: LifetimeSyntax,
|
syntax: LifetimeSyntax,
|
||||||
) -> &'hir hir::Lifetime {
|
) -> &'hir hir::Lifetime {
|
||||||
let res = if let Some(res) = self.resolver.get_lifetime_res(id) {
|
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
|
||||||
match res {
|
let res = match res {
|
||||||
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
||||||
LifetimeRes::Fresh { param, .. } => {
|
LifetimeRes::Fresh { param, .. } => {
|
||||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||||
let param = self.local_def_id(param);
|
let param = self.local_def_id(param);
|
||||||
hir::LifetimeKind::Param(param)
|
hir::LifetimeKind::Param(param)
|
||||||
}
|
}
|
||||||
LifetimeRes::Infer => {
|
LifetimeRes::Infer => {
|
||||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||||
hir::LifetimeKind::Infer
|
hir::LifetimeKind::Infer
|
||||||
}
|
}
|
||||||
LifetimeRes::Static { .. } => {
|
LifetimeRes::Static { .. } => {
|
||||||
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||||
hir::LifetimeKind::Static
|
hir::LifetimeKind::Static
|
||||||
}
|
}
|
||||||
LifetimeRes::Error(guar) => hir::LifetimeKind::Error(guar),
|
LifetimeRes::Error => hir::LifetimeKind::Error,
|
||||||
LifetimeRes::ElidedAnchor { .. } => {
|
LifetimeRes::ElidedAnchor { .. } => {
|
||||||
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
hir::LifetimeKind::Error(self.dcx().span_delayed_bug(ident.span, "unresolved lifetime"))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(?res);
|
debug!(?res);
|
||||||
|
|
@ -1991,9 +1958,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let (name, kind) = self.lower_generic_param_kind(param, source);
|
let (name, kind) = self.lower_generic_param_kind(param, source);
|
||||||
|
|
||||||
let hir_id = self.lower_node_id(param.id);
|
let hir_id = self.lower_node_id(param.id);
|
||||||
let param_attrs = ¶m.attrs;
|
self.lower_attrs(hir_id, ¶m.attrs, param.span(), Target::Param);
|
||||||
let param_span = param.span();
|
hir::GenericParam {
|
||||||
let param = hir::GenericParam {
|
|
||||||
hir_id,
|
hir_id,
|
||||||
def_id: self.local_def_id(param.id),
|
def_id: self.local_def_id(param.id),
|
||||||
name,
|
name,
|
||||||
|
|
@ -2002,9 +1968,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
kind,
|
kind,
|
||||||
colon_span: param.colon_span.map(|s| self.lower_span(s)),
|
colon_span: param.colon_span.map(|s| self.lower_span(s)),
|
||||||
source,
|
source,
|
||||||
};
|
}
|
||||||
self.lower_attrs(hir_id, param_attrs, param_span, Target::from_generic_param(¶m));
|
|
||||||
param
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_generic_param_kind(
|
fn lower_generic_param_kind(
|
||||||
|
|
@ -2017,13 +1981,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// AST resolution emitted an error on those parameters, so we lower them using
|
// AST resolution emitted an error on those parameters, so we lower them using
|
||||||
// `ParamName::Error`.
|
// `ParamName::Error`.
|
||||||
let ident = self.lower_ident(param.ident);
|
let ident = self.lower_ident(param.ident);
|
||||||
let param_name = if let Some(LifetimeRes::Error(..)) =
|
let param_name =
|
||||||
self.resolver.get_lifetime_res(param.id)
|
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
|
||||||
{
|
ParamName::Error(ident)
|
||||||
ParamName::Error(ident)
|
} else {
|
||||||
} else {
|
ParamName::Plain(ident)
|
||||||
ParamName::Plain(ident)
|
};
|
||||||
};
|
|
||||||
let kind =
|
let kind =
|
||||||
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
|
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
|
||||||
|
|
||||||
|
|
@ -2045,7 +2008,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|def| {
|
.map(|def| {
|
||||||
self.lower_ty_alloc(
|
self.lower_ty(
|
||||||
def,
|
def,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||||
)
|
)
|
||||||
|
|
@ -2056,10 +2019,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { ty, span: _, default } => {
|
GenericParamKind::Const { ty, span: _, default } => {
|
||||||
let ty = self.lower_ty_alloc(
|
let ty = self
|
||||||
ty,
|
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Not only do we deny const param defaults in binders but we also map them to `None`
|
// Not only do we deny const param defaults in binders but we also map them to `None`
|
||||||
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
||||||
|
|
@ -2075,7 +2036,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|def| self.lower_anon_const_to_const_arg_and_alloc(def));
|
.map(|def| self.lower_anon_const_to_const_arg(def));
|
||||||
|
|
||||||
(
|
(
|
||||||
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
||||||
|
|
@ -2209,7 +2170,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
|
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
|
||||||
hir::MutTy { ty: self.lower_ty_alloc(&mt.ty, itctx), mutbl: mt.mutbl }
|
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self), ret)]
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
|
|
@ -2294,14 +2255,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer`
|
// `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer`
|
||||||
match c.value.peel_parens().kind {
|
match c.value.peel_parens().kind {
|
||||||
ExprKind::Underscore => {
|
ExprKind::Underscore => {
|
||||||
let ct_kind = hir::ConstArgKind::Infer(());
|
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
|
||||||
self.arena.alloc(hir::ConstArg {
|
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
|
||||||
hir_id: self.lower_node_id(c.id),
|
|
||||||
kind: ct_kind,
|
|
||||||
span: self.lower_span(c.value.span),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
_ => self.lower_anon_const_to_const_arg_and_alloc(c),
|
_ => self.lower_anon_const_to_const_arg(c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2318,9 +2275,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
) -> &'hir hir::ConstArg<'hir> {
|
) -> &'hir hir::ConstArg<'hir> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
let is_trivial_path = path.is_potential_trivial_const_arg()
|
let ct_kind = if path
|
||||||
&& matches!(res, Res::Def(DefKind::ConstParam, _));
|
.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
|
||||||
let ct_kind = if is_trivial_path || tcx.features().min_generic_const_args() {
|
&& (tcx.features().min_generic_const_args()
|
||||||
|
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
|
||||||
|
{
|
||||||
let qpath = self.lower_qpath(
|
let qpath = self.lower_qpath(
|
||||||
ty_id,
|
ty_id,
|
||||||
&None,
|
&None,
|
||||||
|
|
@ -2369,242 +2328,45 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
hir::ConstArgKind::Anon(ct)
|
hir::ConstArgKind::Anon(ct)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.arena.alloc(hir::ConstArg {
|
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: ct_kind,
|
|
||||||
span: self.lower_span(span),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_const_item_rhs(
|
fn lower_const_item_rhs(
|
||||||
&mut self,
|
&mut self,
|
||||||
rhs_kind: &ConstItemRhsKind,
|
attrs: &[hir::Attribute],
|
||||||
|
rhs: Option<&ConstItemRhs>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> hir::ConstItemRhs<'hir> {
|
) -> hir::ConstItemRhs<'hir> {
|
||||||
match rhs_kind {
|
match rhs {
|
||||||
ConstItemRhsKind::Body { rhs: Some(body) } => {
|
Some(ConstItemRhs::TypeConst(anon)) => {
|
||||||
hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body)))
|
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon))
|
||||||
}
|
}
|
||||||
ConstItemRhsKind::Body { rhs: None } => {
|
None if attr::contains_name(attrs, sym::type_const) => {
|
||||||
hir::ConstItemRhs::Body(self.lower_const_body(span, None))
|
|
||||||
}
|
|
||||||
ConstItemRhsKind::TypeConst { rhs: Some(anon) } => {
|
|
||||||
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
|
|
||||||
}
|
|
||||||
ConstItemRhsKind::TypeConst { rhs: None } => {
|
|
||||||
let const_arg = ConstArg {
|
let const_arg = ConstArg {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
kind: hir::ConstArgKind::Error(
|
kind: hir::ConstArgKind::Error(
|
||||||
|
DUMMY_SP,
|
||||||
self.dcx().span_delayed_bug(DUMMY_SP, "no block"),
|
self.dcx().span_delayed_bug(DUMMY_SP, "no block"),
|
||||||
),
|
),
|
||||||
span: DUMMY_SP,
|
|
||||||
};
|
};
|
||||||
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
|
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
|
||||||
}
|
}
|
||||||
}
|
Some(ConstItemRhs::Body(body)) => {
|
||||||
}
|
hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body)))
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self), ret)]
|
|
||||||
fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> {
|
|
||||||
let span = self.lower_span(expr.span);
|
|
||||||
|
|
||||||
let overly_complex_const = |this: &mut Self| {
|
|
||||||
let e = this.dcx().struct_span_err(
|
|
||||||
expr.span,
|
|
||||||
"complex const arguments must be placed inside of a `const` block",
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span }
|
|
||||||
};
|
|
||||||
|
|
||||||
match &expr.kind {
|
|
||||||
ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => {
|
|
||||||
let qpath = self.lower_qpath(
|
|
||||||
func.id,
|
|
||||||
qself,
|
|
||||||
path,
|
|
||||||
ParamMode::Explicit,
|
|
||||||
AllowReturnTypeNotation::No,
|
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
|
|
||||||
let const_arg = self.lower_expr_to_const_arg_direct(arg);
|
|
||||||
&*self.arena.alloc(const_arg)
|
|
||||||
}));
|
|
||||||
|
|
||||||
ConstArg {
|
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: hir::ConstArgKind::TupleCall(qpath, lowered_args),
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ExprKind::Tup(exprs) => {
|
None => hir::ConstItemRhs::Body(self.lower_const_body(span, None)),
|
||||||
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
|
|
||||||
let expr = self.lower_expr_to_const_arg_direct(&expr);
|
|
||||||
&*self.arena.alloc(expr)
|
|
||||||
}));
|
|
||||||
|
|
||||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(exprs), span }
|
|
||||||
}
|
|
||||||
ExprKind::Path(qself, path) => {
|
|
||||||
let qpath = self.lower_qpath(
|
|
||||||
expr.id,
|
|
||||||
qself,
|
|
||||||
path,
|
|
||||||
ParamMode::Explicit,
|
|
||||||
AllowReturnTypeNotation::No,
|
|
||||||
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span }
|
|
||||||
}
|
|
||||||
ExprKind::Struct(se) => {
|
|
||||||
let path = self.lower_qpath(
|
|
||||||
expr.id,
|
|
||||||
&se.qself,
|
|
||||||
&se.path,
|
|
||||||
// FIXME(mgca): we may want this to be `Optional` instead, but
|
|
||||||
// we would also need to make sure that HIR ty lowering errors
|
|
||||||
// when these paths wind up in signatures.
|
|
||||||
ParamMode::Explicit,
|
|
||||||
AllowReturnTypeNotation::No,
|
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let fields = self.arena.alloc_from_iter(se.fields.iter().map(|f| {
|
|
||||||
let hir_id = self.lower_node_id(f.id);
|
|
||||||
// FIXME(mgca): This might result in lowering attributes that
|
|
||||||
// then go unused as the `Target::ExprField` is not actually
|
|
||||||
// corresponding to `Node::ExprField`.
|
|
||||||
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
|
|
||||||
let expr = self.lower_expr_to_const_arg_direct(&f.expr);
|
|
||||||
|
|
||||||
&*self.arena.alloc(hir::ConstArgExprField {
|
|
||||||
hir_id,
|
|
||||||
field: self.lower_ident(f.ident),
|
|
||||||
expr: self.arena.alloc(expr),
|
|
||||||
span: self.lower_span(f.span),
|
|
||||||
})
|
|
||||||
}));
|
|
||||||
|
|
||||||
ConstArg {
|
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: hir::ConstArgKind::Struct(path, fields),
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Array(elements) => {
|
|
||||||
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
|
|
||||||
let const_arg = self.lower_expr_to_const_arg_direct(element);
|
|
||||||
&*self.arena.alloc(const_arg)
|
|
||||||
}));
|
|
||||||
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
|
|
||||||
span: self.lower_span(expr.span),
|
|
||||||
elems: lowered_elems,
|
|
||||||
});
|
|
||||||
|
|
||||||
ConstArg {
|
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: hir::ConstArgKind::Array(array_expr),
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Underscore => ConstArg {
|
|
||||||
hir_id: self.lower_node_id(expr.id),
|
|
||||||
kind: hir::ConstArgKind::Infer(()),
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
ExprKind::Block(block, _) => {
|
|
||||||
if let [stmt] = block.stmts.as_slice()
|
|
||||||
&& let StmtKind::Expr(expr) = &stmt.kind
|
|
||||||
&& matches!(
|
|
||||||
expr.kind,
|
|
||||||
ExprKind::Block(..)
|
|
||||||
| ExprKind::Path(..)
|
|
||||||
| ExprKind::Struct(..)
|
|
||||||
| ExprKind::Call(..)
|
|
||||||
| ExprKind::Tup(..)
|
|
||||||
| ExprKind::Array(..)
|
|
||||||
| ExprKind::ConstBlock(..)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return self.lower_expr_to_const_arg_direct(expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
overly_complex_const(self)
|
|
||||||
}
|
|
||||||
ExprKind::Lit(literal) => {
|
|
||||||
let span = expr.span;
|
|
||||||
let literal = self.lower_lit(literal, span);
|
|
||||||
|
|
||||||
ConstArg {
|
|
||||||
hir_id: self.lower_node_id(expr.id),
|
|
||||||
kind: hir::ConstArgKind::Literal { lit: literal.node, negated: false },
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Unary(UnOp::Neg, inner_expr)
|
|
||||||
if let ExprKind::Lit(literal) = &inner_expr.kind =>
|
|
||||||
{
|
|
||||||
let span = expr.span;
|
|
||||||
let literal = self.lower_lit(literal, span);
|
|
||||||
|
|
||||||
ConstArg {
|
|
||||||
hir_id: self.lower_node_id(expr.id),
|
|
||||||
kind: hir::ConstArgKind::Literal { lit: literal.node, negated: true },
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::ConstBlock(anon_const) => {
|
|
||||||
let def_id = self.local_def_id(anon_const.id);
|
|
||||||
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
|
|
||||||
self.lower_anon_const_to_const_arg(anon_const, span)
|
|
||||||
}
|
|
||||||
_ => overly_complex_const(self),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`hir::ConstArg`] for when to use this function vs
|
/// See [`hir::ConstArg`] for when to use this function vs
|
||||||
/// [`Self::lower_anon_const_to_anon_const`].
|
/// [`Self::lower_anon_const_to_anon_const`].
|
||||||
fn lower_anon_const_to_const_arg_and_alloc(
|
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
|
||||||
&mut self,
|
self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon))
|
||||||
anon: &AnonConst,
|
|
||||||
) -> &'hir hir::ConstArg<'hir> {
|
|
||||||
self.arena.alloc(self.lower_anon_const_to_const_arg(anon, anon.value.span))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn lower_anon_const_to_const_arg(
|
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||||
&mut self,
|
|
||||||
anon: &AnonConst,
|
|
||||||
span: Span,
|
|
||||||
) -> hir::ConstArg<'hir> {
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
// We cannot change parsing depending on feature gates available,
|
|
||||||
// we can only require feature gates to be active as a delayed check.
|
|
||||||
// Thus we just parse anon consts generally and make the real decision
|
|
||||||
// making in ast lowering.
|
|
||||||
// FIXME(min_generic_const_args): revisit once stable
|
|
||||||
if tcx.features().min_generic_const_args() {
|
|
||||||
return match anon.mgca_disambiguation {
|
|
||||||
MgcaDisambiguation::AnonConst => {
|
|
||||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon, span);
|
|
||||||
ConstArg {
|
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
|
||||||
span: lowered_anon.span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
|
// 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.
|
// 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
|
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
|
||||||
|
|
@ -2616,12 +2378,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
} else {
|
} else {
|
||||||
&anon.value
|
&anon.value
|
||||||
};
|
};
|
||||||
|
|
||||||
let maybe_res =
|
let maybe_res =
|
||||||
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
||||||
if let ExprKind::Path(qself, path) = &expr.kind
|
if let ExprKind::Path(qself, path) = &expr.kind
|
||||||
&& path.is_potential_trivial_const_arg()
|
&& path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
|
||||||
&& matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))
|
&& (tcx.features().min_generic_const_args()
|
||||||
|
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
|
||||||
{
|
{
|
||||||
let qpath = self.lower_qpath(
|
let qpath = self.lower_qpath(
|
||||||
expr.id,
|
expr.id,
|
||||||
|
|
@ -2629,6 +2391,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
path,
|
path,
|
||||||
ParamMode::Explicit,
|
ParamMode::Explicit,
|
||||||
AllowReturnTypeNotation::No,
|
AllowReturnTypeNotation::No,
|
||||||
|
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
@ -2636,25 +2399,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
return ConstArg {
|
return ConstArg {
|
||||||
hir_id: self.lower_node_id(anon.id),
|
hir_id: self.lower_node_id(anon.id),
|
||||||
kind: hir::ConstArgKind::Path(qpath),
|
kind: hir::ConstArgKind::Path(qpath),
|
||||||
span: self.lower_span(expr.span),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon, anon.value.span);
|
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||||
ConstArg {
|
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
|
||||||
hir_id: self.next_id(),
|
|
||||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
|
||||||
span: self.lower_span(expr.span),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`hir::ConstArg`] for when to use this function vs
|
/// See [`hir::ConstArg`] for when to use this function vs
|
||||||
/// [`Self::lower_anon_const_to_const_arg`].
|
/// [`Self::lower_anon_const_to_const_arg`].
|
||||||
fn lower_anon_const_to_anon_const(
|
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
|
||||||
&mut self,
|
|
||||||
c: &AnonConst,
|
|
||||||
span: Span,
|
|
||||||
) -> &'hir hir::AnonConst {
|
|
||||||
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
|
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
|
||||||
let def_id = this.local_def_id(c.id);
|
let def_id = this.local_def_id(c.id);
|
||||||
let hir_id = this.lower_node_id(c.id);
|
let hir_id = this.lower_node_id(c.id);
|
||||||
|
|
@ -2662,7 +2416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
def_id,
|
def_id,
|
||||||
hir_id,
|
hir_id,
|
||||||
body: 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(span),
|
span: this.lower_span(c.value.span),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -399,6 +399,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
ExprKind::Lit(lit) => {
|
ExprKind::Lit(lit) => {
|
||||||
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
|
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
|
||||||
}
|
}
|
||||||
|
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
|
||||||
ExprKind::IncludedBytes(byte_sym) => hir::PatExprKind::Lit {
|
ExprKind::IncludedBytes(byte_sym) => hir::PatExprKind::Lit {
|
||||||
lit: respan(span, LitKind::ByteStr(*byte_sym, StrStyle::Cooked)),
|
lit: respan(span, LitKind::ByteStr(*byte_sym, StrStyle::Cooked)),
|
||||||
negated: false,
|
negated: false,
|
||||||
|
|
@ -418,12 +419,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true }
|
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true }
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let is_const_block = matches!(expr.kind, ExprKind::ConstBlock(_));
|
|
||||||
let pattern_from_macro = expr.is_approximately_pattern();
|
let pattern_from_macro = expr.is_approximately_pattern();
|
||||||
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
||||||
span,
|
span,
|
||||||
pattern_from_macro_note: pattern_from_macro,
|
pattern_from_macro_note: pattern_from_macro,
|
||||||
const_block_in_pattern_help: is_const_block,
|
|
||||||
});
|
});
|
||||||
err(guar)
|
err(guar)
|
||||||
}
|
}
|
||||||
|
|
@ -444,18 +443,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let pat_hir_id = self.lower_node_id(pattern.id);
|
let pat_hir_id = self.lower_node_id(pattern.id);
|
||||||
let node = match &pattern.kind {
|
let node = match &pattern.kind {
|
||||||
TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
|
TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
|
||||||
e1.as_deref()
|
e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| {
|
||||||
.map(|e| self.lower_anon_const_to_const_arg_and_alloc(e))
|
self.lower_ty_pat_range_end(
|
||||||
.unwrap_or_else(|| {
|
hir::LangItem::RangeMin,
|
||||||
self.lower_ty_pat_range_end(
|
span.shrink_to_lo(),
|
||||||
hir::LangItem::RangeMin,
|
base_type,
|
||||||
span.shrink_to_lo(),
|
)
|
||||||
base_type,
|
}),
|
||||||
)
|
|
||||||
}),
|
|
||||||
e2.as_deref()
|
e2.as_deref()
|
||||||
.map(|e| match end {
|
.map(|e| match end {
|
||||||
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg_and_alloc(e),
|
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e),
|
||||||
RangeEnd::Excluded => self.lower_excluded_range_end(e),
|
RangeEnd::Excluded => self.lower_excluded_range_end(e),
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
|
|
@ -513,7 +510,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
self.arena.alloc(hir::ConstArg {
|
self.arena.alloc(hir::ConstArg {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
|
kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
|
||||||
span,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -558,6 +554,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let hir_id = self.next_id();
|
let hir_id = self.next_id();
|
||||||
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id, span })
|
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let qself = qself
|
let qself = qself
|
||||||
.as_ref()
|
.as_ref()
|
||||||
// Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
|
// Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
|
||||||
.map(|q| {
|
.map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
|
||||||
self.lower_ty_alloc(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))
|
|
||||||
});
|
|
||||||
|
|
||||||
let partial_res =
|
let partial_res =
|
||||||
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||||
|
|
@ -512,7 +510,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// we generally don't permit such things (see #51008).
|
// we generally don't permit such things (see #51008).
|
||||||
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
|
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
|
||||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
|
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
|
||||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||||
}));
|
}));
|
||||||
let output_ty = match output {
|
let output_ty = match output {
|
||||||
// Only allow `impl Trait` in return position. i.e.:
|
// Only allow `impl Trait` in return position. i.e.:
|
||||||
|
|
@ -522,9 +520,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// ```
|
// ```
|
||||||
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
|
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_alloc(ty, itctx)
|
self.lower_ty(ty, itctx)
|
||||||
} else {
|
} else {
|
||||||
self.lower_ty_alloc(
|
self.lower_ty(
|
||||||
ty,
|
ty,
|
||||||
ImplTraitContext::FeatureGated(
|
ImplTraitContext::FeatureGated(
|
||||||
ImplTraitPosition::FnTraitReturn,
|
ImplTraitPosition::FnTraitReturn,
|
||||||
|
|
@ -533,8 +531,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FnRetTy::Ty(ty) => self
|
FnRetTy::Ty(ty) => {
|
||||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
|
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
|
||||||
|
}
|
||||||
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
|
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
|
||||||
};
|
};
|
||||||
let args = smallvec![GenericArg::Type(
|
let args = smallvec![GenericArg::Type(
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ pub(crate) fn extern_abi_enabled(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
|
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
|
||||||
match extern_abi_enabled(features, span, abi) {
|
match extern_abi_enabled(features, span, abi) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
|
|
@ -95,11 +96,6 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
||||||
ExternAbi::RustCold => {
|
ExternAbi::RustCold => {
|
||||||
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
|
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
|
||||||
}
|
}
|
||||||
ExternAbi::RustPreserveNone => Err(UnstableAbi {
|
|
||||||
abi,
|
|
||||||
feature: sym::rust_preserve_none_cc,
|
|
||||||
explain: GateReason::Experimental,
|
|
||||||
}),
|
|
||||||
ExternAbi::RustInvalid => {
|
ExternAbi::RustInvalid => {
|
||||||
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_session = { path = "../rustc_session" }
|
rustc_session = { path = "../rustc_session" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
|
|
|
||||||
340
compiler/rustc_ast_passes/messages.ftl
Normal file
340
compiler/rustc_ast_passes/messages.ftl
Normal file
|
|
@ -0,0 +1,340 @@
|
||||||
|
ast_passes_abi_cannot_be_coroutine =
|
||||||
|
functions with the {$abi} ABI cannot be `{$coroutine_kind_str}`
|
||||||
|
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definition
|
||||||
|
|
||||||
|
ast_passes_abi_custom_safe_foreign_function =
|
||||||
|
foreign functions with the "custom" ABI cannot be safe
|
||||||
|
.suggestion = remove the `safe` keyword from this definition
|
||||||
|
|
||||||
|
ast_passes_abi_custom_safe_function =
|
||||||
|
functions with the "custom" ABI must be unsafe
|
||||||
|
.suggestion = add the `unsafe` keyword to this definition
|
||||||
|
|
||||||
|
ast_passes_abi_must_not_have_parameters_or_return_type=
|
||||||
|
invalid signature for `extern {$abi}` function
|
||||||
|
.note = functions with the {$abi} ABI cannot have any parameters or return type
|
||||||
|
.suggestion = remove the parameters and return type
|
||||||
|
|
||||||
|
ast_passes_abi_must_not_have_return_type=
|
||||||
|
invalid signature for `extern {$abi}` function
|
||||||
|
.note = functions with the {$abi} ABI cannot have a return type
|
||||||
|
.help = remove the return type
|
||||||
|
|
||||||
|
ast_passes_abi_x86_interrupt =
|
||||||
|
invalid signature for `extern "x86-interrupt"` function
|
||||||
|
.note = functions with the "x86-interrupt" ABI must be have either 1 or 2 parameters (but found {$param_count})
|
||||||
|
|
||||||
|
ast_passes_assoc_const_without_body =
|
||||||
|
associated constant in `impl` without body
|
||||||
|
.suggestion = provide a definition for the constant
|
||||||
|
|
||||||
|
ast_passes_assoc_fn_without_body =
|
||||||
|
associated function in `impl` without body
|
||||||
|
.suggestion = provide a definition for the function
|
||||||
|
|
||||||
|
ast_passes_assoc_type_without_body =
|
||||||
|
associated type in `impl` without body
|
||||||
|
.suggestion = provide a definition for the type
|
||||||
|
|
||||||
|
ast_passes_async_fn_in_const_trait_or_trait_impl =
|
||||||
|
async functions are not allowed in `const` {$context ->
|
||||||
|
[trait_impl] trait impls
|
||||||
|
[impl] impls
|
||||||
|
*[trait] traits
|
||||||
|
}
|
||||||
|
.label = associated functions of `const` cannot be declared `async`
|
||||||
|
|
||||||
|
ast_passes_at_least_one_trait = at least one trait must be specified
|
||||||
|
|
||||||
|
ast_passes_auto_generic = auto traits cannot have generic parameters
|
||||||
|
.label = auto trait cannot have generic parameters
|
||||||
|
.suggestion = remove the parameters
|
||||||
|
|
||||||
|
ast_passes_auto_items = auto traits cannot have associated items
|
||||||
|
.label = {ast_passes_auto_items}
|
||||||
|
.suggestion = remove the associated items
|
||||||
|
|
||||||
|
ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
|
||||||
|
.label = {ast_passes_auto_super_lifetime}
|
||||||
|
.suggestion = remove the super traits or lifetime bounds
|
||||||
|
|
||||||
|
ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
|
||||||
|
.cannot_have = cannot have a body
|
||||||
|
.invalid = the invalid body
|
||||||
|
.existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body
|
||||||
|
|
||||||
|
ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
|
||||||
|
|
||||||
|
ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions
|
||||||
|
.label = `extern "{$abi}"` because of this
|
||||||
|
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||||
|
|
||||||
|
ast_passes_c_variadic_bad_naked_extern = `...` is not supported for `extern "{$abi}"` naked functions
|
||||||
|
.label = `extern "{$abi}"` because of this
|
||||||
|
.help = C-variadic function must have a compatible calling convention
|
||||||
|
|
||||||
|
ast_passes_c_variadic_must_be_unsafe =
|
||||||
|
functions with a C variable argument list must be unsafe
|
||||||
|
.suggestion = add the `unsafe` keyword to this definition
|
||||||
|
|
||||||
|
ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions
|
||||||
|
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||||
|
|
||||||
|
ast_passes_c_variadic_not_supported = the `{$target}` target does not support c-variadic functions
|
||||||
|
|
||||||
|
ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic
|
||||||
|
.const = `const` because of this
|
||||||
|
.variadic = C-variadic because of this
|
||||||
|
|
||||||
|
ast_passes_const_and_coroutine = functions cannot be both `const` and `{$coroutine_kind}`
|
||||||
|
.const = `const` because of this
|
||||||
|
.coroutine = `{$coroutine_kind}` because of this
|
||||||
|
.label = {""}
|
||||||
|
|
||||||
|
ast_passes_const_auto_trait = auto traits cannot be const
|
||||||
|
.help = remove the `const` keyword
|
||||||
|
|
||||||
|
ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types
|
||||||
|
|
||||||
|
ast_passes_const_without_body =
|
||||||
|
free constant item without body
|
||||||
|
.suggestion = provide a definition for the constant
|
||||||
|
|
||||||
|
ast_passes_constraint_on_negative_bound =
|
||||||
|
associated type constraints not allowed on negative bounds
|
||||||
|
|
||||||
|
ast_passes_coroutine_and_c_variadic = functions cannot be both `{$coroutine_kind}` and C-variadic
|
||||||
|
.const = `{$coroutine_kind}` because of this
|
||||||
|
.variadic = C-variadic because of this
|
||||||
|
|
||||||
|
ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
|
||||||
|
.label = not supported
|
||||||
|
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
|
||||||
|
.suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax
|
||||||
|
.note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
|
||||||
|
|
||||||
|
ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
|
||||||
|
|
||||||
|
ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have `{$kw}` qualifier
|
||||||
|
.label = in this `extern` block
|
||||||
|
.suggestion = remove the `{$kw}` qualifier
|
||||||
|
|
||||||
|
ast_passes_extern_invalid_safety = items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||||
|
.suggestion = add `unsafe` to this `extern` block
|
||||||
|
|
||||||
|
ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
|
||||||
|
.label = in this `extern` block
|
||||||
|
.note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
|
||||||
|
|
||||||
|
ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||||
|
|
||||||
|
ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr}
|
||||||
|
.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_extern_without_abi_sugg = `extern` declarations without an explicit ABI are deprecated
|
||||||
|
.label = ABI should be specified here
|
||||||
|
.suggestion = explicitly specify the {$default_abi} ABI
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ast_passes_fieldless_union = unions cannot have zero fields
|
||||||
|
|
||||||
|
ast_passes_fn_body_extern = incorrect function inside `extern` block
|
||||||
|
.cannot_have = cannot have a body
|
||||||
|
.suggestion = remove the invalid body
|
||||||
|
.help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
|
||||||
|
.label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body
|
||||||
|
|
||||||
|
ast_passes_fn_param_c_var_args_not_last =
|
||||||
|
`...` must be the last argument of a C-variadic function
|
||||||
|
|
||||||
|
ast_passes_fn_param_doc_comment =
|
||||||
|
documentation comments cannot be applied to function parameters
|
||||||
|
.label = doc comments are not allowed here
|
||||||
|
|
||||||
|
ast_passes_fn_param_forbidden_attr =
|
||||||
|
allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
|
||||||
|
|
||||||
|
ast_passes_fn_param_forbidden_self =
|
||||||
|
`self` parameter is only allowed in associated functions
|
||||||
|
.label = not semantically valid as function parameter
|
||||||
|
.note = associated functions are those in `impl` or `trait` definitions
|
||||||
|
|
||||||
|
ast_passes_fn_param_too_many =
|
||||||
|
function can not have more than {$max_num_args} arguments
|
||||||
|
|
||||||
|
ast_passes_fn_ptr_invalid_safety = function pointers cannot be declared with `safe` safety qualifier
|
||||||
|
.suggestion = remove safe from this item
|
||||||
|
|
||||||
|
ast_passes_fn_without_body =
|
||||||
|
free function without a body
|
||||||
|
.suggestion = provide a definition for the function
|
||||||
|
|
||||||
|
ast_passes_forbidden_bound =
|
||||||
|
bounds cannot be used in this context
|
||||||
|
|
||||||
|
ast_passes_forbidden_const_param =
|
||||||
|
late-bound const parameters cannot be used currently
|
||||||
|
|
||||||
|
ast_passes_forbidden_default =
|
||||||
|
`default` is only allowed on items in trait impls
|
||||||
|
.label = `default` because of this
|
||||||
|
|
||||||
|
ast_passes_forbidden_non_lifetime_param =
|
||||||
|
only lifetime parameters can be used in this context
|
||||||
|
|
||||||
|
ast_passes_generic_before_constraints = generic arguments must come before the first constraint
|
||||||
|
.constraints = {$constraint_len ->
|
||||||
|
[one] constraint
|
||||||
|
*[other] constraints
|
||||||
|
}
|
||||||
|
.args = generic {$args_len ->
|
||||||
|
[one] argument
|
||||||
|
*[other] arguments
|
||||||
|
}
|
||||||
|
.empty_string = {""},
|
||||||
|
.suggestion = move the {$constraint_len ->
|
||||||
|
[one] constraint
|
||||||
|
*[other] constraints
|
||||||
|
} after the generic {$args_len ->
|
||||||
|
[one] argument
|
||||||
|
*[other] arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_passes_generic_default_trailing = generic parameters with a default must be trailing
|
||||||
|
|
||||||
|
ast_passes_impl_fn_const =
|
||||||
|
redundant `const` fn marker in const impl
|
||||||
|
.parent_constness = this declares all associated functions implicitly const
|
||||||
|
.label = remove the `const`
|
||||||
|
|
||||||
|
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
|
||||||
|
.help = remove one of these features
|
||||||
|
|
||||||
|
ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
|
||||||
|
.suggestion = remove safe from this item
|
||||||
|
|
||||||
|
ast_passes_item_underscore = `{$kind}` items in this context need a name
|
||||||
|
.label = `_` is not a valid name for this `{$kind}` item
|
||||||
|
|
||||||
|
ast_passes_match_arm_with_no_body =
|
||||||
|
`match` arm with no body
|
||||||
|
.suggestion = add a body after the pattern
|
||||||
|
|
||||||
|
ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe
|
||||||
|
.suggestion = needs `unsafe` before the extern keyword
|
||||||
|
|
||||||
|
ast_passes_missing_unsafe_on_extern_lint = extern blocks should be unsafe
|
||||||
|
.suggestion = needs `unsafe` before the extern keyword
|
||||||
|
|
||||||
|
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
|
||||||
|
.help = consider using the `#[path]` attribute to specify filesystem path
|
||||||
|
|
||||||
|
ast_passes_negative_bound_not_supported =
|
||||||
|
negative bounds are not supported
|
||||||
|
|
||||||
|
ast_passes_negative_bound_with_parenthetical_notation =
|
||||||
|
parenthetical notation may not be used for negative bounds
|
||||||
|
|
||||||
|
ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
|
||||||
|
.outer = outer `impl Trait`
|
||||||
|
.inner = nested `impl Trait` here
|
||||||
|
|
||||||
|
ast_passes_nested_lifetimes = nested quantification of lifetimes
|
||||||
|
|
||||||
|
ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
|
||||||
|
|
||||||
|
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
|
||||||
|
.help = use `auto trait Trait {"{}"}` instead
|
||||||
|
|
||||||
|
ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
|
||||||
|
.suggestion = reorder the parameters: lifetimes, then consts and types
|
||||||
|
|
||||||
|
ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
|
||||||
|
.label = pattern not allowed in function without body
|
||||||
|
|
||||||
|
ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types
|
||||||
|
|
||||||
|
ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
|
||||||
|
.label = pattern not allowed in foreign function
|
||||||
|
|
||||||
|
ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing syntax
|
||||||
|
.label = second `use<...>` here
|
||||||
|
|
||||||
|
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
|
||||||
|
|
||||||
|
ast_passes_static_without_body =
|
||||||
|
free static item without body
|
||||||
|
.suggestion = provide a definition for the static
|
||||||
|
|
||||||
|
ast_passes_tilde_const_disallowed = `[const]` is not allowed here
|
||||||
|
.closure = closures cannot have `[const]` trait bounds
|
||||||
|
.function = this function is not `const`, so it cannot have `[const]` trait bounds
|
||||||
|
.trait = this trait is not `const`, so it cannot have `[const]` trait bounds
|
||||||
|
.trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds
|
||||||
|
.impl = inherent impls cannot have `[const]` trait bounds
|
||||||
|
.trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds
|
||||||
|
.trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds
|
||||||
|
.inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds
|
||||||
|
.struct = structs cannot have `[const]` trait bounds
|
||||||
|
.enum = enums cannot have `[const]` trait bounds
|
||||||
|
.union = unions cannot have `[const]` trait bounds
|
||||||
|
.anon_const = anonymous constants cannot have `[const]` trait bounds
|
||||||
|
.object = trait objects cannot have `[const]` trait bounds
|
||||||
|
.item = this item cannot have `[const]` trait bounds
|
||||||
|
|
||||||
|
ast_passes_trait_fn_const =
|
||||||
|
functions in {$in_impl ->
|
||||||
|
[true] trait impls
|
||||||
|
*[false] traits
|
||||||
|
} cannot be declared const
|
||||||
|
.label = functions in {$in_impl ->
|
||||||
|
[true] trait impls
|
||||||
|
*[false] traits
|
||||||
|
} cannot be const
|
||||||
|
.const_context_label = this declares all associated functions implicitly const
|
||||||
|
.remove_const_sugg = remove the `const`{$requires_multiple_changes ->
|
||||||
|
[true] {" ..."}
|
||||||
|
*[false] {""}
|
||||||
|
}
|
||||||
|
.make_impl_const_sugg = ... and declare the impl to be const instead
|
||||||
|
.make_trait_const_sugg = ... and declare the trait to be const instead
|
||||||
|
|
||||||
|
ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
|
||||||
|
|
||||||
|
ast_passes_ty_alias_without_body =
|
||||||
|
free type alias without body
|
||||||
|
.suggestion = provide a definition for the type
|
||||||
|
|
||||||
|
ast_passes_unsafe_item = {$kind} cannot be declared unsafe
|
||||||
|
|
||||||
|
ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
|
||||||
|
.negative = negative because of this
|
||||||
|
.unsafe = unsafe because of this
|
||||||
|
|
||||||
|
ast_passes_unsafe_static =
|
||||||
|
static items cannot be declared with `unsafe` safety qualifier outside of `extern` block
|
||||||
|
|
||||||
|
ast_passes_visibility_not_permitted =
|
||||||
|
visibility qualifiers are not permitted here
|
||||||
|
.enum_variant = enum variants and their fields always share the visibility of the enum they are in
|
||||||
|
.trait_impl = trait items always share the visibility of their trait
|
||||||
|
.individual_impl_items = place qualifiers on individual impl items instead
|
||||||
|
.individual_foreign_items = place qualifiers on individual foreign items instead
|
||||||
|
.remove_qualifier_sugg = remove the qualifier
|
||||||
|
|
||||||
|
ast_passes_where_clause_after_type_alias = where clauses are not allowed after the type for type aliases
|
||||||
|
.note = see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
|
||||||
|
.help = add `#![feature(lazy_type_alias)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
|
||||||
|
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
|
||||||
|
.remove_suggestion = remove this `where`
|
||||||
|
.move_suggestion = move it to the end of the type declaration
|
||||||
|
|
@ -33,7 +33,7 @@ use rustc_session::Session;
|
||||||
use rustc_session::lint::BuiltinLintDiag;
|
use rustc_session::lint::BuiltinLintDiag;
|
||||||
use rustc_session::lint::builtin::{
|
use rustc_session::lint::builtin::{
|
||||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
||||||
PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES,
|
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||||
};
|
};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::{Ident, Span, kw, sym};
|
use rustc_span::{Ident, Span, kw, sym};
|
||||||
|
|
@ -65,28 +65,6 @@ impl TraitOrImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AllowDefault {
|
|
||||||
Yes,
|
|
||||||
No,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AllowDefault {
|
|
||||||
fn when(b: bool) -> Self {
|
|
||||||
if b { Self::Yes } else { Self::No }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AllowFinal {
|
|
||||||
Yes,
|
|
||||||
No,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AllowFinal {
|
|
||||||
fn when(b: bool) -> Self {
|
|
||||||
if b { Self::Yes } else { Self::No }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AstValidator<'a> {
|
struct AstValidator<'a> {
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
features: &'a Features,
|
features: &'a Features,
|
||||||
|
|
@ -422,18 +400,10 @@ impl<'a> AstValidator<'a> {
|
||||||
CanonAbi::C
|
CanonAbi::C
|
||||||
| CanonAbi::Rust
|
| CanonAbi::Rust
|
||||||
| CanonAbi::RustCold
|
| CanonAbi::RustCold
|
||||||
| CanonAbi::RustPreserveNone
|
|
||||||
| CanonAbi::Arm(_)
|
| CanonAbi::Arm(_)
|
||||||
|
| CanonAbi::GpuKernel
|
||||||
| CanonAbi::X86(_) => { /* nothing to check */ }
|
| CanonAbi::X86(_) => { /* nothing to check */ }
|
||||||
|
|
||||||
CanonAbi::GpuKernel => {
|
|
||||||
// An `extern "gpu-kernel"` function cannot be `async` and/or `gen`.
|
|
||||||
self.reject_coroutine(abi, sig);
|
|
||||||
|
|
||||||
// An `extern "gpu-kernel"` function cannot return a value.
|
|
||||||
self.reject_return(abi, sig);
|
|
||||||
}
|
|
||||||
|
|
||||||
CanonAbi::Custom => {
|
CanonAbi::Custom => {
|
||||||
// An `extern "custom"` function must be unsafe.
|
// An `extern "custom"` function must be unsafe.
|
||||||
self.reject_safe_fn(abi, ctxt, sig);
|
self.reject_safe_fn(abi, ctxt, sig);
|
||||||
|
|
@ -463,7 +433,18 @@ impl<'a> AstValidator<'a> {
|
||||||
self.dcx().emit_err(errors::AbiX86Interrupt { spans, param_count });
|
self.dcx().emit_err(errors::AbiX86Interrupt { spans, param_count });
|
||||||
}
|
}
|
||||||
|
|
||||||
self.reject_return(abi, sig);
|
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
|
||||||
|
&& match &ret_ty.kind {
|
||||||
|
TyKind::Never => false,
|
||||||
|
TyKind::Tup(tup) if tup.is_empty() => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
{
|
||||||
|
self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
|
||||||
|
span: ret_ty.span,
|
||||||
|
abi,
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// An `extern "interrupt"` function must have type `fn()`.
|
// An `extern "interrupt"` function must have type `fn()`.
|
||||||
self.reject_params_or_return(abi, ident, sig);
|
self.reject_params_or_return(abi, ident, sig);
|
||||||
|
|
@ -515,18 +496,6 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reject_return(&self, abi: ExternAbi, sig: &FnSig) {
|
|
||||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
|
|
||||||
&& match &ret_ty.kind {
|
|
||||||
TyKind::Never => false,
|
|
||||||
TyKind::Tup(tup) if tup.is_empty() => false,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
{
|
|
||||||
self.dcx().emit_err(errors::AbiMustNotHaveReturnType { span: ret_ty.span, abi });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
|
fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
|
||||||
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
|
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
|
||||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
|
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
|
||||||
|
|
@ -585,32 +554,10 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_defaultness(
|
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||||
&self,
|
if let Defaultness::Default(def_span) = defaultness {
|
||||||
span: Span,
|
let span = self.sess.source_map().guess_head_span(span);
|
||||||
defaultness: Defaultness,
|
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
||||||
allow_default: AllowDefault,
|
|
||||||
allow_final: AllowFinal,
|
|
||||||
) {
|
|
||||||
match defaultness {
|
|
||||||
Defaultness::Default(def_span) if matches!(allow_default, AllowDefault::No) => {
|
|
||||||
let span = self.sess.source_map().guess_head_span(span);
|
|
||||||
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
|
||||||
}
|
|
||||||
Defaultness::Final(def_span) if matches!(allow_final, AllowFinal::No) => {
|
|
||||||
let span = self.sess.source_map().guess_head_span(span);
|
|
||||||
self.dcx().emit_err(errors::ForbiddenFinal { span, def_span });
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_final_has_body(&self, item: &Item<AssocItemKind>, defaultness: Defaultness) {
|
|
||||||
if let AssocItemKind::Fn(box Fn { body: None, .. }) = &item.kind
|
|
||||||
&& let Defaultness::Final(def_span) = defaultness
|
|
||||||
{
|
|
||||||
let span = self.sess.source_map().guess_head_span(item.span);
|
|
||||||
self.dcx().emit_err(errors::ForbiddenFinalWithoutBody { span, def_span });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -742,11 +689,13 @@ impl<'a> AstValidator<'a> {
|
||||||
unreachable!("C variable argument list cannot be used in closures")
|
unreachable!("C variable argument list cannot be used in closures")
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Const::Yes(_) = sig.header.constness
|
// C-variadics are not yet implemented in const evaluation.
|
||||||
&& !self.features.enabled(sym::const_c_variadic)
|
if let Const::Yes(const_span) = sig.header.constness {
|
||||||
{
|
self.dcx().emit_err(errors::ConstAndCVariadic {
|
||||||
let msg = format!("c-variadic const function definitions are unstable");
|
spans: vec![const_span, variadic_param.span],
|
||||||
feature_err(&self.sess, sym::const_c_variadic, sig.span, msg).emit();
|
const_span,
|
||||||
|
variadic_span: variadic_param.span,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||||
|
|
@ -1230,15 +1179,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
contract: _,
|
contract: _,
|
||||||
body,
|
body,
|
||||||
define_opaque: _,
|
define_opaque: _,
|
||||||
eii_impls,
|
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
|
|
||||||
for EiiImpl { eii_macro_path, .. } in eii_impls {
|
|
||||||
self.visit_path(eii_macro_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
|
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
|
||||||
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
|
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
|
||||||
|
|
@ -1370,14 +1314,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
}
|
}
|
||||||
ItemKind::Struct(ident, generics, vdata) => {
|
ItemKind::Struct(ident, generics, vdata) => {
|
||||||
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
|
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
|
||||||
// Scalable vectors can only be tuple structs
|
|
||||||
let is_scalable_vector =
|
|
||||||
item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector));
|
|
||||||
if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) {
|
|
||||||
this.dcx()
|
|
||||||
.emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
|
|
||||||
}
|
|
||||||
|
|
||||||
match vdata {
|
match vdata {
|
||||||
VariantData::Struct { fields, .. } => {
|
VariantData::Struct { fields, .. } => {
|
||||||
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||||
|
|
@ -1403,26 +1339,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
|
ItemKind::Const(box ConstItem { defaultness, rhs, .. }) => {
|
||||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
if !rhs_kind.has_expr() {
|
if rhs.is_none() {
|
||||||
self.dcx().emit_err(errors::ConstWithoutBody {
|
self.dcx().emit_err(errors::ConstWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
replace_span: self.ending_semi_or_hi(item.span),
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if ident.name == kw::Underscore
|
|
||||||
&& !matches!(item.vis.kind, VisibilityKind::Inherited)
|
|
||||||
&& ident.span.eq_ctxt(item.vis.span)
|
|
||||||
{
|
|
||||||
self.lint_buffer.buffer_lint(
|
|
||||||
UNUSED_VISIBILITIES,
|
|
||||||
item.id,
|
|
||||||
item.vis.span,
|
|
||||||
BuiltinLintDiag::UnusedVisibility(item.vis.span),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
visit::walk_item(self, item);
|
visit::walk_item(self, item);
|
||||||
}
|
}
|
||||||
ItemKind::Static(box StaticItem { expr, safety, .. }) => {
|
ItemKind::Static(box StaticItem { expr, safety, .. }) => {
|
||||||
|
|
@ -1442,7 +1366,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
ItemKind::TyAlias(
|
ItemKind::TyAlias(
|
||||||
ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
|
ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
|
||||||
) => {
|
) => {
|
||||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
if ty.is_none() {
|
if ty.is_none() {
|
||||||
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
|
|
@ -1472,7 +1396,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||||
match &fi.kind {
|
match &fi.kind {
|
||||||
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
||||||
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(fi.span, *defaultness);
|
||||||
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
||||||
self.check_foreign_fn_headerless(sig.header);
|
self.check_foreign_fn_headerless(sig.header);
|
||||||
self.check_foreign_item_ascii_only(*ident);
|
self.check_foreign_item_ascii_only(*ident);
|
||||||
|
|
@ -1492,7 +1416,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
ty,
|
ty,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(fi.span, *defaultness);
|
||||||
self.check_foreign_kind_bodyless(*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_type_no_bounds(bounds, "`extern` blocks");
|
||||||
self.check_foreign_ty_genericless(generics, after_where_clause);
|
self.check_foreign_ty_genericless(generics, after_where_clause);
|
||||||
|
|
@ -1751,29 +1675,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self.check_nomangle_item_asciionly(ident, item.span);
|
self.check_nomangle_item_asciionly(ident, item.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
let defaultness = item.kind.defaultness();
|
if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
|
||||||
self.check_defaultness(
|
self.check_defaultness(item.span, item.kind.defaultness());
|
||||||
item.span,
|
}
|
||||||
defaultness,
|
|
||||||
// `default` is allowed on all associated items in impls.
|
|
||||||
AllowDefault::when(matches!(ctxt, AssocCtxt::Impl { .. })),
|
|
||||||
// `final` is allowed on all associated *functions* in traits.
|
|
||||||
AllowFinal::when(
|
|
||||||
ctxt == AssocCtxt::Trait && matches!(item.kind, AssocItemKind::Fn(..)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.check_final_has_body(item, defaultness);
|
|
||||||
|
|
||||||
if let AssocCtxt::Impl { .. } = ctxt {
|
if let AssocCtxt::Impl { .. } = ctxt {
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
AssocItemKind::Const(box ConstItem { rhs_kind, .. }) => {
|
AssocItemKind::Const(box ConstItem { rhs: None, .. }) => {
|
||||||
if !rhs_kind.has_expr() {
|
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
||||||
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
span: item.span,
|
||||||
span: item.span,
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
replace_span: self.ending_semi_or_hi(item.span),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||||
if body.is_none() && !self.is_sdylib_interface {
|
if body.is_none() && !self.is_sdylib_interface {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,5 @@
|
||||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||||
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
|
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
|
||||||
use rustc_errors::msg;
|
|
||||||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
|
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::parse::{feature_err, feature_warn};
|
use rustc_session::parse::{feature_err, feature_warn};
|
||||||
|
|
@ -14,11 +13,15 @@ use crate::errors;
|
||||||
macro_rules! gate {
|
macro_rules! gate {
|
||||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
($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();
|
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
|
($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)]
|
||||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
|
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
@ -28,11 +31,13 @@ macro_rules! gate {
|
||||||
macro_rules! gate_alt {
|
macro_rules! gate_alt {
|
||||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
|
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
|
||||||
if !$has_feature && !$span.allows_unstable($name) {
|
if !$has_feature && !$span.allows_unstable($name) {
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
||||||
if !$has_feature && !$span.allows_unstable($name) {
|
if !$has_feature && !$span.allows_unstable($name) {
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
|
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
|
||||||
for note in $notes {
|
for note in $notes {
|
||||||
diag.note(*note);
|
diag.note(*note);
|
||||||
|
|
@ -125,7 +130,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||||
&self,
|
&self,
|
||||||
non_lifetime_binders,
|
non_lifetime_binders,
|
||||||
non_lt_param_spans,
|
non_lt_param_spans,
|
||||||
msg!("only lifetime parameters can be used in this context")
|
crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME(non_lifetime_binders): Const bound params are pretty broken.
|
// FIXME(non_lifetime_binders): Const bound params are pretty broken.
|
||||||
|
|
@ -155,7 +160,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
||||||
let attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
|
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||||
// Check feature gates for built-in attributes.
|
// Check feature gates for built-in attributes.
|
||||||
if let Some(BuiltinAttribute {
|
if let Some(BuiltinAttribute {
|
||||||
gate: AttributeGate::Gated { feature, message, check, notes, .. },
|
gate: AttributeGate::Gated { feature, message, check, notes, .. },
|
||||||
|
|
@ -249,14 +254,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => {
|
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => {
|
||||||
self.check_impl_trait(ty, false)
|
self.check_impl_trait(ty, false)
|
||||||
}
|
}
|
||||||
ast::ItemKind::Const(box ast::ConstItem {
|
|
||||||
rhs_kind: ast::ConstItemRhsKind::TypeConst { .. },
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
// Make sure this is only allowed if the feature gate is enabled.
|
|
||||||
// #![feature(min_generic_const_args)]
|
|
||||||
gate!(&self, min_generic_const_args, i.span, "top-level `type const` are unstable");
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -304,12 +301,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
visit::walk_ty(self, ty)
|
visit::walk_ty(self, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_where_predicate_kind(&mut self, kind: &'a ast::WherePredicateKind) {
|
fn visit_generics(&mut self, g: &'a ast::Generics) {
|
||||||
if let ast::WherePredicateKind::BoundPredicate(bound) = kind {
|
for predicate in &g.where_clause.predicates {
|
||||||
// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
match &predicate.kind {
|
||||||
self.check_late_bound_lifetime_defs(&bound.bound_generic_params);
|
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);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
visit::walk_where_predicate_kind(self, kind);
|
visit::walk_generics(self, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
|
fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
|
||||||
|
|
@ -337,13 +339,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
|
|
||||||
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
||||||
match e.kind {
|
match e.kind {
|
||||||
ast::ExprKind::TryBlock(_, None) => {
|
ast::ExprKind::TryBlock(_) => {
|
||||||
// `try { ... }` is old and is only gated post-expansion here.
|
|
||||||
gate!(&self, try_blocks, e.span, "`try` expression is experimental");
|
gate!(&self, try_blocks, e.span, "`try` expression is experimental");
|
||||||
}
|
}
|
||||||
ast::ExprKind::TryBlock(_, Some(_)) => {
|
|
||||||
// `try_blocks_heterogeneous` is new, and gated pre-expansion instead.
|
|
||||||
}
|
|
||||||
ast::ExprKind::Lit(token::Lit {
|
ast::ExprKind::Lit(token::Lit {
|
||||||
kind: token::LitKind::Float | token::LitKind::Integer,
|
kind: token::LitKind::Float | token::LitKind::Integer,
|
||||||
suffix,
|
suffix,
|
||||||
|
|
@ -426,20 +424,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
ast::AssocItemKind::Const(box ast::ConstItem {
|
|
||||||
rhs_kind: ast::ConstItemRhsKind::TypeConst { .. },
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
// Make sure this is only allowed if the feature gate is enabled.
|
|
||||||
// #![feature(min_generic_const_args)]
|
|
||||||
gate!(
|
|
||||||
&self,
|
|
||||||
min_generic_const_args,
|
|
||||||
i.span,
|
|
||||||
"associated `type const` are unstable"
|
|
||||||
);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if let ast::Defaultness::Default(_) = i.kind.defaultness() {
|
if let ast::Defaultness::Default(_) = i.kind.defaultness() {
|
||||||
|
|
@ -459,7 +443,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
maybe_stage_features(sess, features, krate);
|
maybe_stage_features(sess, features, krate);
|
||||||
check_incompatible_features(sess, features);
|
check_incompatible_features(sess, features);
|
||||||
check_dependent_features(sess, features);
|
|
||||||
check_new_solver_banned_features(sess, features);
|
check_new_solver_banned_features(sess, features);
|
||||||
|
|
||||||
let mut visitor = PostExpansionVisitor { sess, features };
|
let mut visitor = PostExpansionVisitor { sess, features };
|
||||||
|
|
@ -505,6 +488,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
|
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
|
||||||
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
|
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
|
||||||
{
|
{
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
// Emit yield_expr as the error, since that will be sufficient. You can think of it
|
// Emit yield_expr as the error, since that will be sufficient. You can think of it
|
||||||
// as coroutines and gen_blocks imply yield_expr.
|
// as coroutines and gen_blocks imply yield_expr.
|
||||||
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
|
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
|
||||||
|
|
@ -518,7 +502,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
half_open_range_patterns_in_slices,
|
half_open_range_patterns_in_slices,
|
||||||
"half-open range patterns in slices are unstable"
|
"half-open range patterns in slices are unstable"
|
||||||
);
|
);
|
||||||
gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental");
|
gate_all!(associated_const_equality, "associated const equality is incomplete");
|
||||||
gate_all!(yeet_expr, "`do yeet` expression is experimental");
|
gate_all!(yeet_expr, "`do yeet` expression is experimental");
|
||||||
gate_all!(const_closures, "const closures are experimental");
|
gate_all!(const_closures, "const closures are experimental");
|
||||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||||
|
|
@ -530,44 +514,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||||
gate_all!(postfix_match, "postfix match is experimental");
|
gate_all!(postfix_match, "postfix match is experimental");
|
||||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||||
gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental");
|
|
||||||
// associated_const_equality is stabilized as part of min_generic_const_args
|
|
||||||
if let Some(spans) = spans.get(&sym::associated_const_equality) {
|
|
||||||
for span in spans {
|
|
||||||
if !visitor.features.min_generic_const_args()
|
|
||||||
&& !span.allows_unstable(sym::min_generic_const_args)
|
|
||||||
{
|
|
||||||
feature_err(
|
|
||||||
&visitor.sess,
|
|
||||||
sym::min_generic_const_args,
|
|
||||||
*span,
|
|
||||||
"associated const equality is incomplete",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `mgca_type_const_syntax` is part of `min_generic_const_args` so either
|
|
||||||
// or both are enabled we don't need to emit a feature error.
|
|
||||||
if let Some(spans) = spans.get(&sym::mgca_type_const_syntax) {
|
|
||||||
for span in spans {
|
|
||||||
if visitor.features.min_generic_const_args()
|
|
||||||
|| visitor.features.mgca_type_const_syntax()
|
|
||||||
|| span.allows_unstable(sym::min_generic_const_args)
|
|
||||||
|| span.allows_unstable(sym::mgca_type_const_syntax)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
feature_err(
|
|
||||||
&visitor.sess,
|
|
||||||
sym::min_generic_const_args,
|
|
||||||
*span,
|
|
||||||
"`type const` syntax is experimental",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gate_all!(global_registration, "global registration is experimental");
|
gate_all!(global_registration, "global registration is experimental");
|
||||||
gate_all!(return_type_notation, "return type notation is experimental");
|
gate_all!(return_type_notation, "return type notation is experimental");
|
||||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||||
|
|
@ -579,8 +525,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
gate_all!(super_let, "`super let` is experimental");
|
gate_all!(super_let, "`super let` is experimental");
|
||||||
gate_all!(frontmatter, "frontmatters are experimental");
|
gate_all!(frontmatter, "frontmatters are experimental");
|
||||||
gate_all!(coroutines, "coroutine syntax is experimental");
|
gate_all!(coroutines, "coroutine syntax is experimental");
|
||||||
gate_all!(const_block_items, "const block items are experimental");
|
|
||||||
gate_all!(final_associated_functions, "`final` on trait functions is experimental");
|
|
||||||
|
|
||||||
if !visitor.features.never_patterns() {
|
if !visitor.features.never_patterns() {
|
||||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||||
|
|
@ -595,6 +539,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
if let Ok(snippet) = sm.span_to_snippet(span)
|
if let Ok(snippet) = sm.span_to_snippet(span)
|
||||||
&& snippet == "!"
|
&& snippet == "!"
|
||||||
{
|
{
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
|
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
|
||||||
.emit();
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -691,27 +636,6 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_dependent_features(sess: &Session, features: &Features) {
|
|
||||||
for &(parent, children) in
|
|
||||||
rustc_feature::DEPENDENT_FEATURES.iter().filter(|(parent, _)| features.enabled(*parent))
|
|
||||||
{
|
|
||||||
if children.iter().any(|f| !features.enabled(*f)) {
|
|
||||||
let parent_span = features
|
|
||||||
.enabled_features_iter_stable_order()
|
|
||||||
.find_map(|(name, span)| (name == parent).then_some(span))
|
|
||||||
.unwrap();
|
|
||||||
// FIXME: should probably format this in fluent instead of here
|
|
||||||
let missing = children
|
|
||||||
.iter()
|
|
||||||
.filter(|f| !features.enabled(**f))
|
|
||||||
.map(|s| format!("`{}`", s.as_str()))
|
|
||||||
.intersperse(String::from(", "))
|
|
||||||
.collect();
|
|
||||||
sess.dcx().emit_err(errors::MissingDependentFeatures { parent_span, parent, missing });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_new_solver_banned_features(sess: &Session, features: &Features) {
|
fn check_new_solver_banned_features(sess: &Session, features: &Features) {
|
||||||
if !sess.opts.unstable_opts.next_solver.globally {
|
if !sess.opts.unstable_opts.next_solver.globally {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(iter_intersperse)]
|
|
||||||
#![feature(iter_is_partitioned)]
|
#![feature(iter_is_partitioned)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
pub mod ast_validation;
|
pub mod ast_validation;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub mod feature_gate;
|
pub mod feature_gate;
|
||||||
|
|
||||||
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,6 @@ pub fn where_bound_predicate_to_string(where_bound_predicate: &ast::WhereBoundPr
|
||||||
State::new().where_bound_predicate_to_string(where_bound_predicate)
|
State::new().where_bound_predicate_to_string(where_bound_predicate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if `pat.kind` is `PatKind::Missing`.
|
|
||||||
pub fn pat_to_string(pat: &ast::Pat) -> String {
|
pub fn pat_to_string(pat: &ast::Pat) -> String {
|
||||||
State::new().pat_to_string(pat)
|
State::new().pat_to_string(pat)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use std::borrow::Cow;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustc_ast::attr::AttrIdGenerator;
|
use rustc_ast::attr::AttrIdGenerator;
|
||||||
use rustc_ast::token::{self, CommentKind, Delimiter, DocFragmentKind, Token, TokenKind};
|
use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
|
||||||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||||
use rustc_ast::util::classify;
|
use rustc_ast::util::classify;
|
||||||
use rustc_ast::util::comments::{Comment, CommentStyle};
|
use rustc_ast::util::comments::{Comment, CommentStyle};
|
||||||
|
|
@ -381,24 +381,15 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn doc_comment_to_string(
|
pub fn doc_comment_to_string(
|
||||||
fragment_kind: DocFragmentKind,
|
comment_kind: CommentKind,
|
||||||
attr_style: ast::AttrStyle,
|
attr_style: ast::AttrStyle,
|
||||||
data: Symbol,
|
data: Symbol,
|
||||||
) -> String {
|
) -> String {
|
||||||
match fragment_kind {
|
match (comment_kind, attr_style) {
|
||||||
DocFragmentKind::Sugared(comment_kind) => match (comment_kind, attr_style) {
|
(CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"),
|
||||||
(CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"),
|
(CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"),
|
||||||
(CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"),
|
(CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"),
|
||||||
(CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"),
|
(CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"),
|
||||||
(CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"),
|
|
||||||
},
|
|
||||||
DocFragmentKind::Raw(_) => {
|
|
||||||
format!(
|
|
||||||
"#{}[doc = {:?}]",
|
|
||||||
if attr_style == ast::AttrStyle::Inner { "!" } else { "" },
|
|
||||||
data.to_string(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -674,11 +665,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
self.word("]");
|
self.word("]");
|
||||||
}
|
}
|
||||||
ast::AttrKind::DocComment(comment_kind, data) => {
|
ast::AttrKind::DocComment(comment_kind, data) => {
|
||||||
self.word(doc_comment_to_string(
|
self.word(doc_comment_to_string(*comment_kind, attr.style, *data));
|
||||||
DocFragmentKind::Sugared(*comment_kind),
|
|
||||||
attr.style,
|
|
||||||
*data,
|
|
||||||
));
|
|
||||||
self.hardbreak()
|
self.hardbreak()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -694,7 +681,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
}
|
}
|
||||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||||
}
|
}
|
||||||
match &item.args.unparsed_ref().expect("Parsed attributes are never printed") {
|
match &item.args {
|
||||||
AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
|
AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
|
||||||
Some(MacHeader::Path(&item.path)),
|
Some(MacHeader::Path(&item.path)),
|
||||||
false,
|
false,
|
||||||
|
|
@ -865,17 +852,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
sp: Span,
|
sp: Span,
|
||||||
print_visibility: impl FnOnce(&mut Self),
|
print_visibility: impl FnOnce(&mut Self),
|
||||||
) {
|
) {
|
||||||
if let Some(eii_decl) = ¯o_def.eii_declaration {
|
|
||||||
self.word("#[eii_declaration(");
|
|
||||||
self.print_path(&eii_decl.foreign_item, false, 0);
|
|
||||||
if eii_decl.impl_unsafe {
|
|
||||||
self.word(",");
|
|
||||||
self.space();
|
|
||||||
self.word("unsafe");
|
|
||||||
}
|
|
||||||
self.word(")]");
|
|
||||||
self.hardbreak();
|
|
||||||
}
|
|
||||||
let (kw, has_bang) = if macro_def.macro_rules {
|
let (kw, has_bang) = if macro_def.macro_rules {
|
||||||
("macro_rules", true)
|
("macro_rules", true)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1053,8 +1029,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
|
|
||||||
/* Other */
|
/* Other */
|
||||||
token::DocComment(comment_kind, attr_style, data) => {
|
token::DocComment(comment_kind, attr_style, data) => {
|
||||||
doc_comment_to_string(DocFragmentKind::Sugared(comment_kind), attr_style, data)
|
doc_comment_to_string(comment_kind, attr_style, data).into()
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
token::Eof => "<eof>".into(),
|
token::Eof => "<eof>".into(),
|
||||||
}
|
}
|
||||||
|
|
@ -1961,8 +1936,7 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
|
fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
|
||||||
self.word(lifetime.ident.name.to_string());
|
self.print_name(lifetime.ident.name)
|
||||||
self.ann_post(lifetime.ident)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
|
fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
|
||||||
|
|
@ -2174,15 +2148,6 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
fn print_meta_item(&mut self, item: &ast::MetaItem) {
|
fn print_meta_item(&mut self, item: &ast::MetaItem) {
|
||||||
let ib = self.ibox(INDENT_UNIT);
|
let ib = self.ibox(INDENT_UNIT);
|
||||||
|
|
||||||
match item.unsafety {
|
|
||||||
ast::Safety::Unsafe(_) => {
|
|
||||||
self.word("unsafe");
|
|
||||||
self.popen();
|
|
||||||
}
|
|
||||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
|
ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
|
||||||
ast::MetaItemKind::NameValue(value) => {
|
ast::MetaItemKind::NameValue(value) => {
|
||||||
|
|
@ -2198,12 +2163,6 @@ impl<'a> State<'a> {
|
||||||
self.pclose();
|
self.pclose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match item.unsafety {
|
|
||||||
ast::Safety::Unsafe(_) => self.pclose(),
|
|
||||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.end(ib);
|
self.end(ib);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -818,15 +818,10 @@ impl<'a> State<'a> {
|
||||||
);
|
);
|
||||||
self.word("?")
|
self.word("?")
|
||||||
}
|
}
|
||||||
ast::ExprKind::TryBlock(blk, opt_ty) => {
|
ast::ExprKind::TryBlock(blk) => {
|
||||||
let cb = self.cbox(0);
|
let cb = self.cbox(0);
|
||||||
let ib = self.ibox(0);
|
let ib = self.ibox(0);
|
||||||
self.word_nbsp("try");
|
self.word_nbsp("try");
|
||||||
if let Some(ty) = opt_ty {
|
|
||||||
self.word_nbsp("bikeshed");
|
|
||||||
self.print_type(ty);
|
|
||||||
self.space();
|
|
||||||
}
|
|
||||||
self.print_block_with_attrs(blk, attrs, cb, ib)
|
self.print_block_with_attrs(blk, attrs, cb, ib)
|
||||||
}
|
}
|
||||||
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use ast::StaticItem;
|
use ast::StaticItem;
|
||||||
use itertools::{Itertools, Position};
|
use itertools::{Itertools, Position};
|
||||||
use rustc_ast::{self as ast, EiiImpl, ModKind, Safety, TraitAlias};
|
use rustc_ast::{self as ast, ModKind, TraitAlias};
|
||||||
use rustc_span::Ident;
|
use rustc_span::Ident;
|
||||||
|
|
||||||
use crate::pp::BoxMarker;
|
use crate::pp::BoxMarker;
|
||||||
|
|
@ -51,7 +51,7 @@ impl<'a> State<'a> {
|
||||||
expr.as_deref(),
|
expr.as_deref(),
|
||||||
vis,
|
vis,
|
||||||
*safety,
|
*safety,
|
||||||
ast::Defaultness::Implicit,
|
ast::Defaultness::Final,
|
||||||
define_opaque.as_deref(),
|
define_opaque.as_deref(),
|
||||||
),
|
),
|
||||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||||
|
|
@ -201,27 +201,16 @@ impl<'a> State<'a> {
|
||||||
body.as_deref(),
|
body.as_deref(),
|
||||||
&item.vis,
|
&item.vis,
|
||||||
ast::Safety::Default,
|
ast::Safety::Default,
|
||||||
ast::Defaultness::Implicit,
|
ast::Defaultness::Final,
|
||||||
define_opaque.as_deref(),
|
define_opaque.as_deref(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
|
|
||||||
let ib = self.ibox(INDENT_UNIT);
|
|
||||||
self.word("const");
|
|
||||||
self.nbsp();
|
|
||||||
{
|
|
||||||
let cb = self.cbox(0);
|
|
||||||
let ib = self.ibox(0);
|
|
||||||
self.print_block_with_attrs(block, &[], cb, ib);
|
|
||||||
}
|
|
||||||
self.end(ib);
|
|
||||||
}
|
|
||||||
ast::ItemKind::Const(box ast::ConstItem {
|
ast::ItemKind::Const(box ast::ConstItem {
|
||||||
defaultness,
|
defaultness,
|
||||||
ident,
|
ident,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
rhs_kind,
|
rhs,
|
||||||
define_opaque,
|
define_opaque,
|
||||||
}) => {
|
}) => {
|
||||||
self.print_item_const(
|
self.print_item_const(
|
||||||
|
|
@ -229,7 +218,7 @@ impl<'a> State<'a> {
|
||||||
None,
|
None,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
rhs_kind.expr(),
|
rhs.as_ref().map(|ct| ct.expr()),
|
||||||
&item.vis,
|
&item.vis,
|
||||||
ast::Safety::Default,
|
ast::Safety::Default,
|
||||||
*defaultness,
|
*defaultness,
|
||||||
|
|
@ -573,7 +562,7 @@ impl<'a> State<'a> {
|
||||||
ident,
|
ident,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
rhs_kind,
|
rhs,
|
||||||
define_opaque,
|
define_opaque,
|
||||||
}) => {
|
}) => {
|
||||||
self.print_item_const(
|
self.print_item_const(
|
||||||
|
|
@ -581,7 +570,7 @@ impl<'a> State<'a> {
|
||||||
None,
|
None,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
rhs_kind.expr(),
|
rhs.as_ref().map(|ct| ct.expr()),
|
||||||
vis,
|
vis,
|
||||||
ast::Safety::Default,
|
ast::Safety::Default,
|
||||||
*defaultness,
|
*defaultness,
|
||||||
|
|
@ -682,25 +671,10 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], func: &ast::Fn) {
|
fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], func: &ast::Fn) {
|
||||||
let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impls } =
|
let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque } = func;
|
||||||
func;
|
|
||||||
|
|
||||||
self.print_define_opaques(define_opaque.as_deref());
|
self.print_define_opaques(define_opaque.as_deref());
|
||||||
|
|
||||||
for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls {
|
|
||||||
self.word("#[");
|
|
||||||
if let Safety::Unsafe(..) = impl_safety {
|
|
||||||
self.word("unsafe");
|
|
||||||
self.popen();
|
|
||||||
}
|
|
||||||
self.print_path(eii_macro_path, false, 0);
|
|
||||||
if let Safety::Unsafe(..) = impl_safety {
|
|
||||||
self.pclose();
|
|
||||||
}
|
|
||||||
self.word("]");
|
|
||||||
self.hardbreak();
|
|
||||||
}
|
|
||||||
|
|
||||||
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
|
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
|
||||||
|
|
||||||
self.print_visibility(vis);
|
self.print_visibility(vis);
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ edition = "2024"
|
||||||
rustc_abi = { path = "../rustc_abi" }
|
rustc_abi = { path = "../rustc_abi" }
|
||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_lexer = { path = "../rustc_lexer" }
|
rustc_lexer = { path = "../rustc_lexer" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
|
|
|
||||||
268
compiler/rustc_attr_parsing/messages.ftl
Normal file
268
compiler/rustc_attr_parsing/messages.ftl
Normal file
|
|
@ -0,0 +1,268 @@
|
||||||
|
attr_parsing_as_needed_compatibility =
|
||||||
|
linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds
|
||||||
|
|
||||||
|
attr_parsing_bundle_needs_static =
|
||||||
|
linking modifier `bundle` is only compatible with `static` linking kind
|
||||||
|
|
||||||
|
attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
|
||||||
|
|
||||||
|
attr_parsing_cfg_predicate_identifier =
|
||||||
|
`cfg` predicate key must be an identifier
|
||||||
|
|
||||||
|
attr_parsing_deprecated_item_suggestion =
|
||||||
|
suggestions on deprecated items are unstable
|
||||||
|
.help = add `#![feature(deprecated_suggestion)]` to the crate root
|
||||||
|
.note = see #94785 for more details
|
||||||
|
|
||||||
|
attr_parsing_empty_attribute =
|
||||||
|
unused attribute
|
||||||
|
.suggestion = {$valid_without_list ->
|
||||||
|
[true] remove these parentheses
|
||||||
|
*[other] remove this attribute
|
||||||
|
}
|
||||||
|
.note = {$valid_without_list ->
|
||||||
|
[true] using `{$attr_path}` with an empty list is equivalent to not using a list at all
|
||||||
|
*[other] using `{$attr_path}` with an empty list has no effect
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
attr_parsing_empty_confusables =
|
||||||
|
expected at least one confusable name
|
||||||
|
attr_parsing_empty_link_name =
|
||||||
|
link name must not be empty
|
||||||
|
.label = empty link name
|
||||||
|
|
||||||
|
attr_parsing_expected_one_cfg_pattern =
|
||||||
|
expected 1 cfg-pattern
|
||||||
|
|
||||||
|
attr_parsing_expected_single_version_literal =
|
||||||
|
expected single version literal
|
||||||
|
|
||||||
|
attr_parsing_expected_version_literal =
|
||||||
|
expected a version literal
|
||||||
|
|
||||||
|
attr_parsing_expects_feature_list =
|
||||||
|
`{$name}` expects a list of feature names
|
||||||
|
|
||||||
|
attr_parsing_expects_features =
|
||||||
|
`{$name}` expects feature names
|
||||||
|
|
||||||
|
attr_parsing_ill_formed_attribute_input = {$num_suggestions ->
|
||||||
|
[1] attribute must be of the form {$suggestions}
|
||||||
|
*[other] valid forms for the attribute are {$suggestions}
|
||||||
|
}
|
||||||
|
|
||||||
|
attr_parsing_import_name_type_raw =
|
||||||
|
import name type can only be used with link kind `raw-dylib`
|
||||||
|
|
||||||
|
attr_parsing_import_name_type_x86 =
|
||||||
|
import name type is only supported on x86
|
||||||
|
|
||||||
|
attr_parsing_incompatible_wasm_link =
|
||||||
|
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_align_one_arg =
|
||||||
|
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_expect_literal_integer =
|
||||||
|
incorrect `repr(align)` attribute format: `align` expects a literal integer as argument
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_generic =
|
||||||
|
incorrect `repr({$repr_arg})` attribute format
|
||||||
|
.suggestion = use parentheses instead
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_packed_expect_integer =
|
||||||
|
incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_packed_one_or_zero_arg =
|
||||||
|
incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
|
||||||
|
|
||||||
|
attr_parsing_invalid_alignment_value =
|
||||||
|
invalid alignment value: {$error_part}
|
||||||
|
|
||||||
|
attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
|
||||||
|
.label = this is not an unsafe attribute
|
||||||
|
.suggestion = remove the `unsafe(...)`
|
||||||
|
.note = extraneous unsafe is not allowed in attributes
|
||||||
|
|
||||||
|
attr_parsing_invalid_issue_string =
|
||||||
|
`issue` must be a non-zero numeric string or "none"
|
||||||
|
.must_not_be_zero = `issue` must not be "0", use "none" instead
|
||||||
|
.empty = cannot parse integer from empty string
|
||||||
|
.invalid_digit = invalid digit found in string
|
||||||
|
.pos_overflow = number too large to fit in target type
|
||||||
|
.neg_overflow = number too small to fit in target type
|
||||||
|
|
||||||
|
attr_parsing_invalid_link_modifier =
|
||||||
|
invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
|
||||||
|
|
||||||
|
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
|
||||||
|
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
|
||||||
|
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
|
||||||
|
|
||||||
|
attr_parsing_invalid_predicate =
|
||||||
|
invalid predicate `{$predicate}`
|
||||||
|
|
||||||
|
attr_parsing_invalid_repr_align_need_arg =
|
||||||
|
invalid `repr(align)` attribute: `align` needs an argument
|
||||||
|
.suggestion = supply an argument here
|
||||||
|
|
||||||
|
attr_parsing_invalid_repr_generic =
|
||||||
|
invalid `repr({$repr_arg})` attribute: {$error_part}
|
||||||
|
|
||||||
|
attr_parsing_invalid_repr_hint_no_paren =
|
||||||
|
invalid representation hint: `{$name}` does not take a parenthesized argument list
|
||||||
|
|
||||||
|
attr_parsing_invalid_repr_hint_no_value =
|
||||||
|
invalid representation hint: `{$name}` does not take a value
|
||||||
|
|
||||||
|
attr_parsing_invalid_since =
|
||||||
|
'since' must be a Rust version number, such as "1.31.0"
|
||||||
|
|
||||||
|
attr_parsing_invalid_style = {$is_used_as_inner ->
|
||||||
|
[false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]`
|
||||||
|
*[other] the `#![{$name}]` attribute can only be used at the crate root
|
||||||
|
}
|
||||||
|
.note = This attribute does not have an `!`, which means it is applied to this {$target}
|
||||||
|
|
||||||
|
attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target}
|
||||||
|
.help = `#[{$name}]` can {$only}be applied to {$applied}
|
||||||
|
.suggestion = remove the attribute
|
||||||
|
attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target}
|
||||||
|
.warn = {-attr_parsing_previously_accepted}
|
||||||
|
.help = `#[{$name}]` can {$only}be applied to {$applied}
|
||||||
|
.suggestion = remove the attribute
|
||||||
|
|
||||||
|
attr_parsing_limit_invalid =
|
||||||
|
`limit` must be a non-negative integer
|
||||||
|
.label = {$error_str}
|
||||||
|
attr_parsing_link_arg_unstable =
|
||||||
|
link kind `link-arg` is unstable
|
||||||
|
|
||||||
|
attr_parsing_link_cfg_unstable =
|
||||||
|
link cfg is unstable
|
||||||
|
|
||||||
|
attr_parsing_link_framework_apple =
|
||||||
|
link kind `framework` is only supported on Apple targets
|
||||||
|
|
||||||
|
attr_parsing_link_ordinal_out_of_range = ordinal value in `link_ordinal` is too large: `{$ordinal}`
|
||||||
|
.note = the value may not exceed `u16::MAX`
|
||||||
|
|
||||||
|
attr_parsing_link_requires_name =
|
||||||
|
`#[link]` attribute requires a `name = "string"` argument
|
||||||
|
.label = missing `name` argument
|
||||||
|
|
||||||
|
attr_parsing_meta_bad_delim = wrong meta list delimiters
|
||||||
|
attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
|
||||||
|
|
||||||
|
attr_parsing_missing_feature =
|
||||||
|
missing 'feature'
|
||||||
|
|
||||||
|
attr_parsing_missing_issue =
|
||||||
|
missing 'issue'
|
||||||
|
|
||||||
|
attr_parsing_missing_note =
|
||||||
|
missing 'note'
|
||||||
|
|
||||||
|
attr_parsing_missing_since =
|
||||||
|
missing 'since'
|
||||||
|
|
||||||
|
attr_parsing_multiple_modifiers =
|
||||||
|
multiple `{$modifier}` modifiers in a single `modifiers` argument
|
||||||
|
|
||||||
|
attr_parsing_multiple_stability_levels =
|
||||||
|
multiple stability levels
|
||||||
|
|
||||||
|
attr_parsing_naked_functions_incompatible_attribute =
|
||||||
|
attribute incompatible with `#[unsafe(naked)]`
|
||||||
|
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
|
||||||
|
.naked_attribute = function marked with `#[unsafe(naked)]` here
|
||||||
|
|
||||||
|
attr_parsing_non_ident_feature =
|
||||||
|
'feature' is not an identifier
|
||||||
|
|
||||||
|
attr_parsing_null_on_export = `export_name` may not contain null characters
|
||||||
|
|
||||||
|
attr_parsing_null_on_link_section = `link_section` may not contain null characters
|
||||||
|
|
||||||
|
attr_parsing_null_on_objc_class = `objc::class!` may not contain null characters
|
||||||
|
|
||||||
|
attr_parsing_null_on_objc_selector = `objc::selector!` may not contain null characters
|
||||||
|
|
||||||
|
attr_parsing_objc_class_expected_string_literal = `objc::class!` expected a string literal
|
||||||
|
|
||||||
|
attr_parsing_objc_selector_expected_string_literal = `objc::selector!` expected a string literal
|
||||||
|
|
||||||
|
attr_parsing_raw_dylib_elf_unstable =
|
||||||
|
link kind `raw-dylib` is unstable on ELF platforms
|
||||||
|
|
||||||
|
attr_parsing_raw_dylib_no_nul =
|
||||||
|
link name must not contain NUL characters if link kind is `raw-dylib`
|
||||||
|
|
||||||
|
attr_parsing_raw_dylib_only_windows =
|
||||||
|
link kind `raw-dylib` is only supported on Windows targets
|
||||||
|
|
||||||
|
attr_parsing_repr_ident =
|
||||||
|
meta item in `repr` must be an identifier
|
||||||
|
|
||||||
|
attr_parsing_rustc_allowed_unstable_pairing =
|
||||||
|
`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
|
||||||
|
|
||||||
|
attr_parsing_rustc_promotable_pairing =
|
||||||
|
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
|
||||||
|
|
||||||
|
attr_parsing_soft_no_args =
|
||||||
|
`soft` should not have any arguments
|
||||||
|
|
||||||
|
attr_parsing_stability_outside_std = stability attributes may not be used outside of the standard library
|
||||||
|
|
||||||
|
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
|
||||||
|
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||||
|
|
||||||
|
attr_parsing_unknown_meta_item =
|
||||||
|
unknown meta item '{$item}'
|
||||||
|
.label = expected one of {$expected}
|
||||||
|
|
||||||
|
attr_parsing_unknown_version_literal =
|
||||||
|
unknown version literal format, assuming it refers to a future version
|
||||||
|
|
||||||
|
attr_parsing_unrecognized_repr_hint =
|
||||||
|
unrecognized representation hint
|
||||||
|
.help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
|
||||||
|
.note = for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
|
||||||
|
|
||||||
|
attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||||
|
.label = usage of unsafe attribute
|
||||||
|
attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||||
|
|
||||||
|
attr_parsing_unstable_cfg_target_compact =
|
||||||
|
compact `cfg(target(..))` is experimental and subject to change
|
||||||
|
|
||||||
|
attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable
|
||||||
|
.help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||||
|
|
||||||
|
attr_parsing_unsupported_literal_cfg_boolean =
|
||||||
|
literal in `cfg` predicate value must be a boolean
|
||||||
|
attr_parsing_unsupported_literal_cfg_string =
|
||||||
|
literal in `cfg` predicate value must be a string
|
||||||
|
attr_parsing_unsupported_literal_generic =
|
||||||
|
unsupported literal
|
||||||
|
attr_parsing_unsupported_literal_suggestion =
|
||||||
|
consider removing the prefix
|
||||||
|
|
||||||
|
attr_parsing_unused_duplicate =
|
||||||
|
unused attribute
|
||||||
|
.suggestion = remove this attribute
|
||||||
|
.note = attribute also specified here
|
||||||
|
.warn = {-attr_parsing_previously_accepted}
|
||||||
|
|
||||||
|
attr_parsing_unused_multiple =
|
||||||
|
multiple `{$name}` attributes
|
||||||
|
.suggestion = remove this attribute
|
||||||
|
.note = attribute also specified here
|
||||||
|
|
||||||
|
-attr_parsing_previously_accepted =
|
||||||
|
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
|
||||||
|
attr_parsing_whole_archive_needs_static =
|
||||||
|
linking modifier `whole-archive` is only compatible with `static` linking kind
|
||||||
|
|
@ -17,9 +17,9 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
||||||
]);
|
]);
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
||||||
|
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
) -> impl IntoIterator<Item = Self::Item> {
|
||||||
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -29,7 +29,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
||||||
|
|
||||||
pub(crate) struct UnstableFeatureBoundParser;
|
pub(crate) struct UnstableFeatureBoundParser;
|
||||||
impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
|
impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
|
||||||
const PATH: &[rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
||||||
type Item = (Symbol, Span);
|
type Item = (Symbol, Span);
|
||||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
|
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
|
|
@ -39,9 +39,9 @@ impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
|
||||||
]);
|
]);
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
||||||
|
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
) -> impl IntoIterator<Item = Self::Item> {
|
||||||
if !cx.features().staged_api() {
|
if !cx.features().staged_api() {
|
||||||
cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span });
|
cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span });
|
||||||
|
|
@ -57,26 +57,27 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||||
type Item = Symbol;
|
type Item = Symbol;
|
||||||
const CONVERT: ConvertFn<Self::Item> =
|
const CONVERT: ConvertFn<Self::Item> =
|
||||||
|items, first_span| AttributeKind::RustcAllowConstFnUnstable(items, first_span);
|
|items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
Allow(Target::Fn),
|
Allow(Target::Fn),
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
|
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
]);
|
]);
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
||||||
|
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||||
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unstable<S: Stage>(
|
fn parse_unstable<S: Stage>(
|
||||||
cx: &AcceptContext<'_, '_, S>,
|
cx: &AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &ArgParser<'_>,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
) -> impl IntoIterator<Item = Symbol> {
|
) -> impl IntoIterator<Item = Symbol> {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,16 @@ use std::convert::identity;
|
||||||
|
|
||||||
use rustc_ast::token::Delimiter;
|
use rustc_ast::token::Delimiter;
|
||||||
use rustc_ast::tokenstream::DelimSpan;
|
use rustc_ast::tokenstream::DelimSpan;
|
||||||
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
|
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token};
|
||||||
use rustc_errors::{Applicability, PResult, msg};
|
use rustc_errors::{Applicability, PResult};
|
||||||
use rustc_feature::{
|
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template};
|
||||||
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
|
|
||||||
};
|
|
||||||
use rustc_hir::attrs::CfgEntry;
|
use rustc_hir::attrs::CfgEntry;
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
use rustc_hir::{AttrPath, RustcVersion};
|
||||||
use rustc_hir::{AttrPath, RustcVersion, Target};
|
use rustc_parse::parser::{ForceCollect, Parser};
|
||||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
|
||||||
use rustc_parse::{exp, parse_in};
|
use rustc_parse::{exp, parse_in};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::config::ExpectedValues;
|
use rustc_session::config::ExpectedValues;
|
||||||
|
use rustc_session::lint::BuiltinLintDiag;
|
||||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||||
use rustc_session::parse::{ParseSess, feature_err};
|
use rustc_session::parse::{ParseSess, feature_err};
|
||||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
||||||
|
|
@ -25,7 +23,10 @@ use crate::session_diagnostics::{
|
||||||
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
|
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
|
||||||
ParsedDescription,
|
ParsedDescription,
|
||||||
};
|
};
|
||||||
use crate::{AttributeParser, parse_version, session_diagnostics};
|
use crate::{
|
||||||
|
AttributeParser, CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics,
|
||||||
|
try_gate_cfg,
|
||||||
|
};
|
||||||
|
|
||||||
pub const CFG_TEMPLATE: AttributeTemplate = template!(
|
pub const CFG_TEMPLATE: AttributeTemplate = template!(
|
||||||
List: &["predicate"],
|
List: &["predicate"],
|
||||||
|
|
@ -37,12 +38,12 @@ const CFG_ATTR_TEMPLATE: AttributeTemplate = template!(
|
||||||
"https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute"
|
"https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
pub fn parse_cfg<S: Stage>(
|
pub fn parse_cfg<'c, S: Stage>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> Option<CfgEntry> {
|
) -> Option<CfgEntry> {
|
||||||
let ArgParser::List(list) = args else {
|
let ArgParser::List(list) = args else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let Some(single) = list.single() else {
|
let Some(single) = list.single() else {
|
||||||
|
|
@ -54,7 +55,7 @@ pub fn parse_cfg<S: Stage>(
|
||||||
|
|
||||||
pub fn parse_cfg_entry<S: Stage>(
|
pub fn parse_cfg_entry<S: Stage>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
item: &MetaItemOrLitParser,
|
item: &MetaItemOrLitParser<'_>,
|
||||||
) -> Result<CfgEntry, ErrorGuaranteed> {
|
) -> Result<CfgEntry, ErrorGuaranteed> {
|
||||||
Ok(match item {
|
Ok(match item {
|
||||||
MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() {
|
MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() {
|
||||||
|
|
@ -94,12 +95,13 @@ pub fn parse_cfg_entry<S: Stage>(
|
||||||
LitKind::Bool(b) => CfgEntry::Bool(b, lit.span),
|
LitKind::Bool(b) => CfgEntry::Bool(b, lit.span),
|
||||||
_ => return Err(cx.expected_identifier(lit.span)),
|
_ => return Err(cx.expected_identifier(lit.span)),
|
||||||
},
|
},
|
||||||
|
MetaItemOrLitParser::Err(_, err) => return Err(*err),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cfg_entry_version<S: Stage>(
|
fn parse_cfg_entry_version<S: Stage>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
list: &MetaItemListParser,
|
list: &MetaItemListParser<'_>,
|
||||||
meta_span: Span,
|
meta_span: Span,
|
||||||
) -> Result<CfgEntry, ErrorGuaranteed> {
|
) -> Result<CfgEntry, ErrorGuaranteed> {
|
||||||
try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option());
|
try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option());
|
||||||
|
|
@ -131,7 +133,7 @@ fn parse_cfg_entry_version<S: Stage>(
|
||||||
|
|
||||||
fn parse_cfg_entry_target<S: Stage>(
|
fn parse_cfg_entry_target<S: Stage>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
list: &MetaItemListParser,
|
list: &MetaItemListParser<'_>,
|
||||||
meta_span: Span,
|
meta_span: Span,
|
||||||
) -> Result<CfgEntry, ErrorGuaranteed> {
|
) -> Result<CfgEntry, ErrorGuaranteed> {
|
||||||
if let Some(features) = cx.features_option()
|
if let Some(features) = cx.features_option()
|
||||||
|
|
@ -141,7 +143,7 @@ fn parse_cfg_entry_target<S: Stage>(
|
||||||
cx.sess(),
|
cx.sess(),
|
||||||
sym::cfg_target_compact,
|
sym::cfg_target_compact,
|
||||||
meta_span,
|
meta_span,
|
||||||
msg!("compact `cfg(target(..))` is experimental and subject to change"),
|
fluent_generated::attr_parsing_unstable_cfg_target_compact,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +174,7 @@ fn parse_cfg_entry_target<S: Stage>(
|
||||||
Ok(CfgEntry::All(result, list.span))
|
Ok(CfgEntry::All(result, list.span))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_name_value<S: Stage>(
|
fn parse_name_value<S: Stage>(
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
name_span: Span,
|
name_span: Span,
|
||||||
value: Option<&NameValueParser>,
|
value: Option<&NameValueParser>,
|
||||||
|
|
@ -193,46 +195,43 @@ pub(crate) fn parse_name_value<S: Stage>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match cx.sess.psess.check_config.expecteds.get(&name) {
|
Ok(CfgEntry::NameValue { name, name_span, value, span })
|
||||||
Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => cx
|
|
||||||
.emit_lint(
|
|
||||||
UNEXPECTED_CFGS,
|
|
||||||
AttributeLintKind::UnexpectedCfgValue((name, name_span), value),
|
|
||||||
span,
|
|
||||||
),
|
|
||||||
None if cx.sess.psess.check_config.exhaustive_names => cx.emit_lint(
|
|
||||||
UNEXPECTED_CFGS,
|
|
||||||
AttributeLintKind::UnexpectedCfgName((name, name_span), value),
|
|
||||||
span,
|
|
||||||
),
|
|
||||||
_ => { /* not unexpected */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(CfgEntry::NameValue { name, value: value.map(|(v, _)| v), span })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_config_entry(sess: &Session, cfg_entry: &CfgEntry) -> EvalConfigResult {
|
pub fn eval_config_entry(
|
||||||
|
sess: &Session,
|
||||||
|
cfg_entry: &CfgEntry,
|
||||||
|
id: NodeId,
|
||||||
|
emit_lints: ShouldEmit,
|
||||||
|
) -> EvalConfigResult {
|
||||||
match cfg_entry {
|
match cfg_entry {
|
||||||
CfgEntry::All(subs, ..) => {
|
CfgEntry::All(subs, ..) => {
|
||||||
|
let mut all = None;
|
||||||
for sub in subs {
|
for sub in subs {
|
||||||
let res = eval_config_entry(sess, sub);
|
let res = eval_config_entry(sess, sub, id, emit_lints);
|
||||||
|
// We cannot short-circuit because `eval_config_entry` emits some lints
|
||||||
if !res.as_bool() {
|
if !res.as_bool() {
|
||||||
return res;
|
all.get_or_insert(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EvalConfigResult::True
|
all.unwrap_or_else(|| EvalConfigResult::True)
|
||||||
}
|
}
|
||||||
CfgEntry::Any(subs, span) => {
|
CfgEntry::Any(subs, span) => {
|
||||||
|
let mut any = None;
|
||||||
for sub in subs {
|
for sub in subs {
|
||||||
let res = eval_config_entry(sess, sub);
|
let res = eval_config_entry(sess, sub, id, emit_lints);
|
||||||
|
// We cannot short-circuit because `eval_config_entry` emits some lints
|
||||||
if res.as_bool() {
|
if res.as_bool() {
|
||||||
return res;
|
any.get_or_insert(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
|
any.unwrap_or_else(|| EvalConfigResult::False {
|
||||||
|
reason: cfg_entry.clone(),
|
||||||
|
reason_span: *span,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
CfgEntry::Not(sub, span) => {
|
CfgEntry::Not(sub, span) => {
|
||||||
if eval_config_entry(sess, sub).as_bool() {
|
if eval_config_entry(sess, sub, id, emit_lints).as_bool() {
|
||||||
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
|
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
|
||||||
} else {
|
} else {
|
||||||
EvalConfigResult::True
|
EvalConfigResult::True
|
||||||
|
|
@ -245,8 +244,32 @@ pub fn eval_config_entry(sess: &Session, cfg_entry: &CfgEntry) -> EvalConfigResu
|
||||||
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
|
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CfgEntry::NameValue { name, value, span } => {
|
CfgEntry::NameValue { name, name_span, value, span } => {
|
||||||
if sess.psess.config.contains(&(*name, *value)) {
|
if let ShouldEmit::ErrorsAndLints = emit_lints {
|
||||||
|
match sess.psess.check_config.expecteds.get(name) {
|
||||||
|
Some(ExpectedValues::Some(values))
|
||||||
|
if !values.contains(&value.map(|(v, _)| v)) =>
|
||||||
|
{
|
||||||
|
id.emit_span_lint(
|
||||||
|
sess,
|
||||||
|
UNEXPECTED_CFGS,
|
||||||
|
*span,
|
||||||
|
BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None if sess.psess.check_config.exhaustive_names => {
|
||||||
|
id.emit_span_lint(
|
||||||
|
sess,
|
||||||
|
UNEXPECTED_CFGS,
|
||||||
|
*span,
|
||||||
|
BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => { /* not unexpected */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) {
|
||||||
EvalConfigResult::True
|
EvalConfigResult::True
|
||||||
} else {
|
} else {
|
||||||
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
|
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
|
||||||
|
|
@ -293,9 +316,11 @@ pub fn parse_cfg_attr(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
features: Option<&Features>,
|
features: Option<&Features>,
|
||||||
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
|
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
|
||||||
match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() {
|
match cfg_attr.get_normal_item().args {
|
||||||
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => {
|
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
|
||||||
check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim);
|
if !tokens.is_empty() =>
|
||||||
|
{
|
||||||
|
check_cfg_attr_bad_delim(&sess.psess, dspan, delim);
|
||||||
match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
|
match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
|
||||||
parse_cfg_attr_internal(p, sess, features, cfg_attr)
|
parse_cfg_attr_internal(p, sess, features, cfg_attr)
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -319,7 +344,7 @@ pub fn parse_cfg_attr(
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) =
|
let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) =
|
||||||
cfg_attr.get_normal_item().args.unparsed_ref()?
|
cfg_attr.get_normal_item().args
|
||||||
{
|
{
|
||||||
(dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument)
|
(dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -360,10 +385,7 @@ fn parse_cfg_attr_internal<'a>(
|
||||||
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
|
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
|
||||||
// Parse cfg predicate
|
// Parse cfg predicate
|
||||||
let pred_start = parser.token.span;
|
let pred_start = parser.token.span;
|
||||||
let meta = MetaItemOrLitParser::parse_single(
|
let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?;
|
||||||
parser,
|
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
|
||||||
)?;
|
|
||||||
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
||||||
|
|
||||||
let cfg_predicate = AttributeParser::parse_single_args(
|
let cfg_predicate = AttributeParser::parse_single_args(
|
||||||
|
|
@ -371,14 +393,19 @@ fn parse_cfg_attr_internal<'a>(
|
||||||
attribute.span,
|
attribute.span,
|
||||||
attribute.get_normal_item().span(),
|
attribute.get_normal_item().span(),
|
||||||
attribute.style,
|
attribute.style,
|
||||||
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
|
AttrPath {
|
||||||
|
segments: attribute
|
||||||
|
.ident_path()
|
||||||
|
.expect("cfg_attr is not a doc comment")
|
||||||
|
.into_boxed_slice(),
|
||||||
|
span: attribute.span,
|
||||||
|
},
|
||||||
Some(attribute.get_normal_item().unsafety),
|
Some(attribute.get_normal_item().unsafety),
|
||||||
ParsedDescription::Attribute,
|
ParsedDescription::Attribute,
|
||||||
pred_span,
|
pred_span,
|
||||||
CRATE_NODE_ID,
|
CRATE_NODE_ID,
|
||||||
Target::Crate,
|
|
||||||
features,
|
features,
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
ShouldEmit::ErrorsAndLints,
|
||||||
&meta,
|
&meta,
|
||||||
parse_cfg_entry,
|
parse_cfg_entry,
|
||||||
&CFG_ATTR_TEMPLATE,
|
&CFG_ATTR_TEMPLATE,
|
||||||
|
|
@ -407,18 +434,3 @@ fn parse_cfg_attr_internal<'a>(
|
||||||
|
|
||||||
Ok((cfg_predicate, expanded_attrs))
|
Ok((cfg_predicate, expanded_attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) {
|
|
||||||
let gate = find_gated_cfg(|sym| sym == name);
|
|
||||||
if let (Some(feats), Some(gated_cfg)) = (features, gate) {
|
|
||||||
gate_cfg(gated_cfg, span, sess, feats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
|
|
||||||
let (cfg, feature, has_feature) = gated_cfg;
|
|
||||||
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
|
|
||||||
let explain = format!("`cfg({cfg})` is experimental and subject to change");
|
|
||||||
feature_err(sess, *feature, cfg_span, explain).emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
250
compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
Normal file
250
compiler/rustc_attr_parsing/src/attributes/cfg_old.rs
Normal file
|
|
@ -0,0 +1,250 @@
|
||||||
|
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId};
|
||||||
|
use rustc_ast_pretty::pprust;
|
||||||
|
use rustc_feature::{Features, GatedCfg, find_gated_cfg};
|
||||||
|
use rustc_hir::RustcVersion;
|
||||||
|
use rustc_session::Session;
|
||||||
|
use rustc_session::config::ExpectedValues;
|
||||||
|
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||||
|
use rustc_session::lint::{BuiltinLintDiag, Lint};
|
||||||
|
use rustc_session::parse::feature_err;
|
||||||
|
use rustc_span::{Span, Symbol, sym};
|
||||||
|
|
||||||
|
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
|
||||||
|
use crate::{fluent_generated, parse_version};
|
||||||
|
|
||||||
|
/// Emitter of a builtin lint from `cfg_matches`.
|
||||||
|
///
|
||||||
|
/// Used to support emitting a lint (currently on check-cfg), either:
|
||||||
|
/// - as an early buffered lint (in `rustc`)
|
||||||
|
/// - or has a "normal" lint from HIR (in `rustdoc`)
|
||||||
|
pub trait CfgMatchesLintEmitter {
|
||||||
|
fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CfgMatchesLintEmitter for NodeId {
|
||||||
|
fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) {
|
||||||
|
sess.psess.buffer_lint(lint, sp, *self, diag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Condition {
|
||||||
|
pub name: Symbol,
|
||||||
|
pub name_span: Span,
|
||||||
|
pub value: Option<Symbol>,
|
||||||
|
pub value_span: Option<Span>,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tests if a cfg-pattern matches the cfg set
|
||||||
|
pub fn cfg_matches(
|
||||||
|
cfg: &MetaItemInner,
|
||||||
|
sess: &Session,
|
||||||
|
lint_emitter: impl CfgMatchesLintEmitter,
|
||||||
|
features: Option<&Features>,
|
||||||
|
) -> bool {
|
||||||
|
eval_condition(cfg, sess, features, &mut |cfg| {
|
||||||
|
try_gate_cfg(cfg.name, cfg.span, sess, features);
|
||||||
|
match sess.psess.check_config.expecteds.get(&cfg.name) {
|
||||||
|
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
|
||||||
|
lint_emitter.emit_span_lint(
|
||||||
|
sess,
|
||||||
|
UNEXPECTED_CFGS,
|
||||||
|
cfg.span,
|
||||||
|
BuiltinLintDiag::UnexpectedCfgValue(
|
||||||
|
(cfg.name, cfg.name_span),
|
||||||
|
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None if sess.psess.check_config.exhaustive_names => {
|
||||||
|
lint_emitter.emit_span_lint(
|
||||||
|
sess,
|
||||||
|
UNEXPECTED_CFGS,
|
||||||
|
cfg.span,
|
||||||
|
BuiltinLintDiag::UnexpectedCfgName(
|
||||||
|
(cfg.name, cfg.name_span),
|
||||||
|
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => { /* not unexpected */ }
|
||||||
|
}
|
||||||
|
sess.psess.config.contains(&(cfg.name, cfg.value))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) {
|
||||||
|
let gate = find_gated_cfg(|sym| sym == name);
|
||||||
|
if let (Some(feats), Some(gated_cfg)) = (features, gate) {
|
||||||
|
gate_cfg(gated_cfg, span, sess, feats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
|
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
|
||||||
|
let (cfg, feature, has_feature) = gated_cfg;
|
||||||
|
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
|
||||||
|
let explain = format!("`cfg({cfg})` is experimental and subject to change");
|
||||||
|
feature_err(sess, *feature, cfg_span, explain).emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
|
||||||
|
/// evaluate individual items.
|
||||||
|
pub fn eval_condition(
|
||||||
|
cfg: &MetaItemInner,
|
||||||
|
sess: &Session,
|
||||||
|
features: Option<&Features>,
|
||||||
|
eval: &mut impl FnMut(Condition) -> bool,
|
||||||
|
) -> bool {
|
||||||
|
let dcx = sess.dcx();
|
||||||
|
|
||||||
|
let cfg = match cfg {
|
||||||
|
MetaItemInner::MetaItem(meta_item) => meta_item,
|
||||||
|
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
|
||||||
|
return *b;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||||
|
span: cfg.span(),
|
||||||
|
reason: UnsupportedLiteralReason::CfgBoolean,
|
||||||
|
is_bytestr: false,
|
||||||
|
start_point_span: sess.source_map().start_point(cfg.span()),
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match &cfg.kind {
|
||||||
|
MetaItemKind::List(mis) if cfg.has_name(sym::version) => {
|
||||||
|
try_gate_cfg(sym::version, cfg.span, sess, features);
|
||||||
|
let (min_version, span) = match &mis[..] {
|
||||||
|
[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
|
||||||
|
(sym, span)
|
||||||
|
}
|
||||||
|
[
|
||||||
|
MetaItemInner::Lit(MetaItemLit { span, .. })
|
||||||
|
| MetaItemInner::MetaItem(MetaItem { span, .. }),
|
||||||
|
] => {
|
||||||
|
dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
[..] => {
|
||||||
|
dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
|
||||||
|
span: cfg.span,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let Some(min_version) = parse_version(*min_version) else {
|
||||||
|
dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span });
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
|
||||||
|
if sess.psess.assume_incomplete_release {
|
||||||
|
RustcVersion::current_overridable() > min_version
|
||||||
|
} else {
|
||||||
|
RustcVersion::current_overridable() >= min_version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MetaItemKind::List(mis) => {
|
||||||
|
for mi in mis.iter() {
|
||||||
|
if mi.meta_item_or_bool().is_none() {
|
||||||
|
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||||
|
span: mi.span(),
|
||||||
|
reason: UnsupportedLiteralReason::Generic,
|
||||||
|
is_bytestr: false,
|
||||||
|
start_point_span: sess.source_map().start_point(mi.span()),
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The unwraps below may look dangerous, but we've already asserted
|
||||||
|
// that they won't fail with the loop above.
|
||||||
|
match cfg.name() {
|
||||||
|
Some(sym::any) => mis
|
||||||
|
.iter()
|
||||||
|
// We don't use any() here, because we want to evaluate all cfg condition
|
||||||
|
// as eval_condition can (and does) extra checks
|
||||||
|
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
|
||||||
|
Some(sym::all) => mis
|
||||||
|
.iter()
|
||||||
|
// We don't use all() here, because we want to evaluate all cfg condition
|
||||||
|
// as eval_condition can (and does) extra checks
|
||||||
|
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
|
||||||
|
Some(sym::not) => {
|
||||||
|
let [mi] = mis.as_slice() else {
|
||||||
|
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
!eval_condition(mi, sess, features, eval)
|
||||||
|
}
|
||||||
|
Some(sym::target) => {
|
||||||
|
if let Some(features) = features
|
||||||
|
&& !features.cfg_target_compact()
|
||||||
|
{
|
||||||
|
feature_err(
|
||||||
|
sess,
|
||||||
|
sym::cfg_target_compact,
|
||||||
|
cfg.span,
|
||||||
|
fluent_generated::attr_parsing_unstable_cfg_target_compact,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
mis.iter().fold(true, |res, mi| {
|
||||||
|
let Some(mut mi) = mi.meta_item().cloned() else {
|
||||||
|
dcx.emit_err(session_diagnostics::CfgPredicateIdentifier {
|
||||||
|
span: mi.span(),
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let [seg, ..] = &mut mi.path.segments[..] {
|
||||||
|
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
dcx.emit_err(session_diagnostics::InvalidPredicate {
|
||||||
|
span: cfg.span,
|
||||||
|
predicate: pprust::path_to_string(&cfg.path),
|
||||||
|
});
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MetaItemKind::Word | MetaItemKind::NameValue(..)
|
||||||
|
if cfg.path.segments.len() != 1
|
||||||
|
|| cfg.path.segments[0].ident.is_path_segment_keyword() =>
|
||||||
|
{
|
||||||
|
dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
|
||||||
|
true
|
||||||
|
}
|
||||||
|
MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
|
||||||
|
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||||
|
span: lit.span,
|
||||||
|
reason: UnsupportedLiteralReason::CfgString,
|
||||||
|
is_bytestr: lit.kind.is_bytestr(),
|
||||||
|
start_point_span: sess.source_map().start_point(lit.span),
|
||||||
|
});
|
||||||
|
true
|
||||||
|
}
|
||||||
|
MetaItemKind::Word | MetaItemKind::NameValue(..) => {
|
||||||
|
let ident = cfg.ident().expect("multi-segment cfg predicate");
|
||||||
|
eval(Condition {
|
||||||
|
name: ident.name,
|
||||||
|
name_span: ident.span,
|
||||||
|
value: cfg.value_str(),
|
||||||
|
value_span: cfg.name_value_literal_span(),
|
||||||
|
span: cfg.span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,35 +1,22 @@
|
||||||
use rustc_ast::token::Token;
|
use rustc_ast::token::Token;
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_ast::{AttrStyle, NodeId, token};
|
use rustc_ast::{AttrStyle, NodeId, token};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
|
||||||
use rustc_feature::{AttributeTemplate, Features};
|
use rustc_feature::{AttributeTemplate, Features};
|
||||||
|
use rustc_hir::AttrPath;
|
||||||
use rustc_hir::attrs::CfgEntry;
|
use rustc_hir::attrs::CfgEntry;
|
||||||
use rustc_hir::{AttrPath, Target};
|
|
||||||
use rustc_parse::exp;
|
use rustc_parse::exp;
|
||||||
use rustc_parse::parser::{Parser, Recovery};
|
use rustc_parse::parser::Parser;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::lint::BuiltinLintDiag;
|
use rustc_span::{ErrorGuaranteed, Ident, Span};
|
||||||
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
|
|
||||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
|
||||||
|
|
||||||
use crate::parser::MetaItemOrLitParser;
|
use crate::parser::MetaItemOrLitParser;
|
||||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum CfgSelectPredicate {
|
pub enum CfgSelectPredicate {
|
||||||
Cfg(CfgEntry),
|
Cfg(CfgEntry),
|
||||||
Wildcard(Token),
|
Wildcard(Token),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CfgSelectPredicate {
|
|
||||||
fn span(&self) -> Span {
|
|
||||||
match self {
|
|
||||||
CfgSelectPredicate::Cfg(cfg_entry) => cfg_entry.span(),
|
|
||||||
CfgSelectPredicate::Wildcard(token) => token.span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CfgSelectBranches {
|
pub struct CfgSelectBranches {
|
||||||
/// All the conditional branches.
|
/// All the conditional branches.
|
||||||
|
|
@ -41,33 +28,6 @@ pub struct CfgSelectBranches {
|
||||||
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
|
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CfgSelectBranches {
|
|
||||||
/// Removes the top-most branch for which `predicate` returns `true`,
|
|
||||||
/// or the wildcard if none of the reachable branches satisfied the predicate.
|
|
||||||
pub fn pop_first_match<F>(&mut self, predicate: F) -> Option<(TokenStream, Span)>
|
|
||||||
where
|
|
||||||
F: Fn(&CfgEntry) -> bool,
|
|
||||||
{
|
|
||||||
for (index, (cfg, _, _)) in self.reachable.iter().enumerate() {
|
|
||||||
if predicate(cfg) {
|
|
||||||
let matched = self.reachable.remove(index);
|
|
||||||
return Some((matched.1, matched.2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.wildcard.take().map(|(_, tts, span)| (tts, span))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consume this value and iterate over all the `TokenStream`s that it stores.
|
|
||||||
pub fn into_iter_tts(self) -> impl Iterator<Item = (TokenStream, Span)> {
|
|
||||||
let it1 = self.reachable.into_iter().map(|(_, tts, span)| (tts, span));
|
|
||||||
let it2 = self.wildcard.into_iter().map(|(_, tts, span)| (tts, span));
|
|
||||||
let it3 = self.unreachable.into_iter().map(|(_, tts, span)| (tts, span));
|
|
||||||
|
|
||||||
it1.chain(it2).chain(it3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_cfg_select(
|
pub fn parse_cfg_select(
|
||||||
p: &mut Parser<'_>,
|
p: &mut Parser<'_>,
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
|
|
@ -91,26 +51,24 @@ pub fn parse_cfg_select(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let meta = MetaItemOrLitParser::parse_single(
|
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
|
||||||
p,
|
.map_err(|diag| diag.emit())?;
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
|
||||||
)
|
|
||||||
.map_err(|diag| diag.emit())?;
|
|
||||||
let cfg_span = meta.span();
|
let cfg_span = meta.span();
|
||||||
let cfg = AttributeParser::parse_single_args(
|
let cfg = AttributeParser::parse_single_args(
|
||||||
sess,
|
sess,
|
||||||
cfg_span,
|
cfg_span,
|
||||||
cfg_span,
|
cfg_span,
|
||||||
AttrStyle::Inner,
|
AttrStyle::Inner,
|
||||||
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
|
AttrPath {
|
||||||
|
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
|
||||||
|
span: cfg_span,
|
||||||
|
},
|
||||||
None,
|
None,
|
||||||
ParsedDescription::Macro,
|
ParsedDescription::Macro,
|
||||||
cfg_span,
|
cfg_span,
|
||||||
lint_node_id,
|
lint_node_id,
|
||||||
// Doesn't matter what the target actually is here.
|
|
||||||
Target::Crate,
|
|
||||||
features,
|
features,
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
ShouldEmit::ErrorsAndLints,
|
||||||
&meta,
|
&meta,
|
||||||
parse_cfg_entry,
|
parse_cfg_entry,
|
||||||
&AttributeTemplate::default(),
|
&AttributeTemplate::default(),
|
||||||
|
|
@ -128,102 +86,5 @@ pub fn parse_cfg_select(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(features) = features
|
|
||||||
&& features.enabled(sym::cfg_select)
|
|
||||||
{
|
|
||||||
let it = branches
|
|
||||||
.reachable
|
|
||||||
.iter()
|
|
||||||
.map(|(entry, _, _)| CfgSelectPredicate::Cfg(entry.clone()))
|
|
||||||
.chain(branches.wildcard.as_ref().map(|(t, _, _)| CfgSelectPredicate::Wildcard(*t)))
|
|
||||||
.chain(
|
|
||||||
branches.unreachable.iter().map(|(entry, _, _)| CfgSelectPredicate::clone(entry)),
|
|
||||||
);
|
|
||||||
|
|
||||||
lint_unreachable(p, it, lint_node_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(branches)
|
Ok(branches)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_unreachable(
|
|
||||||
p: &mut Parser<'_>,
|
|
||||||
predicates: impl Iterator<Item = CfgSelectPredicate>,
|
|
||||||
lint_node_id: NodeId,
|
|
||||||
) {
|
|
||||||
// Symbols that have a known value.
|
|
||||||
let mut known = FxHashMap::<Symbol, bool>::default();
|
|
||||||
let mut wildcard_span = None;
|
|
||||||
let mut it = predicates;
|
|
||||||
|
|
||||||
let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| {
|
|
||||||
let span = predicate.span();
|
|
||||||
p.psess.buffer_lint(
|
|
||||||
UNREACHABLE_CFG_SELECT_PREDICATES,
|
|
||||||
span,
|
|
||||||
lint_node_id,
|
|
||||||
BuiltinLintDiag::UnreachableCfg { span, wildcard_span },
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
for predicate in &mut it {
|
|
||||||
let CfgSelectPredicate::Cfg(ref cfg_entry) = predicate else {
|
|
||||||
wildcard_span = Some(predicate.span());
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
match cfg_entry {
|
|
||||||
CfgEntry::Bool(true, _) => {
|
|
||||||
wildcard_span = Some(predicate.span());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
CfgEntry::Bool(false, _) => continue,
|
|
||||||
CfgEntry::NameValue { name, value, .. } => match value {
|
|
||||||
None => {
|
|
||||||
// `name` will be false in all subsequent branches.
|
|
||||||
let current = known.insert(*name, false);
|
|
||||||
|
|
||||||
match current {
|
|
||||||
None => continue,
|
|
||||||
Some(false) => {
|
|
||||||
branch_is_unreachable(predicate, None);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Some(true) => {
|
|
||||||
// this branch will be taken, so all subsequent branches are unreachable.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(_) => { /* for now we don't bother solving these */ }
|
|
||||||
},
|
|
||||||
CfgEntry::Not(inner, _) => match &**inner {
|
|
||||||
CfgEntry::NameValue { name, value: None, .. } => {
|
|
||||||
// `name` will be true in all subsequent branches.
|
|
||||||
let current = known.insert(*name, true);
|
|
||||||
|
|
||||||
match current {
|
|
||||||
None => continue,
|
|
||||||
Some(true) => {
|
|
||||||
branch_is_unreachable(predicate, None);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Some(false) => {
|
|
||||||
// this branch will be taken, so all subsequent branches are unreachable.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => { /* for now we don't bother solving these */ }
|
|
||||||
},
|
|
||||||
CfgEntry::All(_, _) | CfgEntry::Any(_, _) => {
|
|
||||||
/* for now we don't bother solving these */
|
|
||||||
}
|
|
||||||
CfgEntry::Version(..) => { /* don't bother solving these */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for predicate in it {
|
|
||||||
branch_is_unreachable(predicate, wildcard_span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
use super::prelude::*;
|
|
||||||
pub(crate) struct CfiEncodingParser;
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for CfiEncodingParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::cfi_encoding];
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
|
||||||
Allow(Target::Struct),
|
|
||||||
Allow(Target::ForeignTy),
|
|
||||||
Allow(Target::Enum),
|
|
||||||
Allow(Target::Union),
|
|
||||||
]);
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding");
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(name_value) = args.name_value() else {
|
|
||||||
cx.expected_name_value(cx.attr_span, Some(sym::cfi_encoding));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(value_str) = name_value.value_as_str() else {
|
|
||||||
cx.expected_string_literal(name_value.value_span, None);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
if value_str.as_str().trim().is_empty() {
|
|
||||||
cx.expected_non_empty_string_literal(name_value.value_span);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(AttributeKind::CfiEncoding { encoding: value_str })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -23,9 +23,9 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
||||||
]);
|
]);
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
|
const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(list) = args.list() else {
|
let Some(list) = args.list() else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -57,6 +57,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
|
||||||
Allow(Target::Fn),
|
Allow(Target::Fn),
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
|
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
Allow(Target::ForeignFn),
|
Allow(Target::ForeignFn),
|
||||||
Allow(Target::Closure),
|
Allow(Target::Closure),
|
||||||
|
|
@ -83,7 +84,7 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
|
||||||
]);
|
]);
|
||||||
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
|
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(args) = args.list() else {
|
let Some(args) = args.list() else {
|
||||||
cx.expected_specific_argument_and_list(cx.attr_span, &[sym::on, sym::off]);
|
cx.expected_specific_argument_and_list(cx.attr_span, &[sym::on, sym::off]);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -134,7 +135,7 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
|
||||||
]);
|
]);
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(nv) = args.name_value() else {
|
let Some(nv) = args.name_value() else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -163,7 +164,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser {
|
||||||
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
|
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName");
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(nv) = args.name_value() else {
|
let Some(nv) = args.name_value() else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -181,7 +182,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser {
|
||||||
cx.emit_err(NullOnObjcClass { span: nv.value_span });
|
cx.emit_err(NullOnObjcClass { span: nv.value_span });
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(AttributeKind::RustcObjcClass { classname, span: cx.attr_span })
|
Some(AttributeKind::ObjcClass { classname, span: cx.attr_span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,7 +196,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcSelectorParser {
|
||||||
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
|
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(nv) = args.name_value() else {
|
let Some(nv) = args.name_value() else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -213,7 +214,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcSelectorParser {
|
||||||
cx.emit_err(NullOnObjcSelector { span: nv.value_span });
|
cx.emit_err(NullOnObjcSelector { span: nv.value_span });
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(AttributeKind::RustcObjcSelector { methname, span: cx.attr_span })
|
Some(AttributeKind::ObjcSelector { methname, span: cx.attr_span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,7 +343,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
Allow(Target::Method(MethodKind::Trait { body: false })), // `#[track_caller]` is inherited from trait methods
|
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||||
Allow(Target::ForeignFn),
|
Allow(Target::ForeignFn),
|
||||||
Allow(Target::Closure),
|
Allow(Target::Closure),
|
||||||
Warn(Target::MacroDef),
|
Warn(Target::MacroDef),
|
||||||
|
|
@ -471,13 +472,13 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_tf_attribute<S: Stage>(
|
fn parse_tf_attribute<'c, S: Stage>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = (Symbol, Span)> {
|
) -> impl IntoIterator<Item = (Symbol, Span)> + 'c {
|
||||||
let mut features = Vec::new();
|
let mut features = Vec::new();
|
||||||
let ArgParser::List(list) = args else {
|
let ArgParser::List(list) = args else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return features;
|
return features;
|
||||||
};
|
};
|
||||||
if list.is_empty() {
|
if list.is_empty() {
|
||||||
|
|
@ -528,10 +529,10 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
||||||
};
|
};
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
||||||
|
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||||
parse_tf_attribute(cx, args)
|
parse_tf_attribute(cx, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -566,10 +567,10 @@ impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||||
parse_tf_attribute(cx, args)
|
parse_tf_attribute(cx, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -598,9 +599,9 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(list) = args.list() else {
|
let Some(list) = args.list() else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -690,16 +691,6 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ThreadLocalParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for ThreadLocalParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::thread_local];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
|
pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisParser {
|
||||||
|
|
@ -708,109 +699,3 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisPa
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct EiiForeignItemParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for EiiForeignItemParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiForeignItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct PatchableFunctionEntryParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for PatchableFunctionEntryParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::patchable_function_entry];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(meta_item_list) = args.list() else {
|
|
||||||
cx.expected_list(cx.attr_span, args);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut prefix = None;
|
|
||||||
let mut entry = None;
|
|
||||||
|
|
||||||
if meta_item_list.len() == 0 {
|
|
||||||
cx.expected_list(meta_item_list.span, args);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut errored = false;
|
|
||||||
|
|
||||||
for item in meta_item_list.mixed() {
|
|
||||||
let Some(meta_item) = item.meta_item() else {
|
|
||||||
errored = true;
|
|
||||||
cx.expected_name_value(item.span(), None);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(name_value_lit) = meta_item.args().name_value() else {
|
|
||||||
errored = true;
|
|
||||||
cx.expected_name_value(item.span(), None);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let attrib_to_write = match meta_item.ident().map(|ident| ident.name) {
|
|
||||||
Some(sym::prefix_nops) => {
|
|
||||||
// Duplicate prefixes are not allowed
|
|
||||||
if prefix.is_some() {
|
|
||||||
errored = true;
|
|
||||||
cx.duplicate_key(meta_item.path().span(), sym::prefix_nops);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
&mut prefix
|
|
||||||
}
|
|
||||||
Some(sym::entry_nops) => {
|
|
||||||
// Duplicate entries are not allowed
|
|
||||||
if entry.is_some() {
|
|
||||||
errored = true;
|
|
||||||
cx.duplicate_key(meta_item.path().span(), sym::entry_nops);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
&mut entry
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
errored = true;
|
|
||||||
cx.expected_specific_argument(
|
|
||||||
meta_item.path().span(),
|
|
||||||
&[sym::prefix_nops, sym::entry_nops],
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let rustc_ast::LitKind::Int(val, _) = name_value_lit.value_as_lit().kind else {
|
|
||||||
errored = true;
|
|
||||||
cx.expected_integer_literal(name_value_lit.value_span);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(val) = val.get().try_into() else {
|
|
||||||
errored = true;
|
|
||||||
cx.expected_integer_literal_in_range(
|
|
||||||
name_value_lit.value_span,
|
|
||||||
u8::MIN as isize,
|
|
||||||
u8::MAX as isize,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
*attrib_to_write = Some(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
if errored {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(AttributeKind::PatchableFunctionEntry {
|
|
||||||
prefix: prefix.unwrap_or(0),
|
|
||||||
entry: entry.unwrap_or(0),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||||
template!(List: &[r#""name1", "name2", ..."#]),
|
template!(List: &[r#""name1", "name2", ..."#]),
|
||||||
|this, cx, args| {
|
|this, cx, args| {
|
||||||
let Some(list) = args.list() else {
|
let Some(list) = args.list() else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(AttributeKind::RustcConfusables {
|
Some(AttributeKind::Confusables {
|
||||||
symbols: self.confusables,
|
symbols: self.confusables,
|
||||||
first_span: self.first_span.unwrap(),
|
first_span: self.first_span.unwrap(),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
|
use rustc_hir::attrs::WindowsSubsystemKind;
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
|
||||||
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
|
|
||||||
use rustc_span::Symbol;
|
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
||||||
|
|
@ -13,9 +9,9 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let ArgParser::NameValue(n) = args else {
|
let ArgParser::NameValue(n) = args else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -30,56 +26,6 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CrateTypeParser;
|
|
||||||
|
|
||||||
impl<S: Stage> CombineAttributeParser<S> for CrateTypeParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::crate_type];
|
|
||||||
type Item = CrateType;
|
|
||||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::CrateType(items);
|
|
||||||
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
|
|
||||||
const TEMPLATE: AttributeTemplate =
|
|
||||||
template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html");
|
|
||||||
|
|
||||||
fn extend(
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
args: &ArgParser,
|
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
|
||||||
let ArgParser::NameValue(n) = args else {
|
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(crate_type) = n.value_as_str() else {
|
|
||||||
cx.expected_string_literal(n.value_span, Some(n.value_as_lit()));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(crate_type) = crate_type.try_into() else {
|
|
||||||
// We don't error on invalid `#![crate_type]` when not applied to a crate
|
|
||||||
if cx.shared.target == Target::Crate {
|
|
||||||
let candidate = find_best_match_for_name(
|
|
||||||
&CrateType::all_stable().iter().map(|(name, _)| *name).collect::<Vec<_>>(),
|
|
||||||
crate_type,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
cx.emit_lint(
|
|
||||||
UNKNOWN_CRATE_TYPES,
|
|
||||||
AttributeLintKind::CrateTypeUnknown {
|
|
||||||
span: n.value_span,
|
|
||||||
suggested: candidate,
|
|
||||||
},
|
|
||||||
n.value_span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(crate_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RecursionLimitParser;
|
pub(crate) struct RecursionLimitParser;
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
||||||
|
|
@ -87,9 +33,9 @@ impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let ArgParser::NameValue(nv) = args else {
|
let ArgParser::NameValue(nv) = args else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -110,9 +56,9 @@ impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let ArgParser::NameValue(nv) = args else {
|
let ArgParser::NameValue(nv) = args else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -133,9 +79,9 @@ impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let ArgParser::NameValue(nv) = args else {
|
let ArgParser::NameValue(nv) = args else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -156,9 +102,9 @@ impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let ArgParser::NameValue(nv) = args else {
|
let ArgParser::NameValue(nv) = args else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -177,7 +123,7 @@ pub(crate) struct NoCoreParser;
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
|
||||||
const PATH: &[Symbol] = &[sym::no_core];
|
const PATH: &[Symbol] = &[sym::no_core];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,25 +132,16 @@ pub(crate) struct NoStdParser;
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
|
||||||
const PATH: &[Symbol] = &[sym::no_std];
|
const PATH: &[Symbol] = &[sym::no_std];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct NoMainParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::no_main];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcCoherenceIsCoreParser;
|
pub(crate) struct RustcCoherenceIsCoreParser;
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
|
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,10 +151,10 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
||||||
const PATH: &[Symbol] = &[sym::windows_subsystem];
|
const PATH: &[Symbol] = &[sym::windows_subsystem];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute");
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute");
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(nv) = args.name_value() else {
|
let Some(nv) = args.name_value() else {
|
||||||
cx.expected_name_value(
|
cx.expected_name_value(
|
||||||
args.span().unwrap_or(cx.inner_span),
|
args.span().unwrap_or(cx.inner_span),
|
||||||
|
|
@ -238,66 +175,3 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
||||||
Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
|
Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PanicRuntimeParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::panic_runtime];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct NeedsPanicRuntimeParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct ProfilerRuntimeParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::profiler_runtime];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct NoBuiltinsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::no_builtins];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcPreserveUbChecksParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcPreserveUbChecksParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcNoImplicitBoundsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct DefaultLibAllocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::default_lib_allocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser {
|
||||||
type Item = DebugVisualizer;
|
type Item = DebugVisualizer;
|
||||||
const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v);
|
const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v);
|
||||||
|
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||||
let Some(l) = args.list() else {
|
let Some(l) = args.list() else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(args.span().unwrap_or(cx.attr_span));
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let Some(single) = l.single() else {
|
let Some(single) = l.single() else {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
|
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
|
||||||
use rustc_hir::{RustcVersion, VERSION_PLACEHOLDER};
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::util::parse_version;
|
use super::util::parse_version;
|
||||||
|
|
@ -13,15 +12,15 @@ fn get<S: Stage>(
|
||||||
cx: &AcceptContext<'_, '_, S>,
|
cx: &AcceptContext<'_, '_, S>,
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
param_span: Span,
|
param_span: Span,
|
||||||
arg: &ArgParser,
|
arg: &ArgParser<'_>,
|
||||||
item: Option<Symbol>,
|
item: &Option<Symbol>,
|
||||||
) -> Option<Ident> {
|
) -> Option<Symbol> {
|
||||||
if item.is_some() {
|
if item.is_some() {
|
||||||
cx.duplicate_key(param_span, name);
|
cx.duplicate_key(param_span, name);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if let Some(v) = arg.name_value() {
|
if let Some(v) = arg.name_value() {
|
||||||
if let Some(value_str) = v.value_as_ident() {
|
if let Some(value_str) = v.value_as_str() {
|
||||||
Some(value_str)
|
Some(value_str)
|
||||||
} else {
|
} else {
|
||||||
cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
|
cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
|
||||||
|
|
@ -69,11 +68,11 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
||||||
NameValueStr: "reason"
|
NameValueStr: "reason"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let features = cx.features();
|
let features = cx.features();
|
||||||
|
|
||||||
let mut since = None;
|
let mut since = None;
|
||||||
let mut note: Option<Ident> = None;
|
let mut note = None;
|
||||||
let mut suggestion = None;
|
let mut suggestion = None;
|
||||||
|
|
||||||
let is_rustc = features.staged_api();
|
let is_rustc = features.staged_api();
|
||||||
|
|
@ -93,16 +92,10 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
||||||
|
|
||||||
match ident_name {
|
match ident_name {
|
||||||
Some(name @ sym::since) => {
|
Some(name @ sym::since) => {
|
||||||
since = Some(get(cx, name, param.span(), param.args(), since)?.name);
|
since = Some(get(cx, name, param.span(), param.args(), &since)?);
|
||||||
}
|
}
|
||||||
Some(name @ sym::note) => {
|
Some(name @ sym::note) => {
|
||||||
note = Some(get(
|
note = Some(get(cx, name, param.span(), param.args(), ¬e)?);
|
||||||
cx,
|
|
||||||
name,
|
|
||||||
param.span(),
|
|
||||||
param.args(),
|
|
||||||
note.map(|ident| ident.name),
|
|
||||||
)?);
|
|
||||||
}
|
}
|
||||||
Some(name @ sym::suggestion) => {
|
Some(name @ sym::suggestion) => {
|
||||||
if !features.deprecated_suggestion() {
|
if !features.deprecated_suggestion() {
|
||||||
|
|
@ -114,15 +107,16 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
suggestion =
|
suggestion =
|
||||||
Some(get(cx, name, param.span(), param.args(), suggestion)?.name);
|
Some(get(cx, name, param.span(), param.args(), &suggestion)?);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cx.expected_specific_argument(
|
cx.unknown_key(
|
||||||
param.span(),
|
param.span(),
|
||||||
|
param.path().to_string(),
|
||||||
if features.deprecated_suggestion() {
|
if features.deprecated_suggestion() {
|
||||||
&[sym::since, sym::note, sym::suggestion]
|
&["since", "note", "suggestion"]
|
||||||
} else {
|
} else {
|
||||||
&[sym::since, sym::note]
|
&["since", "note"]
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -131,7 +125,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArgParser::NameValue(v) => {
|
ArgParser::NameValue(v) => {
|
||||||
let Some(value) = v.value_as_ident() else {
|
let Some(value) = v.value_as_str() else {
|
||||||
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
|
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
@ -144,8 +138,6 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
||||||
DeprecatedSince::Future
|
DeprecatedSince::Future
|
||||||
} else if !is_rustc {
|
} else if !is_rustc {
|
||||||
DeprecatedSince::NonStandard(since)
|
DeprecatedSince::NonStandard(since)
|
||||||
} else if since.as_str() == VERSION_PLACEHOLDER {
|
|
||||||
DeprecatedSince::RustcVersion(RustcVersion::CURRENT)
|
|
||||||
} else if let Some(version) = parse_version(since) {
|
} else if let Some(version) = parse_version(since) {
|
||||||
DeprecatedSince::RustcVersion(version)
|
DeprecatedSince::RustcVersion(version)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
use rustc_feature::{AttributeTemplate, template};
|
|
||||||
use rustc_hir::attrs::AttributeKind;
|
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
|
||||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
|
||||||
use rustc_span::{Symbol, sym};
|
|
||||||
|
|
||||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
|
||||||
use crate::context::{AcceptContext, Stage};
|
|
||||||
use crate::parser::ArgParser;
|
|
||||||
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
|
||||||
|
|
||||||
pub(crate) struct DoNotRecommendParser;
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend];
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr.
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */);
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let attr_span = cx.attr_span;
|
|
||||||
if !matches!(args, ArgParser::NoArgs) {
|
|
||||||
cx.emit_lint(
|
|
||||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DoNotRecommendDoesNotExpectArgs,
|
|
||||||
attr_span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some(AttributeKind::DoNotRecommend { attr_span })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,760 +0,0 @@
|
||||||
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
|
|
||||||
use rustc_feature::template;
|
|
||||||
use rustc_hir::Target;
|
|
||||||
use rustc_hir::attrs::{
|
|
||||||
AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow,
|
|
||||||
};
|
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
|
||||||
use rustc_span::{Span, Symbol, edition, sym};
|
|
||||||
use thin_vec::ThinVec;
|
|
||||||
|
|
||||||
use super::prelude::{ALL_TARGETS, AllowedTargets};
|
|
||||||
use super::{AcceptMapping, AttributeParser};
|
|
||||||
use crate::context::{AcceptContext, FinalizeContext, Stage};
|
|
||||||
use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser};
|
|
||||||
use crate::session_diagnostics::{
|
|
||||||
DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel,
|
|
||||||
DocAttributeNotAttribute, DocKeywordNotKeyword,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn check_keyword<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool {
|
|
||||||
// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we
|
|
||||||
// can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the
|
|
||||||
// `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`.
|
|
||||||
if keyword.is_reserved(|| edition::LATEST_STABLE_EDITION)
|
|
||||||
|| keyword.is_weak()
|
|
||||||
|| keyword == sym::SelfTy
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
cx.emit_err(DocKeywordNotKeyword { span, keyword });
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_attribute<S: Stage>(
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
attribute: Symbol,
|
|
||||||
span: Span,
|
|
||||||
) -> bool {
|
|
||||||
// FIXME: This should support attributes with namespace like `diagnostic::do_not_recommend`.
|
|
||||||
if rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&attribute) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
cx.emit_err(DocAttributeNotAttribute { span, attribute });
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
|
|
||||||
fn check_attr_not_crate_level<S: Stage>(
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
span: Span,
|
|
||||||
attr_name: Symbol,
|
|
||||||
) -> bool {
|
|
||||||
if cx.shared.target == Target::Crate {
|
|
||||||
cx.emit_err(DocAttrNotCrateLevel { span, attr_name });
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks that an attribute is used at the crate level. Returns `true` if valid.
|
|
||||||
fn check_attr_crate_level<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool {
|
|
||||||
if cx.shared.target != Target::Crate {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::AttrCrateLevelOnly,
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: To be removed once merged and replace with `cx.expected_name_value(span, _name)`.
|
|
||||||
fn expected_name_value<S: Stage>(
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
span: Span,
|
|
||||||
_name: Option<Symbol>,
|
|
||||||
) {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::ExpectedNameValue,
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead.
|
|
||||||
fn expected_no_args<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::ExpectedNoArgs,
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead.
|
|
||||||
// cx.expected_string_literal(span, _actual_literal);
|
|
||||||
fn expected_string_literal<S: Stage>(
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
span: Span,
|
|
||||||
_actual_literal: Option<&MetaItemLit>,
|
|
||||||
) {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::MalformedDoc,
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_keyword_and_attribute<S: Stage>(
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
path: &OwnedPathParser,
|
|
||||||
args: &ArgParser,
|
|
||||||
attr_value: &mut Option<(Symbol, Span)>,
|
|
||||||
attr_name: Symbol,
|
|
||||||
) {
|
|
||||||
let Some(nv) = args.name_value() else {
|
|
||||||
expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym());
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(value) = nv.value_as_str() else {
|
|
||||||
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let ret = if attr_name == sym::keyword {
|
|
||||||
check_keyword(cx, value, nv.value_span)
|
|
||||||
} else {
|
|
||||||
check_attribute(cx, value, nv.value_span)
|
|
||||||
};
|
|
||||||
if !ret {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let span = path.span();
|
|
||||||
if attr_value.is_some() {
|
|
||||||
cx.duplicate_key(span, path.word_sym().unwrap());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !check_attr_not_crate_level(cx, span, attr_name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*attr_value = Some((value, span));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
pub(crate) struct DocParser {
|
|
||||||
attribute: DocAttribute,
|
|
||||||
nb_doc_attrs: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DocParser {
|
|
||||||
fn parse_single_test_doc_attr_item<S: Stage>(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
mip: &MetaItemParser,
|
|
||||||
) {
|
|
||||||
let path = mip.path();
|
|
||||||
let args = mip.args();
|
|
||||||
|
|
||||||
match path.word_sym() {
|
|
||||||
Some(sym::no_crate_inject) => {
|
|
||||||
if let Err(span) = args.no_args() {
|
|
||||||
expected_no_args(cx, span);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(used_span) = self.attribute.no_crate_inject {
|
|
||||||
let unused_span = path.span();
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::UnusedDuplicate {
|
|
||||||
this: unused_span,
|
|
||||||
other: used_span,
|
|
||||||
warning: true,
|
|
||||||
},
|
|
||||||
unused_span,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !check_attr_crate_level(cx, path.span()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.attribute.no_crate_inject = Some(path.span())
|
|
||||||
}
|
|
||||||
Some(sym::attr) => {
|
|
||||||
let Some(list) = args.list() else {
|
|
||||||
// FIXME: remove this method once merged and uncomment the line below instead.
|
|
||||||
// cx.expected_list(cx.attr_span, args);
|
|
||||||
let span = cx.attr_span;
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::MalformedDoc,
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: convert list into a Vec of `AttributeKind` because current code is awful.
|
|
||||||
for attr in list.mixed() {
|
|
||||||
self.attribute.test_attrs.push(attr.span());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(name) => {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocTestUnknown { name },
|
|
||||||
path.span(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocTestLiteral,
|
|
||||||
path.span(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_alias<S: Stage>(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
alias: Symbol,
|
|
||||||
span: Span,
|
|
||||||
) {
|
|
||||||
let attr_str = "`#[doc(alias = \"...\")]`";
|
|
||||||
if alias == sym::empty {
|
|
||||||
cx.emit_err(DocAliasEmpty { span, attr_str });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let alias_str = alias.as_str();
|
|
||||||
if let Some(c) =
|
|
||||||
alias_str.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
|
|
||||||
{
|
|
||||||
cx.emit_err(DocAliasBadChar { span, attr_str, char_: c });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if alias_str.starts_with(' ') || alias_str.ends_with(' ') {
|
|
||||||
cx.emit_err(DocAliasStartEnd { span, attr_str });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if !check_attr_not_crate_level(cx, span, sym::alias) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DuplicateDocAlias { first_definition },
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.attribute.aliases.insert(alias, span);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_alias<S: Stage>(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
path: &OwnedPathParser,
|
|
||||||
args: &ArgParser,
|
|
||||||
) {
|
|
||||||
match args {
|
|
||||||
ArgParser::NoArgs => {
|
|
||||||
cx.emit_err(DocAliasMalformed { span: args.span().unwrap_or(path.span()) });
|
|
||||||
}
|
|
||||||
ArgParser::List(list) => {
|
|
||||||
for i in list.mixed() {
|
|
||||||
let Some(alias) = i.lit().and_then(|i| i.value_str()) else {
|
|
||||||
cx.expected_string_literal(i.span(), i.lit());
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.add_alias(cx, alias, i.span());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ArgParser::NameValue(nv) => {
|
|
||||||
let Some(alias) = nv.value_as_str() else {
|
|
||||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
self.add_alias(cx, alias, nv.value_span);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_inline<S: Stage>(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
path: &OwnedPathParser,
|
|
||||||
args: &ArgParser,
|
|
||||||
inline: DocInline,
|
|
||||||
) {
|
|
||||||
if let Err(span) = args.no_args() {
|
|
||||||
expected_no_args(cx, span);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.attribute.inline.push((inline, path.span()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_cfg<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
|
||||||
// This function replaces cases like `cfg(all())` with `true`.
|
|
||||||
fn simplify_cfg(cfg_entry: &mut CfgEntry) {
|
|
||||||
match cfg_entry {
|
|
||||||
CfgEntry::All(cfgs, span) if cfgs.is_empty() => {
|
|
||||||
*cfg_entry = CfgEntry::Bool(true, *span)
|
|
||||||
}
|
|
||||||
CfgEntry::Any(cfgs, span) if cfgs.is_empty() => {
|
|
||||||
*cfg_entry = CfgEntry::Bool(false, *span)
|
|
||||||
}
|
|
||||||
CfgEntry::Not(cfg, _) => simplify_cfg(cfg),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(mut cfg_entry) = super::cfg::parse_cfg(cx, args) {
|
|
||||||
simplify_cfg(&mut cfg_entry);
|
|
||||||
self.attribute.cfg.push(cfg_entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_auto_cfg<S: Stage>(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
path: &OwnedPathParser,
|
|
||||||
args: &ArgParser,
|
|
||||||
) {
|
|
||||||
match args {
|
|
||||||
ArgParser::NoArgs => {
|
|
||||||
self.attribute.auto_cfg_change.push((true, path.span()));
|
|
||||||
}
|
|
||||||
ArgParser::List(list) => {
|
|
||||||
for meta in list.mixed() {
|
|
||||||
let MetaItemOrLitParser::MetaItemParser(item) = meta else {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocAutoCfgExpectsHideOrShow,
|
|
||||||
meta.span(),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let (kind, attr_name) = match item.path().word_sym() {
|
|
||||||
Some(sym::hide) => (HideOrShow::Hide, sym::hide),
|
|
||||||
Some(sym::show) => (HideOrShow::Show, sym::show),
|
|
||||||
_ => {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocAutoCfgExpectsHideOrShow,
|
|
||||||
item.span(),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let ArgParser::List(list) = item.args() else {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name },
|
|
||||||
item.span(),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut cfg_hide_show = CfgHideShow { kind, values: ThinVec::new() };
|
|
||||||
|
|
||||||
for item in list.mixed() {
|
|
||||||
let MetaItemOrLitParser::MetaItemParser(sub_item) = item else {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name },
|
|
||||||
item.span(),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
match sub_item.args() {
|
|
||||||
a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
|
|
||||||
let Some(name) = sub_item.path().word_sym() else {
|
|
||||||
// FIXME: remove this method once merged and uncomment the line
|
|
||||||
// below instead.
|
|
||||||
// cx.expected_identifier(sub_item.path().span());
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::MalformedDoc,
|
|
||||||
sub_item.path().span(),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
if let Ok(CfgEntry::NameValue { name, value, .. }) =
|
|
||||||
super::cfg::parse_name_value(
|
|
||||||
name,
|
|
||||||
sub_item.path().span(),
|
|
||||||
a.name_value(),
|
|
||||||
sub_item.span(),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
cfg_hide_show.values.push(CfgInfo {
|
|
||||||
name,
|
|
||||||
name_span: sub_item.path().span(),
|
|
||||||
// If `value` is `Some`, `a.name_value()` will always return
|
|
||||||
// `Some` as well.
|
|
||||||
value: value
|
|
||||||
.map(|v| (v, a.name_value().unwrap().value_span)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocAutoCfgHideShowUnexpectedItem {
|
|
||||||
attr_name,
|
|
||||||
},
|
|
||||||
sub_item.span(),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.attribute.auto_cfg.push((cfg_hide_show, path.span()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ArgParser::NameValue(nv) => {
|
|
||||||
let MetaItemLit { kind: LitKind::Bool(bool_value), span, .. } = nv.value_as_lit()
|
|
||||||
else {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocAutoCfgWrongLiteral,
|
|
||||||
nv.value_span,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
self.attribute.auto_cfg_change.push((*bool_value, *span));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_single_doc_attr_item<S: Stage>(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
mip: &MetaItemParser,
|
|
||||||
) {
|
|
||||||
let path = mip.path();
|
|
||||||
let args = mip.args();
|
|
||||||
|
|
||||||
macro_rules! no_args {
|
|
||||||
($ident: ident) => {{
|
|
||||||
if let Err(span) = args.no_args() {
|
|
||||||
expected_no_args(cx, span);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: It's errorring when the attribute is passed multiple times on the command
|
|
||||||
// line.
|
|
||||||
// The right fix for this would be to only check this rule if the attribute is
|
|
||||||
// not set on the command line but directly in the code.
|
|
||||||
// if self.attribute.$ident.is_some() {
|
|
||||||
// cx.duplicate_key(path.span(), path.word_sym().unwrap());
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
self.attribute.$ident = Some(path.span());
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
macro_rules! no_args_and_not_crate_level {
|
|
||||||
($ident: ident) => {{
|
|
||||||
if let Err(span) = args.no_args() {
|
|
||||||
expected_no_args(cx, span);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let span = path.span();
|
|
||||||
if !check_attr_not_crate_level(cx, span, sym::$ident) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.attribute.$ident = Some(span);
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
macro_rules! no_args_and_crate_level {
|
|
||||||
($ident: ident) => {{
|
|
||||||
if let Err(span) = args.no_args() {
|
|
||||||
expected_no_args(cx, span);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let span = path.span();
|
|
||||||
if !check_attr_crate_level(cx, span) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.attribute.$ident = Some(span);
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
macro_rules! string_arg_and_crate_level {
|
|
||||||
($ident: ident) => {{
|
|
||||||
let Some(nv) = args.name_value() else {
|
|
||||||
expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym());
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(s) = nv.value_as_str() else {
|
|
||||||
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if !check_attr_crate_level(cx, path.span()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: It's errorring when the attribute is passed multiple times on the command
|
|
||||||
// line.
|
|
||||||
// The right fix for this would be to only check this rule if the attribute is
|
|
||||||
// not set on the command line but directly in the code.
|
|
||||||
// if self.attribute.$ident.is_some() {
|
|
||||||
// cx.duplicate_key(path.span(), path.word_sym().unwrap());
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
self.attribute.$ident = Some((s, path.span()));
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
match path.word_sym() {
|
|
||||||
Some(sym::alias) => self.parse_alias(cx, path, args),
|
|
||||||
Some(sym::hidden) => no_args!(hidden),
|
|
||||||
Some(sym::html_favicon_url) => string_arg_and_crate_level!(html_favicon_url),
|
|
||||||
Some(sym::html_logo_url) => string_arg_and_crate_level!(html_logo_url),
|
|
||||||
Some(sym::html_no_source) => no_args_and_crate_level!(html_no_source),
|
|
||||||
Some(sym::html_playground_url) => string_arg_and_crate_level!(html_playground_url),
|
|
||||||
Some(sym::html_root_url) => string_arg_and_crate_level!(html_root_url),
|
|
||||||
Some(sym::issue_tracker_base_url) => {
|
|
||||||
string_arg_and_crate_level!(issue_tracker_base_url)
|
|
||||||
}
|
|
||||||
Some(sym::inline) => self.parse_inline(cx, path, args, DocInline::Inline),
|
|
||||||
Some(sym::no_inline) => self.parse_inline(cx, path, args, DocInline::NoInline),
|
|
||||||
Some(sym::masked) => no_args!(masked),
|
|
||||||
Some(sym::cfg) => self.parse_cfg(cx, args),
|
|
||||||
Some(sym::notable_trait) => no_args!(notable_trait),
|
|
||||||
Some(sym::keyword) => parse_keyword_and_attribute(
|
|
||||||
cx,
|
|
||||||
path,
|
|
||||||
args,
|
|
||||||
&mut self.attribute.keyword,
|
|
||||||
sym::keyword,
|
|
||||||
),
|
|
||||||
Some(sym::attribute) => parse_keyword_and_attribute(
|
|
||||||
cx,
|
|
||||||
path,
|
|
||||||
args,
|
|
||||||
&mut self.attribute.attribute,
|
|
||||||
sym::attribute,
|
|
||||||
),
|
|
||||||
Some(sym::fake_variadic) => no_args_and_not_crate_level!(fake_variadic),
|
|
||||||
Some(sym::search_unbox) => no_args_and_not_crate_level!(search_unbox),
|
|
||||||
Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo),
|
|
||||||
Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args),
|
|
||||||
Some(sym::test) => {
|
|
||||||
let Some(list) = args.list() else {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocTestTakesList,
|
|
||||||
args.span().unwrap_or(path.span()),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
for i in list.mixed() {
|
|
||||||
match i {
|
|
||||||
MetaItemOrLitParser::MetaItemParser(mip) => {
|
|
||||||
self.parse_single_test_doc_attr_item(cx, mip);
|
|
||||||
}
|
|
||||||
MetaItemOrLitParser::Lit(lit) => {
|
|
||||||
// FIXME: remove this method once merged and uncomment the line
|
|
||||||
// below instead.
|
|
||||||
// cx.unexpected_literal(lit.span);
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::MalformedDoc,
|
|
||||||
lit.span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(sym::spotlight) => {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocUnknownSpotlight { span: path.span() },
|
|
||||||
path.span(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some(sym::include) if let Some(nv) = args.name_value() => {
|
|
||||||
let inner = match cx.attr_style {
|
|
||||||
AttrStyle::Outer => "",
|
|
||||||
AttrStyle::Inner => "!",
|
|
||||||
};
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocUnknownInclude {
|
|
||||||
inner,
|
|
||||||
value: nv.value_as_lit().symbol,
|
|
||||||
span: path.span(),
|
|
||||||
},
|
|
||||||
path.span(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some(name @ (sym::passes | sym::no_default_passes)) => {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocUnknownPasses { name, span: path.span() },
|
|
||||||
path.span(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some(sym::plugins) => {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocUnknownPlugins { span: path.span() },
|
|
||||||
path.span(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some(name) => {
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocUnknownAny { name },
|
|
||||||
path.span(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let full_name =
|
|
||||||
path.segments().map(|s| s.as_str()).intersperse("::").collect::<String>();
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::DocUnknownAny { name: Symbol::intern(&full_name) },
|
|
||||||
path.span(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn accept_single_doc_attr<S: Stage>(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
args: &ArgParser,
|
|
||||||
) {
|
|
||||||
match args {
|
|
||||||
ArgParser::NoArgs => {
|
|
||||||
let suggestions = cx.suggestions();
|
|
||||||
let span = cx.attr_span;
|
|
||||||
cx.emit_lint(
|
|
||||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
|
||||||
AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None },
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ArgParser::List(items) => {
|
|
||||||
for i in items.mixed() {
|
|
||||||
match i {
|
|
||||||
MetaItemOrLitParser::MetaItemParser(mip) => {
|
|
||||||
self.nb_doc_attrs += 1;
|
|
||||||
self.parse_single_doc_attr_item(cx, mip);
|
|
||||||
}
|
|
||||||
MetaItemOrLitParser::Lit(lit) => {
|
|
||||||
expected_name_value(cx, lit.span, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ArgParser::NameValue(nv) => {
|
|
||||||
if nv.value_as_str().is_none() {
|
|
||||||
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
|
|
||||||
} else {
|
|
||||||
unreachable!(
|
|
||||||
"Should have been handled at the same time as sugar-syntaxed doc comments"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Stage> AttributeParser<S> for DocParser {
|
|
||||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
|
||||||
&[sym::doc],
|
|
||||||
template!(
|
|
||||||
List: &[
|
|
||||||
"alias",
|
|
||||||
"attribute",
|
|
||||||
"hidden",
|
|
||||||
"html_favicon_url",
|
|
||||||
"html_logo_url",
|
|
||||||
"html_no_source",
|
|
||||||
"html_playground_url",
|
|
||||||
"html_root_url",
|
|
||||||
"issue_tracker_base_url",
|
|
||||||
"inline",
|
|
||||||
"no_inline",
|
|
||||||
"masked",
|
|
||||||
"cfg",
|
|
||||||
"notable_trait",
|
|
||||||
"keyword",
|
|
||||||
"fake_variadic",
|
|
||||||
"search_unbox",
|
|
||||||
"rust_logo",
|
|
||||||
"auto_cfg",
|
|
||||||
"test",
|
|
||||||
"spotlight",
|
|
||||||
"include",
|
|
||||||
"no_default_passes",
|
|
||||||
"passes",
|
|
||||||
"plugins",
|
|
||||||
],
|
|
||||||
NameValueStr: "string"
|
|
||||||
),
|
|
||||||
|this, cx, args| {
|
|
||||||
this.accept_single_doc_attr(cx, args);
|
|
||||||
},
|
|
||||||
)];
|
|
||||||
// FIXME: Currently emitted from 2 different places, generating duplicated warnings.
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
|
||||||
// const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
|
||||||
// Allow(Target::ExternCrate),
|
|
||||||
// Allow(Target::Use),
|
|
||||||
// Allow(Target::Static),
|
|
||||||
// Allow(Target::Const),
|
|
||||||
// Allow(Target::Fn),
|
|
||||||
// Allow(Target::Mod),
|
|
||||||
// Allow(Target::ForeignMod),
|
|
||||||
// Allow(Target::TyAlias),
|
|
||||||
// Allow(Target::Enum),
|
|
||||||
// Allow(Target::Variant),
|
|
||||||
// Allow(Target::Struct),
|
|
||||||
// Allow(Target::Field),
|
|
||||||
// Allow(Target::Union),
|
|
||||||
// Allow(Target::Trait),
|
|
||||||
// Allow(Target::TraitAlias),
|
|
||||||
// Allow(Target::Impl { of_trait: true }),
|
|
||||||
// Allow(Target::Impl { of_trait: false }),
|
|
||||||
// Allow(Target::AssocConst),
|
|
||||||
// Allow(Target::Method(MethodKind::Inherent)),
|
|
||||||
// Allow(Target::Method(MethodKind::Trait { body: true })),
|
|
||||||
// Allow(Target::Method(MethodKind::Trait { body: false })),
|
|
||||||
// Allow(Target::Method(MethodKind::TraitImpl)),
|
|
||||||
// Allow(Target::AssocTy),
|
|
||||||
// Allow(Target::ForeignFn),
|
|
||||||
// Allow(Target::ForeignStatic),
|
|
||||||
// Allow(Target::ForeignTy),
|
|
||||||
// Allow(Target::MacroDef),
|
|
||||||
// Allow(Target::Crate),
|
|
||||||
// Error(Target::WherePredicate),
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
|
||||||
if self.nb_doc_attrs != 0 {
|
|
||||||
Some(AttributeKind::Doc(Box::new(self.attribute)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -15,7 +15,7 @@ impl<S: Stage> SingleAttributeParser<S> for DummyParser {
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
|
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
|
||||||
|
|
||||||
fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser) -> Option<AttributeKind> {
|
fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
Some(AttributeKind::RustcDummy)
|
Some(AttributeKind::Dummy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,13 @@
|
||||||
// SingleAttributeParser which is what we have two of here.
|
// SingleAttributeParser which is what we have two of here.
|
||||||
|
|
||||||
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
||||||
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
||||||
pub(crate) struct InlineParser;
|
pub(crate) struct InlineParser;
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||||
const PATH: &[Symbol] = &[sym::inline];
|
const PATH: &'static [Symbol] = &[sym::inline];
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
|
|
@ -34,7 +33,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||||
"https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
|
"https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
match args {
|
match args {
|
||||||
ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
|
ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
|
||||||
ArgParser::List(list) => {
|
ArgParser::List(list) => {
|
||||||
|
|
@ -57,7 +56,9 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArgParser::NameValue(_) => {
|
ArgParser::NameValue(_) => {
|
||||||
cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
|
let suggestions = cx.suggestions();
|
||||||
|
let span = cx.attr_span;
|
||||||
|
cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +68,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||||
pub(crate) struct RustcForceInlineParser;
|
pub(crate) struct RustcForceInlineParser;
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_force_inline];
|
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
|
|
@ -77,7 +78,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||||
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
|
const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let reason = match args {
|
let reason = match args {
|
||||||
ArgParser::NoArgs => None,
|
ArgParser::NoArgs => None,
|
||||||
ArgParser::List(list) => {
|
ArgParser::List(list) => {
|
||||||
|
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
use rustc_hir::attrs::InstructionSetAttr;
|
|
||||||
|
|
||||||
use super::prelude::*;
|
|
||||||
use crate::session_diagnostics;
|
|
||||||
|
|
||||||
pub(crate) struct InstructionSetParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for InstructionSetParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::instruction_set];
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::Closure),
|
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
|
||||||
]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute");
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32];
|
|
||||||
const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32];
|
|
||||||
let Some(maybe_meta_item) = args.list().and_then(MetaItemListParser::single) else {
|
|
||||||
cx.expected_specific_argument(cx.attr_span, POSSIBLE_SYMBOLS);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(meta_item) = maybe_meta_item.meta_item() else {
|
|
||||||
cx.expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut segments = meta_item.path().segments();
|
|
||||||
|
|
||||||
let Some(architecture) = segments.next() else {
|
|
||||||
cx.expected_specific_argument(meta_item.span(), POSSIBLE_SYMBOLS);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(instruction_set) = segments.next() else {
|
|
||||||
cx.expected_specific_argument(architecture.span, POSSIBLE_SYMBOLS);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let instruction_set = match architecture.name {
|
|
||||||
sym::arm => {
|
|
||||||
if !cx.sess.target.has_thumb_interworking {
|
|
||||||
cx.dcx().emit_err(session_diagnostics::UnsupportedInstructionSet {
|
|
||||||
span: cx.attr_span,
|
|
||||||
instruction_set: sym::arm,
|
|
||||||
current_target: &cx.sess.opts.target_triple,
|
|
||||||
});
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
match instruction_set.name {
|
|
||||||
sym::a32 => InstructionSetAttr::ArmA32,
|
|
||||||
sym::t32 => InstructionSetAttr::ArmT32,
|
|
||||||
_ => {
|
|
||||||
cx.expected_specific_argument(instruction_set.span, POSSIBLE_ARM_SYMBOLS);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
cx.expected_specific_argument(architecture.span, POSSIBLE_SYMBOLS);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::InstructionSet(instruction_set))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
use rustc_errors::msg;
|
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
|
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
|
||||||
use rustc_hir::attrs::*;
|
use rustc_hir::attrs::*;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::kw;
|
use rustc_span::kw;
|
||||||
use rustc_target::spec::{Arch, BinaryFormat};
|
use rustc_target::spec::{Arch, BinaryFormat};
|
||||||
|
|
@ -11,11 +9,12 @@ use rustc_target::spec::{Arch, BinaryFormat};
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::util::parse_single_integer;
|
use super::util::parse_single_integer;
|
||||||
use crate::attributes::cfg::parse_cfg_entry;
|
use crate::attributes::cfg::parse_cfg_entry;
|
||||||
|
use crate::fluent_generated;
|
||||||
use crate::session_diagnostics::{
|
use crate::session_diagnostics::{
|
||||||
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
|
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86,
|
||||||
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
|
IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
|
||||||
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
|
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
|
||||||
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
|
WholeArchiveNeedsStatic,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct LinkNameParser;
|
pub(crate) struct LinkNameParser;
|
||||||
|
|
@ -33,7 +32,7 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
|
||||||
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
|
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(nv) = args.name_value() else {
|
let Some(nv) = args.name_value() else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -62,21 +61,23 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||||
], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute");
|
], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute");
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
|
||||||
|
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||||
let items = match args {
|
let items = match args {
|
||||||
ArgParser::List(list) => list,
|
ArgParser::List(list) => list,
|
||||||
// This is an edgecase added because making this a hard error would break too many crates
|
// This is an edgecase added because making this a hard error would break too many crates
|
||||||
// Specifically `#[link = "dl"]` is accepted with a FCW
|
// Specifically `#[link = "dl"]` is accepted with a FCW
|
||||||
// For more information, see https://github.com/rust-lang/rust/pull/143193
|
// For more information, see https://github.com/rust-lang/rust/pull/143193
|
||||||
ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => {
|
ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => {
|
||||||
cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
|
let suggestions = cx.suggestions();
|
||||||
|
let span = cx.attr_span;
|
||||||
|
cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -141,6 +142,8 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||||
|
|
||||||
macro report_unstable_modifier($feature: ident) {
|
macro report_unstable_modifier($feature: ident) {
|
||||||
if !features.$feature() {
|
if !features.$feature() {
|
||||||
|
// FIXME: make this translatable
|
||||||
|
#[expect(rustc::untranslatable_diagnostic)]
|
||||||
feature_err(
|
feature_err(
|
||||||
sess,
|
sess,
|
||||||
sym::$feature,
|
sym::$feature,
|
||||||
|
|
@ -165,14 +168,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||||
cx.emit_err(BundleNeedsStatic { span });
|
cx.emit_err(BundleNeedsStatic { span });
|
||||||
}
|
}
|
||||||
|
|
||||||
(sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
|
|
||||||
assign_modifier(export_symbols)
|
|
||||||
}
|
|
||||||
|
|
||||||
(sym::export_symbols, _) => {
|
|
||||||
cx.emit_err(ExportSymbolsNeedsStatic { span });
|
|
||||||
}
|
|
||||||
|
|
||||||
(sym::verbatim, _) => assign_modifier(&mut verbatim),
|
(sym::verbatim, _) => assign_modifier(&mut verbatim),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
@ -198,7 +193,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||||
span,
|
span,
|
||||||
&[
|
&[
|
||||||
sym::bundle,
|
sym::bundle,
|
||||||
sym::export_symbols,
|
|
||||||
sym::verbatim,
|
sym::verbatim,
|
||||||
sym::whole_dash_archive,
|
sym::whole_dash_archive,
|
||||||
sym::as_dash_needed,
|
sym::as_dash_needed,
|
||||||
|
|
@ -249,7 +243,7 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||||
|
|
||||||
impl LinkParser {
|
impl LinkParser {
|
||||||
fn parse_link_name<S: Stage>(
|
fn parse_link_name<S: Stage>(
|
||||||
item: &MetaItemParser,
|
item: &MetaItemParser<'_>,
|
||||||
name: &mut Option<(Symbol, Span)>,
|
name: &mut Option<(Symbol, Span)>,
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
@ -274,7 +268,7 @@ impl LinkParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_link_kind<S: Stage>(
|
fn parse_link_kind<S: Stage>(
|
||||||
item: &MetaItemParser,
|
item: &MetaItemParser<'_>,
|
||||||
kind: &mut Option<NativeLibKind>,
|
kind: &mut Option<NativeLibKind>,
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
|
|
@ -294,9 +288,7 @@ impl LinkParser {
|
||||||
};
|
};
|
||||||
|
|
||||||
let link_kind = match link_kind {
|
let link_kind = match link_kind {
|
||||||
kw::Static => {
|
kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
|
||||||
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
|
|
||||||
}
|
|
||||||
sym::dylib => NativeLibKind::Dylib { as_needed: None },
|
sym::dylib => NativeLibKind::Dylib { as_needed: None },
|
||||||
sym::framework => {
|
sym::framework => {
|
||||||
if !sess.target.is_like_darwin {
|
if !sess.target.is_like_darwin {
|
||||||
|
|
@ -316,7 +308,7 @@ impl LinkParser {
|
||||||
sess,
|
sess,
|
||||||
sym::raw_dylib_elf,
|
sym::raw_dylib_elf,
|
||||||
nv.value_span,
|
nv.value_span,
|
||||||
msg!("link kind `raw-dylib` is unstable on ELF platforms"),
|
fluent_generated::attr_parsing_raw_dylib_elf_unstable,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -331,7 +323,7 @@ impl LinkParser {
|
||||||
sess,
|
sess,
|
||||||
sym::link_arg_attribute,
|
sym::link_arg_attribute,
|
||||||
nv.value_span,
|
nv.value_span,
|
||||||
msg!("link kind `link-arg` is unstable"),
|
fluent_generated::attr_parsing_link_arg_unstable,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -356,7 +348,7 @@ impl LinkParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_link_modifiers<S: Stage>(
|
fn parse_link_modifiers<S: Stage>(
|
||||||
item: &MetaItemParser,
|
item: &MetaItemParser<'_>,
|
||||||
modifiers: &mut Option<(Symbol, Span)>,
|
modifiers: &mut Option<(Symbol, Span)>,
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
@ -377,7 +369,7 @@ impl LinkParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_link_cfg<S: Stage>(
|
fn parse_link_cfg<S: Stage>(
|
||||||
item: &MetaItemParser,
|
item: &MetaItemParser<'_>,
|
||||||
cfg: &mut Option<CfgEntry>,
|
cfg: &mut Option<CfgEntry>,
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
|
|
@ -388,7 +380,7 @@ impl LinkParser {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let Some(link_cfg) = item.args().list() else {
|
let Some(link_cfg) = item.args().list() else {
|
||||||
cx.expected_list(item.span(), item.args());
|
cx.expected_list(item.span());
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
let Some(link_cfg) = link_cfg.single() else {
|
let Some(link_cfg) = link_cfg.single() else {
|
||||||
|
|
@ -396,14 +388,20 @@ impl LinkParser {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if !features.link_cfg() {
|
if !features.link_cfg() {
|
||||||
feature_err(sess, sym::link_cfg, item.span(), msg!("link cfg is unstable")).emit();
|
feature_err(
|
||||||
|
sess,
|
||||||
|
sym::link_cfg,
|
||||||
|
item.span(),
|
||||||
|
fluent_generated::attr_parsing_link_cfg_unstable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
*cfg = parse_cfg_entry(cx, link_cfg).ok();
|
*cfg = parse_cfg_entry(cx, link_cfg).ok();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_link_wasm_import_module<S: Stage>(
|
fn parse_link_wasm_import_module<S: Stage>(
|
||||||
item: &MetaItemParser,
|
item: &MetaItemParser<'_>,
|
||||||
wasm_import_module: &mut Option<(Symbol, Span)>,
|
wasm_import_module: &mut Option<(Symbol, Span)>,
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
@ -424,7 +422,7 @@ impl LinkParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_link_import_name_type<S: Stage>(
|
fn parse_link_import_name_type<S: Stage>(
|
||||||
item: &MetaItemParser,
|
item: &MetaItemParser<'_>,
|
||||||
import_name_type: &mut Option<(PeImportNameType, Span)>,
|
import_name_type: &mut Option<(PeImportNameType, Span)>,
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
@ -472,6 +470,7 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
|
||||||
Allow(Target::Static),
|
Allow(Target::Static),
|
||||||
Allow(Target::Fn),
|
Allow(Target::Fn),
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
|
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
]);
|
]);
|
||||||
|
|
@ -480,7 +479,7 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
|
||||||
"https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
|
"https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(nv) = args.name_value() else {
|
let Some(nv) = args.name_value() else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -534,7 +533,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
|
||||||
Allow(Target::Static),
|
Allow(Target::Static),
|
||||||
Allow(Target::ForeignStatic),
|
Allow(Target::ForeignStatic),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct LinkOrdinalParser;
|
pub(crate) struct LinkOrdinalParser;
|
||||||
|
|
@ -553,7 +552,7 @@ impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
|
||||||
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
|
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let ordinal = parse_single_integer(cx, args)?;
|
let ordinal = parse_single_integer(cx, args)?;
|
||||||
|
|
||||||
// According to the table at
|
// According to the table at
|
||||||
|
|
@ -589,12 +588,12 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
Allow(Target::Fn),
|
Allow(Target::Fn),
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
|
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
Allow(Target::Static),
|
Allow(Target::Static),
|
||||||
Allow(Target::ForeignStatic),
|
Allow(Target::ForeignStatic),
|
||||||
Allow(Target::ForeignFn),
|
Allow(Target::ForeignFn),
|
||||||
Warn(Target::Method(MethodKind::Trait { body: false })), // Not inherited
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: [
|
const TEMPLATE: AttributeTemplate = template!(NameValueStr: [
|
||||||
|
|
@ -609,7 +608,7 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
||||||
"weak_odr",
|
"weak_odr",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(name_value) = args.name_value() else {
|
let Some(name_value) = args.name_value() else {
|
||||||
cx.expected_name_value(cx.attr_span, Some(sym::linkage));
|
cx.expected_name_value(cx.attr_span, Some(sym::linkage));
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -661,21 +660,3 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
||||||
Some(AttributeKind::Linkage(linkage, cx.attr_span))
|
Some(AttributeKind::Linkage(linkage, cx.attr_span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct NeedsAllocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::needs_allocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct CompilerBuiltinsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::compiler_builtins];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser {
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAsPtr;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PubTransparentParser;
|
pub(crate) struct PubTransparentParser;
|
||||||
|
|
@ -23,7 +23,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser {
|
||||||
Allow(Target::Enum),
|
Allow(Target::Enum),
|
||||||
Allow(Target::Union),
|
Allow(Target::Union),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PassByValueParser;
|
pub(crate) struct PassByValueParser;
|
||||||
|
|
@ -35,7 +35,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser {
|
||||||
Allow(Target::Enum),
|
Allow(Target::Enum),
|
||||||
Allow(Target::TyAlias),
|
Allow(Target::TyAlias),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassByValue;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcShouldNotBeCalledOnConstItems;
|
pub(crate) struct RustcShouldNotBeCalledOnConstItems;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use rustc_hir::attrs::{CollapseMacroDebuginfo, MacroUseArgs};
|
use rustc_errors::DiagArgValue;
|
||||||
use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS;
|
use rustc_hir::attrs::MacroUseArgs;
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
use crate::session_diagnostics::IllFormedAttributeInputLint;
|
||||||
|
|
||||||
pub(crate) struct MacroEscapeParser;
|
pub(crate) struct MacroEscapeParser;
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
|
||||||
|
|
@ -99,8 +100,15 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArgParser::NameValue(nv) => {
|
ArgParser::NameValue(_) => {
|
||||||
cx.expected_list_or_no_args(nv.args_span());
|
let suggestions = cx.suggestions();
|
||||||
|
cx.emit_err(IllFormedAttributeInputLint {
|
||||||
|
num_suggestions: suggestions.len(),
|
||||||
|
suggestions: DiagArgValue::StrListSepByAnd(
|
||||||
|
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -139,79 +147,45 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
|
||||||
Error(Target::Crate),
|
Error(Target::Crate),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let local_inner_macros = match args {
|
let local_inner_macros = match args {
|
||||||
ArgParser::NoArgs => false,
|
ArgParser::NoArgs => false,
|
||||||
ArgParser::List(list) => {
|
ArgParser::List(list) => {
|
||||||
let Some(l) = list.single() else {
|
let Some(l) = list.single() else {
|
||||||
cx.warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
|
let span = cx.attr_span;
|
||||||
|
let suggestions = cx.suggestions();
|
||||||
|
cx.emit_lint(
|
||||||
|
AttributeLintKind::InvalidMacroExportArguments { suggestions },
|
||||||
|
span,
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
match l.meta_item().and_then(|i| i.path().word_sym()) {
|
match l.meta_item().and_then(|i| i.path().word_sym()) {
|
||||||
Some(sym::local_inner_macros) => true,
|
Some(sym::local_inner_macros) => true,
|
||||||
_ => {
|
_ => {
|
||||||
cx.warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
|
let span = cx.attr_span;
|
||||||
|
let suggestions = cx.suggestions();
|
||||||
|
cx.emit_lint(
|
||||||
|
AttributeLintKind::InvalidMacroExportArguments { suggestions },
|
||||||
|
span,
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArgParser::NameValue(nv) => {
|
ArgParser::NameValue(_) => {
|
||||||
cx.expected_list_or_no_args(nv.args_span());
|
let span = cx.attr_span;
|
||||||
|
let suggestions = cx.suggestions();
|
||||||
|
cx.emit_err(IllFormedAttributeInputLint {
|
||||||
|
num_suggestions: suggestions.len(),
|
||||||
|
suggestions: DiagArgValue::StrListSepByAnd(
|
||||||
|
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
});
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
|
Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CollapseDebugInfoParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::collapse_debuginfo];
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(
|
|
||||||
List: &["no", "external", "yes"],
|
|
||||||
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
|
|
||||||
);
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(list) = args.list() else {
|
|
||||||
cx.expected_list(cx.attr_span, args);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let Some(single) = list.single() else {
|
|
||||||
cx.expected_single_argument(list.span);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let Some(mi) = single.meta_item() else {
|
|
||||||
cx.unexpected_literal(single.span());
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
if let Err(err) = mi.args().no_args() {
|
|
||||||
cx.expected_no_args(err);
|
|
||||||
}
|
|
||||||
let path = mi.path().word_sym();
|
|
||||||
let info = match path {
|
|
||||||
Some(sym::yes) => CollapseMacroDebuginfo::Yes,
|
|
||||||
Some(sym::no) => CollapseMacroDebuginfo::No,
|
|
||||||
Some(sym::external) => CollapseMacroDebuginfo::External,
|
|
||||||
_ => {
|
|
||||||
cx.expected_specific_argument(mi.span(), &[sym::yes, sym::no, sym::external]);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::CollapseDebugInfo(info))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcProcMacroDeclsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcProcMacroDeclsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_proc_macro_decls];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcProcMacroDecls;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -32,34 +32,27 @@ mod prelude;
|
||||||
pub(crate) mod allow_unstable;
|
pub(crate) mod allow_unstable;
|
||||||
pub(crate) mod body;
|
pub(crate) mod body;
|
||||||
pub(crate) mod cfg;
|
pub(crate) mod cfg;
|
||||||
|
pub(crate) mod cfg_old;
|
||||||
pub(crate) mod cfg_select;
|
pub(crate) mod cfg_select;
|
||||||
pub(crate) mod cfi_encoding;
|
|
||||||
pub(crate) mod codegen_attrs;
|
pub(crate) mod codegen_attrs;
|
||||||
pub(crate) mod confusables;
|
pub(crate) mod confusables;
|
||||||
pub(crate) mod crate_level;
|
pub(crate) mod crate_level;
|
||||||
pub(crate) mod debugger;
|
pub(crate) mod debugger;
|
||||||
pub(crate) mod deprecation;
|
pub(crate) mod deprecation;
|
||||||
pub(crate) mod do_not_recommend;
|
|
||||||
pub(crate) mod doc;
|
|
||||||
pub(crate) mod dummy;
|
pub(crate) mod dummy;
|
||||||
pub(crate) mod inline;
|
pub(crate) mod inline;
|
||||||
pub(crate) mod instruction_set;
|
|
||||||
pub(crate) mod link_attrs;
|
pub(crate) mod link_attrs;
|
||||||
pub(crate) mod lint_helpers;
|
pub(crate) mod lint_helpers;
|
||||||
pub(crate) mod loop_match;
|
pub(crate) mod loop_match;
|
||||||
pub(crate) mod macro_attrs;
|
pub(crate) mod macro_attrs;
|
||||||
pub(crate) mod must_not_suspend;
|
|
||||||
pub(crate) mod must_use;
|
pub(crate) mod must_use;
|
||||||
pub(crate) mod no_implicit_prelude;
|
pub(crate) mod no_implicit_prelude;
|
||||||
pub(crate) mod no_link;
|
|
||||||
pub(crate) mod non_exhaustive;
|
pub(crate) mod non_exhaustive;
|
||||||
pub(crate) mod path;
|
pub(crate) mod path;
|
||||||
pub(crate) mod pin_v2;
|
pub(crate) mod pin_v2;
|
||||||
pub(crate) mod proc_macro_attrs;
|
pub(crate) mod proc_macro_attrs;
|
||||||
pub(crate) mod prototype;
|
pub(crate) mod prototype;
|
||||||
pub(crate) mod repr;
|
pub(crate) mod repr;
|
||||||
pub(crate) mod rustc_allocator;
|
|
||||||
pub(crate) mod rustc_dump;
|
|
||||||
pub(crate) mod rustc_internal;
|
pub(crate) mod rustc_internal;
|
||||||
pub(crate) mod semantics;
|
pub(crate) mod semantics;
|
||||||
pub(crate) mod stability;
|
pub(crate) mod stability;
|
||||||
|
|
@ -68,7 +61,7 @@ pub(crate) mod traits;
|
||||||
pub(crate) mod transparency;
|
pub(crate) mod transparency;
|
||||||
pub(crate) mod util;
|
pub(crate) mod util;
|
||||||
|
|
||||||
type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser);
|
type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>);
|
||||||
type AcceptMapping<T, S> = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn<T, S>)];
|
type AcceptMapping<T, S> = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn<T, S>)];
|
||||||
|
|
||||||
/// An [`AttributeParser`] is a type which searches for syntactic attributes.
|
/// An [`AttributeParser`] is a type which searches for syntactic attributes.
|
||||||
|
|
@ -139,7 +132,7 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
|
||||||
const TEMPLATE: AttributeTemplate;
|
const TEMPLATE: AttributeTemplate;
|
||||||
|
|
||||||
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
|
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind>;
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use in combination with [`SingleAttributeParser`].
|
/// Use in combination with [`SingleAttributeParser`].
|
||||||
|
|
@ -288,7 +281,7 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without
|
||||||
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
|
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
if let Err(span) = args.no_args() {
|
if let Err(span) = args.no_args() {
|
||||||
cx.expected_no_args(span);
|
cx.expected_no_args(span);
|
||||||
}
|
}
|
||||||
|
|
@ -321,10 +314,10 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
|
||||||
const TEMPLATE: AttributeTemplate;
|
const TEMPLATE: AttributeTemplate;
|
||||||
|
|
||||||
/// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
|
/// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item>;
|
) -> impl IntoIterator<Item = Self::Item> + 'c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use in combination with [`CombineAttributeParser`].
|
/// Use in combination with [`CombineAttributeParser`].
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
use super::prelude::*;
|
|
||||||
|
|
||||||
pub(crate) struct MustNotSuspendParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for MustNotSuspendParser {
|
|
||||||
const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend];
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Struct),
|
|
||||||
Allow(Target::Enum),
|
|
||||||
Allow(Target::Union),
|
|
||||||
Allow(Target::Trait),
|
|
||||||
]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let reason = match args {
|
|
||||||
ArgParser::NameValue(reason) => match reason.value_as_str() {
|
|
||||||
Some(val) => Some(val),
|
|
||||||
None => {
|
|
||||||
cx.expected_nv_or_no_args(reason.value_span);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ArgParser::NoArgs => None,
|
|
||||||
ArgParser::List(list) => {
|
|
||||||
cx.expected_nv_or_no_args(list.span);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::MustNotSupend { reason })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
use rustc_errors::DiagArgValue;
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
use crate::session_diagnostics::IllFormedAttributeInputLint;
|
||||||
|
|
||||||
pub(crate) struct MustUseParser;
|
pub(crate) struct MustUseParser;
|
||||||
|
|
||||||
|
|
@ -26,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
|
||||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
|
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
Some(AttributeKind::MustUse {
|
Some(AttributeKind::MustUse {
|
||||||
span: cx.attr_span,
|
span: cx.attr_span,
|
||||||
reason: match args {
|
reason: match args {
|
||||||
|
|
@ -41,8 +44,15 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
|
||||||
};
|
};
|
||||||
Some(value_str)
|
Some(value_str)
|
||||||
}
|
}
|
||||||
ArgParser::List(list) => {
|
ArgParser::List(_) => {
|
||||||
cx.expected_nv_or_no_args(list.span);
|
let suggestions = cx.suggestions();
|
||||||
|
cx.emit_err(IllFormedAttributeInputLint {
|
||||||
|
num_suggestions: suggestions.len(),
|
||||||
|
suggestions: DiagArgValue::StrListSepByAnd(
|
||||||
|
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||||
|
),
|
||||||
|
span: cx.attr_span,
|
||||||
|
});
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
use super::prelude::*;
|
|
||||||
|
|
||||||
pub(crate) struct NoLinkParser;
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NoLinkParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::no_link];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::ExternCrate),
|
|
||||||
Warn(Target::Field),
|
|
||||||
Warn(Target::Arm),
|
|
||||||
Warn(Target::MacroDef),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoLink;
|
|
||||||
}
|
|
||||||
|
|
@ -13,7 +13,7 @@ impl<S: Stage> SingleAttributeParser<S> for PathParser {
|
||||||
"https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
|
"https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(nv) = args.name_value() else {
|
let Some(nv) = args.name_value() else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ pub(super) use rustc_feature::{AttributeTemplate, template};
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub(super) use rustc_hir::attrs::AttributeKind;
|
pub(super) use rustc_hir::attrs::AttributeKind;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
pub(super) use rustc_hir::lints::AttributeLintKind;
|
||||||
|
#[doc(hidden)]
|
||||||
pub(super) use rustc_hir::{MethodKind, Target};
|
pub(super) use rustc_hir::{MethodKind, Target};
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
|
pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
|
||||||
use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS;
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
||||||
const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
|
const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
|
||||||
|
|
@ -33,7 +30,7 @@ impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
|
||||||
"https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
|
"https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
|
let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
|
||||||
Some(AttributeKind::ProcMacroDerive {
|
Some(AttributeKind::ProcMacroDerive {
|
||||||
trait_name: trait_name.expect("Trait name is mandatory, so it is present"),
|
trait_name: trait_name.expect("Trait name is mandatory, so it is present"),
|
||||||
|
|
@ -52,7 +49,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
|
||||||
const TEMPLATE: AttributeTemplate =
|
const TEMPLATE: AttributeTemplate =
|
||||||
template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]);
|
template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;
|
let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;
|
||||||
Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span })
|
Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span })
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +57,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
|
||||||
|
|
||||||
fn parse_derive_like<S: Stage>(
|
fn parse_derive_like<S: Stage>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &ArgParser<'_>,
|
||||||
trait_name_mandatory: bool,
|
trait_name_mandatory: bool,
|
||||||
) -> Option<(Option<Symbol>, ThinVec<Symbol>)> {
|
) -> Option<(Option<Symbol>, ThinVec<Symbol>)> {
|
||||||
let Some(list) = args.list() else {
|
let Some(list) = args.list() else {
|
||||||
|
|
@ -68,7 +65,7 @@ fn parse_derive_like<S: Stage>(
|
||||||
if args.no_args().is_ok() && !trait_name_mandatory {
|
if args.no_args().is_ok() && !trait_name_mandatory {
|
||||||
return Some((None, ThinVec::new()));
|
return Some((None, ThinVec::new()));
|
||||||
}
|
}
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let mut items = list.mixed();
|
let mut items = list.mixed();
|
||||||
|
|
@ -99,7 +96,7 @@ fn parse_derive_like<S: Stage>(
|
||||||
let mut attributes = ThinVec::new();
|
let mut attributes = ThinVec::new();
|
||||||
if let Some(attrs) = items.next() {
|
if let Some(attrs) = items.next() {
|
||||||
let Some(attr_list) = attrs.meta_item() else {
|
let Some(attr_list) = attrs.meta_item() else {
|
||||||
cx.unexpected_literal(attrs.span());
|
cx.expected_list(attrs.span());
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
if !attr_list.path().word_is(sym::attributes) {
|
if !attr_list.path().word_is(sym::attributes) {
|
||||||
|
|
@ -107,7 +104,7 @@ fn parse_derive_like<S: Stage>(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let Some(attr_list) = attr_list.args().list() else {
|
let Some(attr_list) = attr_list.args().list() else {
|
||||||
cx.expected_list(attrs.span(), attr_list.args());
|
cx.expected_list(attrs.span());
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -129,13 +126,6 @@ fn parse_derive_like<S: Stage>(
|
||||||
cx.expected_identifier(ident.span);
|
cx.expected_identifier(ident.span);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if rustc_feature::is_builtin_attr_name(ident.name) {
|
|
||||||
cx.emit_lint(
|
|
||||||
AMBIGUOUS_DERIVE_HELPERS,
|
|
||||||
AttributeLintKind::AmbiguousDeriveHelpers,
|
|
||||||
ident.span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
attributes.push(ident.name);
|
attributes.push(ident.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
|
||||||
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]);
|
const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(list) = args.list() else {
|
let Some(list) = args.list() else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -46,8 +46,9 @@ impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
|
||||||
extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed);
|
extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed);
|
||||||
} else if let Some(arg) = meta_item.word_is(sym::phase) {
|
} else if let Some(arg) = meta_item.word_is(sym::phase) {
|
||||||
extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed);
|
extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed);
|
||||||
} else if let Some(..) = meta_item.path().word() {
|
} else if let Some(word) = meta_item.path().word() {
|
||||||
cx.expected_specific_argument(meta_item.span(), &[sym::dialect, sym::phase]);
|
let word = word.to_string();
|
||||||
|
cx.unknown_key(meta_item.span(), word, &["dialect", "phase"]);
|
||||||
failed = true;
|
failed = true;
|
||||||
} else {
|
} else {
|
||||||
cx.expected_name_value(meta_item.span(), None);
|
cx.expected_name_value(meta_item.span(), None);
|
||||||
|
|
@ -69,7 +70,7 @@ impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
|
||||||
fn extract_value<S: Stage>(
|
fn extract_value<S: Stage>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
key: Symbol,
|
key: Symbol,
|
||||||
arg: &ArgParser,
|
arg: &ArgParser<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
out_val: &mut Option<(Symbol, Span)>,
|
out_val: &mut Option<(Symbol, Span)>,
|
||||||
failed: &mut bool,
|
failed: &mut bool,
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,14 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
|
||||||
"https://doc.rust-lang.org/reference/type-layout.html#representations"
|
"https://doc.rust-lang.org/reference/type-layout.html#representations"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn extend(
|
fn extend<'c>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &'c ArgParser<'_>,
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||||
let mut reprs = Vec::new();
|
let mut reprs = Vec::new();
|
||||||
|
|
||||||
let Some(list) = args.list() else {
|
let Some(list) = args.list() else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return reprs;
|
return reprs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -98,7 +98,10 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_repr<S: Stage>(cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser) -> Option<ReprAttr> {
|
fn parse_repr<S: Stage>(
|
||||||
|
cx: &AcceptContext<'_, '_, S>,
|
||||||
|
param: &MetaItemParser<'_>,
|
||||||
|
) -> Option<ReprAttr> {
|
||||||
use ReprAttr::*;
|
use ReprAttr::*;
|
||||||
|
|
||||||
// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
|
// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
|
||||||
|
|
@ -189,7 +192,7 @@ enum AlignKind {
|
||||||
|
|
||||||
fn parse_repr_align<S: Stage>(
|
fn parse_repr_align<S: Stage>(
|
||||||
cx: &AcceptContext<'_, '_, S>,
|
cx: &AcceptContext<'_, '_, S>,
|
||||||
list: &MetaItemListParser,
|
list: &MetaItemListParser<'_>,
|
||||||
param_span: Span,
|
param_span: Span,
|
||||||
align_kind: AlignKind,
|
align_kind: AlignKind,
|
||||||
) -> Option<ReprAttr> {
|
) -> Option<ReprAttr> {
|
||||||
|
|
@ -272,13 +275,17 @@ fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
|
||||||
pub(crate) struct AlignParser(Option<(Align, Span)>);
|
pub(crate) struct AlignParser(Option<(Align, Span)>);
|
||||||
|
|
||||||
impl AlignParser {
|
impl AlignParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_align];
|
const PATH: &'static [Symbol] = &[sym::rustc_align];
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
|
const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
|
||||||
|
|
||||||
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
fn parse<'c, S: Stage>(
|
||||||
|
&mut self,
|
||||||
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
|
args: &'c ArgParser<'_>,
|
||||||
|
) {
|
||||||
match args {
|
match args {
|
||||||
ArgParser::NoArgs | ArgParser::NameValue(_) => {
|
ArgParser::NoArgs | ArgParser::NameValue(_) => {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
}
|
}
|
||||||
ArgParser::List(list) => {
|
ArgParser::List(list) => {
|
||||||
let Some(align) = list.single() else {
|
let Some(align) = list.single() else {
|
||||||
|
|
@ -315,7 +322,7 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
Allow(Target::Method(MethodKind::Trait { body: false })), // `#[align]` is inherited from trait methods
|
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||||
Allow(Target::ForeignFn),
|
Allow(Target::ForeignFn),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -329,10 +336,14 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
|
||||||
pub(crate) struct AlignStaticParser(AlignParser);
|
pub(crate) struct AlignStaticParser(AlignParser);
|
||||||
|
|
||||||
impl AlignStaticParser {
|
impl AlignStaticParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_align_static];
|
const PATH: &'static [Symbol] = &[sym::rustc_align_static];
|
||||||
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
||||||
|
|
||||||
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
fn parse<'c, S: Stage>(
|
||||||
|
&mut self,
|
||||||
|
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||||
|
args: &'c ArgParser<'_>,
|
||||||
|
) {
|
||||||
self.0.parse(cx, args)
|
self.0.parse(cx, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
use super::prelude::*;
|
|
||||||
|
|
||||||
pub(crate) struct RustcAllocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_allocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcAllocatorZeroedParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorZeroedParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcAllocatorZeroedVariantParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RustcAllocatorZeroedVariantParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed_variant];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function");
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(name) = args.name_value().and_then(NameValueParser::value_as_str) else {
|
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::RustcAllocatorZeroedVariant { name })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcDeallocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDeallocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_deallocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcReallocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcReallocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_reallocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcReallocator;
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
use rustc_hir::Target;
|
|
||||||
use rustc_hir::attrs::AttributeKind;
|
|
||||||
use rustc_span::{Span, Symbol, sym};
|
|
||||||
|
|
||||||
use crate::attributes::prelude::Allow;
|
|
||||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
|
||||||
use crate::context::Stage;
|
|
||||||
use crate::target_checking::AllowedTargets;
|
|
||||||
|
|
||||||
pub(crate) struct RustcDumpUserArgsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_user_args];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcDumpDefParentsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParentsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_def_parents];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcDumpItemBoundsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBoundsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcDumpPredicatesParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_predicates];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Struct),
|
|
||||||
Allow(Target::Enum),
|
|
||||||
Allow(Target::Union),
|
|
||||||
Allow(Target::Trait),
|
|
||||||
Allow(Target::AssocTy),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcDumpVtableParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtableParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_vtable];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Impl { of_trait: true }),
|
|
||||||
Allow(Target::TyAlias),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDumpVtable;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,6 @@
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
|
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir::target::GenericParamKind;
|
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
|
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
|
||||||
StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
|
StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
|
||||||
|
|
@ -9,7 +8,7 @@ use rustc_hir::{
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::util::parse_version;
|
use super::util::parse_version;
|
||||||
use crate::session_diagnostics::{self};
|
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
|
||||||
|
|
||||||
macro_rules! reject_outside_std {
|
macro_rules! reject_outside_std {
|
||||||
($cx: ident) => {
|
($cx: ident) => {
|
||||||
|
|
@ -44,7 +43,7 @@ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
Allow(Target::TyAlias),
|
Allow(Target::TyAlias),
|
||||||
Allow(Target::Variant),
|
Allow(Target::Variant),
|
||||||
Allow(Target::Field),
|
Allow(Target::Field),
|
||||||
Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
|
Allow(Target::Param),
|
||||||
Allow(Target::Static),
|
Allow(Target::Static),
|
||||||
Allow(Target::ForeignFn),
|
Allow(Target::ForeignFn),
|
||||||
Allow(Target::ForeignStatic),
|
Allow(Target::ForeignStatic),
|
||||||
|
|
@ -173,7 +172,7 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
|
||||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||||
let (stability, span) = self.stability?;
|
let (stability, span) = self.stability?;
|
||||||
|
|
||||||
Some(AttributeKind::RustcBodyStability { stability, span })
|
Some(AttributeKind::BodyStability { stability, span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,7 +184,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser {
|
||||||
Allow(Target::Fn),
|
Allow(Target::Fn),
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConstStabilityIndirect;
|
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -244,20 +243,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||||
this.promotable = true;
|
this.promotable = true;
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
|
||||||
Allow(Target::Impl { of_trait: false }),
|
|
||||||
Allow(Target::Impl { of_trait: true }),
|
|
||||||
Allow(Target::Use), // FIXME I don't think this does anything?
|
|
||||||
Allow(Target::Const),
|
|
||||||
Allow(Target::AssocConst),
|
|
||||||
Allow(Target::Trait),
|
|
||||||
Allow(Target::Static),
|
|
||||||
Allow(Target::Crate),
|
|
||||||
]);
|
|
||||||
|
|
||||||
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||||
if self.promotable {
|
if self.promotable {
|
||||||
|
|
@ -271,7 +257,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||||
|
|
||||||
let (stability, span) = self.stability?;
|
let (stability, span) = self.stability?;
|
||||||
|
|
||||||
Some(AttributeKind::RustcConstStability { stability, span })
|
Some(AttributeKind::ConstStability { stability, span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,7 +267,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||||
/// `name = value`
|
/// `name = value`
|
||||||
fn insert_value_into_option_or_error<S: Stage>(
|
fn insert_value_into_option_or_error<S: Stage>(
|
||||||
cx: &AcceptContext<'_, '_, S>,
|
cx: &AcceptContext<'_, '_, S>,
|
||||||
param: &MetaItemParser,
|
param: &MetaItemParser<'_>,
|
||||||
item: &mut Option<Symbol>,
|
item: &mut Option<Symbol>,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
|
|
@ -303,20 +289,25 @@ fn insert_value_into_option_or_error<S: Stage>(
|
||||||
/// its stability information.
|
/// its stability information.
|
||||||
pub(crate) fn parse_stability<S: Stage>(
|
pub(crate) fn parse_stability<S: Stage>(
|
||||||
cx: &AcceptContext<'_, '_, S>,
|
cx: &AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &ArgParser<'_>,
|
||||||
) -> Option<(Symbol, StabilityLevel)> {
|
) -> Option<(Symbol, StabilityLevel)> {
|
||||||
let mut feature = None;
|
let mut feature = None;
|
||||||
let mut since = None;
|
let mut since = None;
|
||||||
|
|
||||||
let ArgParser::List(list) = args else {
|
let ArgParser::List(list) = args else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
for param in list.mixed() {
|
for param in list.mixed() {
|
||||||
let param_span = param.span();
|
let param_span = param.span();
|
||||||
let Some(param) = param.meta_item() else {
|
let Some(param) = param.meta_item() else {
|
||||||
cx.unexpected_literal(param.span());
|
cx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||||
|
span: param_span,
|
||||||
|
reason: UnsupportedLiteralReason::Generic,
|
||||||
|
is_bytestr: false,
|
||||||
|
start_point_span: cx.sess().source_map().start_point(param_span),
|
||||||
|
});
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -329,7 +320,11 @@ pub(crate) fn parse_stability<S: Stage>(
|
||||||
insert_value_into_option_or_error(cx, ¶m, &mut since, word.unwrap())?
|
insert_value_into_option_or_error(cx, ¶m, &mut since, word.unwrap())?
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cx.expected_specific_argument(param_span, &[sym::feature, sym::since]);
|
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||||
|
span: param_span,
|
||||||
|
item: param.path().to_string(),
|
||||||
|
expected: &["feature", "since"],
|
||||||
|
});
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -370,7 +365,7 @@ pub(crate) fn parse_stability<S: Stage>(
|
||||||
/// attribute, and return the feature name and its stability information.
|
/// attribute, and return the feature name and its stability information.
|
||||||
pub(crate) fn parse_unstability<S: Stage>(
|
pub(crate) fn parse_unstability<S: Stage>(
|
||||||
cx: &AcceptContext<'_, '_, S>,
|
cx: &AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &ArgParser<'_>,
|
||||||
) -> Option<(Symbol, StabilityLevel)> {
|
) -> Option<(Symbol, StabilityLevel)> {
|
||||||
let mut feature = None;
|
let mut feature = None;
|
||||||
let mut reason = None;
|
let mut reason = None;
|
||||||
|
|
@ -381,13 +376,18 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||||
let mut old_name = None;
|
let mut old_name = None;
|
||||||
|
|
||||||
let ArgParser::List(list) = args else {
|
let ArgParser::List(list) = args else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
for param in list.mixed() {
|
for param in list.mixed() {
|
||||||
let Some(param) = param.meta_item() else {
|
let Some(param) = param.meta_item() else {
|
||||||
cx.unexpected_literal(param.span());
|
cx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||||
|
span: param.span(),
|
||||||
|
reason: UnsupportedLiteralReason::Generic,
|
||||||
|
is_bytestr: false,
|
||||||
|
start_point_span: cx.sess().source_map().start_point(param.span()),
|
||||||
|
});
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -436,17 +436,11 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||||
insert_value_into_option_or_error(cx, ¶m, &mut old_name, word.unwrap())?
|
insert_value_into_option_or_error(cx, ¶m, &mut old_name, word.unwrap())?
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cx.expected_specific_argument(
|
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||||
param.span(),
|
span: param.span(),
|
||||||
&[
|
item: param.path().to_string(),
|
||||||
sym::feature,
|
expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"],
|
||||||
sym::reason,
|
});
|
||||||
sym::issue,
|
|
||||||
sym::soft,
|
|
||||||
sym::implied_by,
|
|
||||||
sym::old_name,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
use rustc_hir::attrs::RustcAbiAttrKind;
|
|
||||||
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
||||||
pub(crate) struct IgnoreParser;
|
pub(crate) struct IgnoreParser;
|
||||||
|
|
@ -16,20 +13,27 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
||||||
"https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
|
"https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
Some(AttributeKind::Ignore {
|
Some(AttributeKind::Ignore {
|
||||||
span: cx.attr_span,
|
span: cx.attr_span,
|
||||||
reason: match args {
|
reason: match args {
|
||||||
ArgParser::NoArgs => None,
|
ArgParser::NoArgs => None,
|
||||||
ArgParser::NameValue(name_value) => {
|
ArgParser::NameValue(name_value) => {
|
||||||
let Some(str_value) = name_value.value_as_str() else {
|
let Some(str_value) = name_value.value_as_str() else {
|
||||||
cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
|
let suggestions = cx.suggestions();
|
||||||
|
let span = cx.attr_span;
|
||||||
|
cx.emit_lint(
|
||||||
|
AttributeLintKind::IllFormedAttributeInput { suggestions },
|
||||||
|
span,
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
Some(str_value)
|
Some(str_value)
|
||||||
}
|
}
|
||||||
ArgParser::List(_) => {
|
ArgParser::List(_) => {
|
||||||
cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
|
let suggestions = cx.suggestions();
|
||||||
|
let span = cx.attr_span;
|
||||||
|
cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -50,7 +54,7 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
||||||
"https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
|
"https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
|
||||||
);
|
);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
Some(AttributeKind::ShouldPanic {
|
Some(AttributeKind::ShouldPanic {
|
||||||
span: cx.attr_span,
|
span: cx.attr_span,
|
||||||
reason: match args {
|
reason: match args {
|
||||||
|
|
@ -92,201 +96,3 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcVarianceParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_variance];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Struct),
|
|
||||||
Allow(Target::Enum),
|
|
||||||
Allow(Target::Union),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVariance;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcVarianceOfOpaquesParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceOfOpaquesParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_variance_of_opaques];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVarianceOfOpaques;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct ReexportTestHarnessMainParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for ReexportTestHarnessMainParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::reexport_test_harness_main];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(nv) = args.name_value() else {
|
|
||||||
cx.expected_name_value(
|
|
||||||
args.span().unwrap_or(cx.inner_span),
|
|
||||||
Some(sym::reexport_test_harness_main),
|
|
||||||
);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(name) = nv.value_as_str() else {
|
|
||||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::ReexportTestHarnessMain(name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcAbiParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RustcAbiParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_abi];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::debug, sym::assert_eq]);
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::TyAlias),
|
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::ForeignFn),
|
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
|
||||||
]);
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(args) = args.list() else {
|
|
||||||
cx.expected_specific_argument_and_list(cx.attr_span, &[sym::assert_eq, sym::debug]);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(arg) = args.single() else {
|
|
||||||
cx.expected_single_argument(cx.attr_span);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let fail_incorrect_argument =
|
|
||||||
|span| cx.expected_specific_argument(span, &[sym::assert_eq, sym::debug]);
|
|
||||||
|
|
||||||
let Some(arg) = arg.meta_item() else {
|
|
||||||
fail_incorrect_argument(args.span);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let kind: RustcAbiAttrKind = match arg.path().word_sym() {
|
|
||||||
Some(sym::assert_eq) => RustcAbiAttrKind::AssertEq,
|
|
||||||
Some(sym::debug) => RustcAbiAttrKind::Debug,
|
|
||||||
None | Some(_) => {
|
|
||||||
fail_incorrect_argument(arg.span());
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::RustcAbi { attr_span: cx.attr_span, kind })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcDelayedBugFromInsideQueryParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDelayedBugFromInsideQueryParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_delayed_bug_from_inside_query];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDelayedBugFromInsideQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcEvaluateWhereClausesParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcEvaluateWhereClausesParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_evaluate_where_clauses];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEvaluateWhereClauses;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcOutlivesParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcOutlivesParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_outlives];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Struct),
|
|
||||||
Allow(Target::Enum),
|
|
||||||
Allow(Target::Union),
|
|
||||||
Allow(Target::TyAlias),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOutlives;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct TestRunnerParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::test_runner];
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["path"]);
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(list) = args.list() else {
|
|
||||||
cx.expected_list(cx.attr_span, args);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(single) = list.single() else {
|
|
||||||
cx.expected_single_argument(list.span);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(meta) = single.meta_item() else {
|
|
||||||
cx.unexpected_literal(single.span());
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::TestRunner(meta.path().0.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcTestMarkerParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RustcTestMarkerParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_test_marker];
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Const),
|
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::Static),
|
|
||||||
]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "test_path");
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(name_value) = args.name_value() else {
|
|
||||||
cx.expected_name_value(cx.attr_span, Some(sym::rustc_test_marker));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(value_str) = name_value.value_as_str() else {
|
|
||||||
cx.expected_string_literal(name_value.value_span, None);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
if value_str.as_str().trim().is_empty() {
|
|
||||||
cx.expected_non_empty_string_literal(name_value.value_span);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(AttributeKind::RustcTestMarker(value_str))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
|
||||||
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]);
|
const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let mut array = false;
|
let mut array = false;
|
||||||
let mut boxed_slice = false;
|
let mut boxed_slice = false;
|
||||||
let Some(args) = args.list() else {
|
let Some(args) = args.list() else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
|
|
@ -50,11 +50,7 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
|
||||||
cx.duplicate_key(arg.span(), key);
|
cx.duplicate_key(arg.span(), key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(AttributeKind::RustcSkipDuringMethodDispatch {
|
Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
|
||||||
array,
|
|
||||||
boxed_slice,
|
|
||||||
span: cx.attr_span,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,7 +59,16 @@ impl<S: Stage> NoArgsAttributeParser<S> for ParenSugarParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
|
const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ParenSugar;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TypeConstParser;
|
||||||
|
impl<S: Stage> NoArgsAttributeParser<S> for TypeConstParser {
|
||||||
|
const PATH: &[Symbol] = &[sym::type_const];
|
||||||
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
|
const ALLOWED_TARGETS: AllowedTargets =
|
||||||
|
AllowedTargets::AllowList(&[Allow(Target::Const), Allow(Target::AssocConst)]);
|
||||||
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Markers
|
// Markers
|
||||||
|
|
@ -86,15 +91,15 @@ impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
|
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDenyExplicitImpl;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DynIncompatibleTraitParser;
|
pub(crate) struct DoNotImplementViaObjectParser;
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
|
const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDynIncompatibleTrait;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specialization
|
// Specialization
|
||||||
|
|
@ -104,7 +109,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for SpecializationTraitParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
|
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcSpecializationTrait;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::SpecializationTrait;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct UnsafeSpecializationMarkerParser;
|
pub(crate) struct UnsafeSpecializationMarkerParser;
|
||||||
|
|
@ -112,7 +117,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for UnsafeSpecializationMarkerParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
|
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcUnsafeSpecializationMarker;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coherence
|
// Coherence
|
||||||
|
|
@ -122,7 +127,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for CoinductiveParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_coinductive];
|
const PATH: &[Symbol] = &[sym::rustc_coinductive];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoinductive;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Coinductive;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct AllowIncoherentImplParser;
|
pub(crate) struct AllowIncoherentImplParser;
|
||||||
|
|
@ -131,7 +136,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
const ALLOWED_TARGETS: AllowedTargets =
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
|
AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAllowIncoherentImpl;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FundamentalParser;
|
pub(crate) struct FundamentalParser;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ use super::prelude::*;
|
||||||
|
|
||||||
pub(crate) struct TransparencyParser;
|
pub(crate) struct TransparencyParser;
|
||||||
|
|
||||||
|
// FIXME(jdonszelmann): make these proper diagnostics
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||||
|
|
@ -12,26 +15,26 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
||||||
});
|
});
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
|
||||||
const TEMPLATE: AttributeTemplate =
|
const TEMPLATE: AttributeTemplate =
|
||||||
template!(NameValueStr: ["transparent", "semiopaque", "opaque"]);
|
template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||||
let Some(nv) = args.name_value() else {
|
let Some(nv) = args.name_value() else {
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
cx.expected_name_value(cx.attr_span, None);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
match nv.value_as_str() {
|
match nv.value_as_str() {
|
||||||
Some(sym::transparent) => Some(Transparency::Transparent),
|
Some(sym::transparent) => Some(Transparency::Transparent),
|
||||||
Some(sym::semiopaque) => Some(Transparency::SemiOpaque),
|
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
|
||||||
Some(sym::opaque) => Some(Transparency::Opaque),
|
Some(sym::opaque) => Some(Transparency::Opaque),
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
cx.expected_specific_argument_strings(
|
cx.expected_specific_argument_strings(
|
||||||
nv.value_span,
|
nv.value_span,
|
||||||
&[sym::transparent, sym::semiopaque, sym::opaque],
|
&[sym::transparent, sym::semitransparent, sym::opaque],
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
.map(AttributeKind::RustcMacroTransparency)
|
.map(AttributeKind::MacroTransparency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use rustc_ast::attr::AttributeExt;
|
||||||
use rustc_feature::is_builtin_attr_name;
|
use rustc_feature::is_builtin_attr_name;
|
||||||
use rustc_hir::RustcVersion;
|
use rustc_hir::RustcVersion;
|
||||||
use rustc_hir::limit::Limit;
|
use rustc_hir::limit::Limit;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::{Symbol, sym};
|
||||||
|
|
||||||
use crate::context::{AcceptContext, Stage};
|
use crate::context::{AcceptContext, Stage};
|
||||||
use crate::parser::{ArgParser, NameValueParser};
|
use crate::parser::{ArgParser, NameValueParser};
|
||||||
|
|
@ -28,7 +28,38 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
|
pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
|
||||||
attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
|
attr.is_doc_comment().is_some()
|
||||||
|
|| attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>(
|
||||||
|
attrs: impl Iterator<Item = &'tcx T>,
|
||||||
|
symbol: Symbol,
|
||||||
|
) -> bool {
|
||||||
|
let doc_attrs = attrs.filter(|attr| attr.has_name(sym::doc));
|
||||||
|
for attr in doc_attrs {
|
||||||
|
let Some(values) = attr.meta_item_list() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let alias_values = values.iter().filter(|v| v.has_name(sym::alias));
|
||||||
|
for v in alias_values {
|
||||||
|
if let Some(nested) = v.meta_item_list() {
|
||||||
|
// #[doc(alias("foo", "bar"))]
|
||||||
|
let mut iter = nested.iter().filter_map(|item| item.lit()).map(|item| item.symbol);
|
||||||
|
if iter.any(|s| s == symbol) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if let Some(meta) = v.meta_item()
|
||||||
|
&& let Some(lit) = meta.name_value_literal()
|
||||||
|
{
|
||||||
|
// #[doc(alias = "foo")]
|
||||||
|
if lit.symbol == symbol {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a single integer.
|
/// Parse a single integer.
|
||||||
|
|
@ -39,10 +70,10 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
|
||||||
/// `args` is the parser for the attribute arguments.
|
/// `args` is the parser for the attribute arguments.
|
||||||
pub(crate) fn parse_single_integer<S: Stage>(
|
pub(crate) fn parse_single_integer<S: Stage>(
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
cx: &mut AcceptContext<'_, '_, S>,
|
||||||
args: &ArgParser,
|
args: &ArgParser<'_>,
|
||||||
) -> Option<u128> {
|
) -> Option<u128> {
|
||||||
let Some(list) = args.list() else {
|
let Some(list) = args.list() else {
|
||||||
cx.expected_list(cx.attr_span, args);
|
cx.expected_list(cx.attr_span);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let Some(single) = list.single() else {
|
let Some(single) = list.single() else {
|
||||||
|
|
|
||||||
|
|
@ -1,80 +1,100 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::btree_map::Entry;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use private::Sealed;
|
use private::Sealed;
|
||||||
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
|
use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
|
||||||
use rustc_errors::{Diag, Diagnostic, Level};
|
use rustc_errors::{Diag, Diagnostic, Level};
|
||||||
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
|
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
|
||||||
use rustc_hir::attrs::AttributeKind;
|
use rustc_hir::attrs::AttributeKind;
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
|
||||||
use rustc_hir::{AttrPath, HirId};
|
use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
|
||||||
use rustc_parse::parser::Recovery;
|
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::lint::{Lint, LintId};
|
|
||||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||||
|
|
||||||
use crate::AttributeParser;
|
use crate::AttributeParser;
|
||||||
// Glob imports to avoid big, bitrotty import lists
|
use crate::attributes::allow_unstable::{
|
||||||
use crate::attributes::allow_unstable::*;
|
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
|
||||||
use crate::attributes::body::*;
|
};
|
||||||
use crate::attributes::cfi_encoding::*;
|
use crate::attributes::body::CoroutineParser;
|
||||||
use crate::attributes::codegen_attrs::*;
|
use crate::attributes::codegen_attrs::{
|
||||||
use crate::attributes::confusables::*;
|
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
|
||||||
use crate::attributes::crate_level::*;
|
NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
|
||||||
use crate::attributes::debugger::*;
|
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
|
||||||
use crate::attributes::deprecation::*;
|
TrackCallerParser, UsedParser,
|
||||||
use crate::attributes::do_not_recommend::*;
|
};
|
||||||
use crate::attributes::doc::*;
|
use crate::attributes::confusables::ConfusablesParser;
|
||||||
use crate::attributes::dummy::*;
|
use crate::attributes::crate_level::{
|
||||||
use crate::attributes::inline::*;
|
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
|
||||||
use crate::attributes::instruction_set::*;
|
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
|
||||||
use crate::attributes::link_attrs::*;
|
WindowsSubsystemParser,
|
||||||
use crate::attributes::lint_helpers::*;
|
};
|
||||||
use crate::attributes::loop_match::*;
|
use crate::attributes::debugger::DebuggerViualizerParser;
|
||||||
use crate::attributes::macro_attrs::*;
|
use crate::attributes::deprecation::DeprecationParser;
|
||||||
use crate::attributes::must_not_suspend::*;
|
use crate::attributes::dummy::DummyParser;
|
||||||
use crate::attributes::must_use::*;
|
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||||
use crate::attributes::no_implicit_prelude::*;
|
use crate::attributes::link_attrs::{
|
||||||
use crate::attributes::no_link::*;
|
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
|
||||||
use crate::attributes::non_exhaustive::*;
|
LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
|
||||||
|
};
|
||||||
|
use crate::attributes::lint_helpers::{
|
||||||
|
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
|
||||||
|
RustcShouldNotBeCalledOnConstItems,
|
||||||
|
};
|
||||||
|
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
|
||||||
|
use crate::attributes::macro_attrs::{
|
||||||
|
AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser,
|
||||||
|
};
|
||||||
|
use crate::attributes::must_use::MustUseParser;
|
||||||
|
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
|
||||||
|
use crate::attributes::non_exhaustive::NonExhaustiveParser;
|
||||||
use crate::attributes::path::PathParser as PathAttributeParser;
|
use crate::attributes::path::PathParser as PathAttributeParser;
|
||||||
use crate::attributes::pin_v2::*;
|
use crate::attributes::pin_v2::PinV2Parser;
|
||||||
use crate::attributes::proc_macro_attrs::*;
|
use crate::attributes::proc_macro_attrs::{
|
||||||
use crate::attributes::prototype::*;
|
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
|
||||||
use crate::attributes::repr::*;
|
};
|
||||||
use crate::attributes::rustc_allocator::*;
|
use crate::attributes::prototype::CustomMirParser;
|
||||||
use crate::attributes::rustc_dump::*;
|
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||||
use crate::attributes::rustc_internal::*;
|
use crate::attributes::rustc_internal::{
|
||||||
use crate::attributes::semantics::*;
|
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser,
|
||||||
use crate::attributes::stability::*;
|
RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
|
||||||
use crate::attributes::test_attrs::*;
|
};
|
||||||
use crate::attributes::traits::*;
|
use crate::attributes::semantics::MayDangleParser;
|
||||||
use crate::attributes::transparency::*;
|
use crate::attributes::stability::{
|
||||||
|
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||||
|
};
|
||||||
|
use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
|
||||||
|
use crate::attributes::traits::{
|
||||||
|
AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
|
||||||
|
DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
|
||||||
|
PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
|
||||||
|
UnsafeSpecializationMarkerParser,
|
||||||
|
};
|
||||||
|
use crate::attributes::transparency::TransparencyParser;
|
||||||
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
|
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
|
||||||
use crate::parser::{ArgParser, RefPathParser};
|
use crate::parser::{ArgParser, PathParser};
|
||||||
use crate::session_diagnostics::{
|
use crate::session_diagnostics::{
|
||||||
AttributeParseError, AttributeParseErrorReason, ParsedDescription,
|
AttributeParseError, AttributeParseErrorReason, ParsedDescription, UnknownMetaItem,
|
||||||
};
|
};
|
||||||
use crate::target_checking::AllowedTargets;
|
use crate::target_checking::AllowedTargets;
|
||||||
|
|
||||||
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
||||||
|
|
||||||
pub(super) struct GroupTypeInner<S: Stage> {
|
pub(super) struct GroupTypeInner<S: Stage> {
|
||||||
pub(super) accepters: BTreeMap<&'static [Symbol], GroupTypeInnerAccept<S>>,
|
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
|
||||||
|
pub(super) finalizers: Vec<FinalizeFn<S>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
||||||
pub(super) template: AttributeTemplate,
|
pub(super) template: AttributeTemplate,
|
||||||
pub(super) accept_fn: AcceptFn<S>,
|
pub(super) accept_fn: AcceptFn<S>,
|
||||||
pub(super) allowed_targets: AllowedTargets,
|
pub(super) allowed_targets: AllowedTargets,
|
||||||
pub(super) finalizer: FinalizeFn<S>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type AcceptFn<S> =
|
type AcceptFn<S> =
|
||||||
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
|
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>;
|
||||||
pub(crate) type FinalizeFn<S> =
|
type FinalizeFn<S> =
|
||||||
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
||||||
|
|
||||||
macro_rules! attribute_parsers {
|
macro_rules! attribute_parsers {
|
||||||
|
|
@ -102,7 +122,8 @@ macro_rules! attribute_parsers {
|
||||||
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||||
) => {
|
) => {
|
||||||
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
|
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
|
||||||
let mut accepters = BTreeMap::<_, GroupTypeInnerAccept<$stage>>::new();
|
let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||||
|
let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
|
||||||
$(
|
$(
|
||||||
{
|
{
|
||||||
thread_local! {
|
thread_local! {
|
||||||
|
|
@ -110,29 +131,25 @@ macro_rules! attribute_parsers {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||||
match accepters.entry(*path) {
|
accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||||
Entry::Vacant(e) => {
|
template: *template,
|
||||||
e.insert(GroupTypeInnerAccept {
|
accept_fn: Box::new(|cx, args| {
|
||||||
template: *template,
|
STATE_OBJECT.with_borrow_mut(|s| {
|
||||||
accept_fn: Box::new(|cx, args| {
|
accept_fn(s, cx, args)
|
||||||
STATE_OBJECT.with_borrow_mut(|s| {
|
})
|
||||||
accept_fn(s, cx, args)
|
}),
|
||||||
})
|
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
||||||
}),
|
});
|
||||||
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
|
||||||
finalizer: Box::new(|cx| {
|
|
||||||
let state = STATE_OBJECT.take();
|
|
||||||
state.finalize(cx)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizes.push(Box::new(|cx| {
|
||||||
|
let state = STATE_OBJECT.take();
|
||||||
|
state.finalize(cx)
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
GroupTypeInner { accepters }
|
GroupTypeInner { accepters:accepts, finalizers:finalizes }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -144,10 +161,8 @@ attribute_parsers!(
|
||||||
BodyStabilityParser,
|
BodyStabilityParser,
|
||||||
ConfusablesParser,
|
ConfusablesParser,
|
||||||
ConstStabilityParser,
|
ConstStabilityParser,
|
||||||
DocParser,
|
|
||||||
MacroUseParser,
|
MacroUseParser,
|
||||||
NakedParser,
|
NakedParser,
|
||||||
RustcCguTestAttributeParser,
|
|
||||||
StabilityParser,
|
StabilityParser,
|
||||||
UsedParser,
|
UsedParser,
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
@ -155,73 +170,46 @@ attribute_parsers!(
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
Combine<AllowConstFnUnstableParser>,
|
Combine<AllowConstFnUnstableParser>,
|
||||||
Combine<AllowInternalUnstableParser>,
|
Combine<AllowInternalUnstableParser>,
|
||||||
Combine<CrateTypeParser>,
|
|
||||||
Combine<DebuggerViualizerParser>,
|
Combine<DebuggerViualizerParser>,
|
||||||
Combine<ForceTargetFeatureParser>,
|
Combine<ForceTargetFeatureParser>,
|
||||||
Combine<LinkParser>,
|
Combine<LinkParser>,
|
||||||
Combine<ReprParser>,
|
Combine<ReprParser>,
|
||||||
Combine<RustcCleanParser>,
|
|
||||||
Combine<RustcLayoutParser>,
|
|
||||||
Combine<RustcMirParser>,
|
|
||||||
Combine<RustcThenThisWouldNeedParser>,
|
|
||||||
Combine<TargetFeatureParser>,
|
Combine<TargetFeatureParser>,
|
||||||
Combine<UnstableFeatureBoundParser>,
|
Combine<UnstableFeatureBoundParser>,
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
Single<CfiEncodingParser>,
|
|
||||||
Single<CollapseDebugInfoParser>,
|
|
||||||
Single<CoverageParser>,
|
Single<CoverageParser>,
|
||||||
Single<CrateNameParser>,
|
Single<CrateNameParser>,
|
||||||
Single<CustomMirParser>,
|
Single<CustomMirParser>,
|
||||||
Single<DeprecationParser>,
|
Single<DeprecationParser>,
|
||||||
Single<DoNotRecommendParser>,
|
|
||||||
Single<DummyParser>,
|
Single<DummyParser>,
|
||||||
Single<ExportNameParser>,
|
Single<ExportNameParser>,
|
||||||
Single<IgnoreParser>,
|
Single<IgnoreParser>,
|
||||||
Single<InlineParser>,
|
Single<InlineParser>,
|
||||||
Single<InstructionSetParser>,
|
|
||||||
Single<LangParser>,
|
|
||||||
Single<LinkNameParser>,
|
Single<LinkNameParser>,
|
||||||
Single<LinkOrdinalParser>,
|
Single<LinkOrdinalParser>,
|
||||||
Single<LinkSectionParser>,
|
Single<LinkSectionParser>,
|
||||||
Single<LinkageParser>,
|
Single<LinkageParser>,
|
||||||
Single<MacroExportParser>,
|
Single<MacroExportParser>,
|
||||||
Single<MoveSizeLimitParser>,
|
Single<MoveSizeLimitParser>,
|
||||||
Single<MustNotSuspendParser>,
|
|
||||||
Single<MustUseParser>,
|
Single<MustUseParser>,
|
||||||
Single<ObjcClassParser>,
|
Single<ObjcClassParser>,
|
||||||
Single<ObjcSelectorParser>,
|
Single<ObjcSelectorParser>,
|
||||||
Single<OptimizeParser>,
|
Single<OptimizeParser>,
|
||||||
Single<PatchableFunctionEntryParser>,
|
|
||||||
Single<PathAttributeParser>,
|
Single<PathAttributeParser>,
|
||||||
Single<PatternComplexityLimitParser>,
|
Single<PatternComplexityLimitParser>,
|
||||||
Single<ProcMacroDeriveParser>,
|
Single<ProcMacroDeriveParser>,
|
||||||
Single<RecursionLimitParser>,
|
Single<RecursionLimitParser>,
|
||||||
Single<ReexportTestHarnessMainParser>,
|
|
||||||
Single<RustcAbiParser>,
|
|
||||||
Single<RustcAllocatorZeroedVariantParser>,
|
|
||||||
Single<RustcBuiltinMacroParser>,
|
Single<RustcBuiltinMacroParser>,
|
||||||
Single<RustcDefPath>,
|
|
||||||
Single<RustcDeprecatedSafe2024Parser>,
|
|
||||||
Single<RustcDiagnosticItemParser>,
|
|
||||||
Single<RustcForceInlineParser>,
|
Single<RustcForceInlineParser>,
|
||||||
Single<RustcIfThisChangedParser>,
|
|
||||||
Single<RustcLayoutScalarValidRangeEndParser>,
|
Single<RustcLayoutScalarValidRangeEndParser>,
|
||||||
Single<RustcLayoutScalarValidRangeStartParser>,
|
Single<RustcLayoutScalarValidRangeStartParser>,
|
||||||
Single<RustcLegacyConstGenericsParser>,
|
Single<RustcObjectLifetimeDefaultParser>,
|
||||||
Single<RustcLintOptDenyFieldAccessParser>,
|
|
||||||
Single<RustcMustImplementOneOfParser>,
|
|
||||||
Single<RustcNeverTypeOptionsParser>,
|
|
||||||
Single<RustcReservationImplParser>,
|
|
||||||
Single<RustcScalableVectorParser>,
|
|
||||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||||
Single<RustcSymbolName>,
|
|
||||||
Single<RustcTestMarkerParser>,
|
|
||||||
Single<SanitizeParser>,
|
Single<SanitizeParser>,
|
||||||
Single<ShouldPanicParser>,
|
Single<ShouldPanicParser>,
|
||||||
Single<SkipDuringMethodDispatchParser>,
|
Single<SkipDuringMethodDispatchParser>,
|
||||||
Single<TestRunnerParser>,
|
|
||||||
Single<TransparencyParser>,
|
Single<TransparencyParser>,
|
||||||
Single<TypeLengthLimitParser>,
|
Single<TypeLengthLimitParser>,
|
||||||
Single<WindowsSubsystemParser>,
|
Single<WindowsSubsystemParser>,
|
||||||
|
|
@ -231,14 +219,11 @@ attribute_parsers!(
|
||||||
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
||||||
Single<WithoutArgs<CoinductiveParser>>,
|
Single<WithoutArgs<CoinductiveParser>>,
|
||||||
Single<WithoutArgs<ColdParser>>,
|
Single<WithoutArgs<ColdParser>>,
|
||||||
Single<WithoutArgs<CompilerBuiltinsParser>>,
|
|
||||||
Single<WithoutArgs<ConstContinueParser>>,
|
Single<WithoutArgs<ConstContinueParser>>,
|
||||||
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
||||||
Single<WithoutArgs<CoroutineParser>>,
|
Single<WithoutArgs<CoroutineParser>>,
|
||||||
Single<WithoutArgs<DefaultLibAllocatorParser>>,
|
|
||||||
Single<WithoutArgs<DenyExplicitImplParser>>,
|
Single<WithoutArgs<DenyExplicitImplParser>>,
|
||||||
Single<WithoutArgs<DynIncompatibleTraitParser>>,
|
Single<WithoutArgs<DoNotImplementViaObjectParser>>,
|
||||||
Single<WithoutArgs<EiiForeignItemParser>>,
|
|
||||||
Single<WithoutArgs<ExportStableParser>>,
|
Single<WithoutArgs<ExportStableParser>>,
|
||||||
Single<WithoutArgs<FfiConstParser>>,
|
Single<WithoutArgs<FfiConstParser>>,
|
||||||
Single<WithoutArgs<FfiPureParser>>,
|
Single<WithoutArgs<FfiPureParser>>,
|
||||||
|
|
@ -247,75 +232,26 @@ attribute_parsers!(
|
||||||
Single<WithoutArgs<MacroEscapeParser>>,
|
Single<WithoutArgs<MacroEscapeParser>>,
|
||||||
Single<WithoutArgs<MarkerParser>>,
|
Single<WithoutArgs<MarkerParser>>,
|
||||||
Single<WithoutArgs<MayDangleParser>>,
|
Single<WithoutArgs<MayDangleParser>>,
|
||||||
Single<WithoutArgs<NeedsAllocatorParser>>,
|
|
||||||
Single<WithoutArgs<NeedsPanicRuntimeParser>>,
|
|
||||||
Single<WithoutArgs<NoBuiltinsParser>>,
|
|
||||||
Single<WithoutArgs<NoCoreParser>>,
|
Single<WithoutArgs<NoCoreParser>>,
|
||||||
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
||||||
Single<WithoutArgs<NoLinkParser>>,
|
|
||||||
Single<WithoutArgs<NoMainParser>>,
|
|
||||||
Single<WithoutArgs<NoMangleParser>>,
|
Single<WithoutArgs<NoMangleParser>>,
|
||||||
Single<WithoutArgs<NoStdParser>>,
|
Single<WithoutArgs<NoStdParser>>,
|
||||||
Single<WithoutArgs<NonExhaustiveParser>>,
|
Single<WithoutArgs<NonExhaustiveParser>>,
|
||||||
Single<WithoutArgs<PanicHandlerParser>>,
|
|
||||||
Single<WithoutArgs<PanicRuntimeParser>>,
|
|
||||||
Single<WithoutArgs<ParenSugarParser>>,
|
Single<WithoutArgs<ParenSugarParser>>,
|
||||||
Single<WithoutArgs<PassByValueParser>>,
|
Single<WithoutArgs<PassByValueParser>>,
|
||||||
Single<WithoutArgs<PinV2Parser>>,
|
Single<WithoutArgs<PinV2Parser>>,
|
||||||
Single<WithoutArgs<PointeeParser>>,
|
Single<WithoutArgs<PointeeParser>>,
|
||||||
Single<WithoutArgs<PreludeImportParser>>,
|
|
||||||
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
||||||
Single<WithoutArgs<ProcMacroParser>>,
|
Single<WithoutArgs<ProcMacroParser>>,
|
||||||
Single<WithoutArgs<ProfilerRuntimeParser>>,
|
|
||||||
Single<WithoutArgs<PubTransparentParser>>,
|
Single<WithoutArgs<PubTransparentParser>>,
|
||||||
Single<WithoutArgs<RustcAllocatorParser>>,
|
|
||||||
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
|
|
||||||
Single<WithoutArgs<RustcCaptureAnalysisParser>>,
|
|
||||||
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
||||||
Single<WithoutArgs<RustcConversionSuggestionParser>>,
|
|
||||||
Single<WithoutArgs<RustcDeallocatorParser>>,
|
|
||||||
Single<WithoutArgs<RustcDelayedBugFromInsideQueryParser>>,
|
|
||||||
Single<WithoutArgs<RustcDoNotConstCheckParser>>,
|
|
||||||
Single<WithoutArgs<RustcDumpDefParentsParser>>,
|
|
||||||
Single<WithoutArgs<RustcDumpItemBoundsParser>>,
|
|
||||||
Single<WithoutArgs<RustcDumpPredicatesParser>>,
|
|
||||||
Single<WithoutArgs<RustcDumpUserArgsParser>>,
|
|
||||||
Single<WithoutArgs<RustcDumpVtableParser>>,
|
|
||||||
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
|
|
||||||
Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
|
|
||||||
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
|
||||||
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
|
|
||||||
Single<WithoutArgs<RustcInsignificantDtorParser>>,
|
|
||||||
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
|
|
||||||
Single<WithoutArgs<RustcIntrinsicParser>>,
|
|
||||||
Single<WithoutArgs<RustcLintOptTyParser>>,
|
|
||||||
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
|
|
||||||
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
|
|
||||||
Single<WithoutArgs<RustcMainParser>>,
|
Single<WithoutArgs<RustcMainParser>>,
|
||||||
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
|
||||||
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
|
||||||
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
|
|
||||||
Single<WithoutArgs<RustcNoMirInlineParser>>,
|
|
||||||
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
|
|
||||||
Single<WithoutArgs<RustcNonnullOptimizationGuaranteedParser>>,
|
|
||||||
Single<WithoutArgs<RustcNounwindParser>>,
|
|
||||||
Single<WithoutArgs<RustcObjectLifetimeDefaultParser>>,
|
|
||||||
Single<WithoutArgs<RustcOffloadKernelParser>>,
|
|
||||||
Single<WithoutArgs<RustcOutlivesParser>>,
|
|
||||||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||||
Single<WithoutArgs<RustcPreserveUbChecksParser>>,
|
|
||||||
Single<WithoutArgs<RustcProcMacroDeclsParser>>,
|
|
||||||
Single<WithoutArgs<RustcReallocatorParser>>,
|
|
||||||
Single<WithoutArgs<RustcRegionsParser>>,
|
|
||||||
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
||||||
Single<WithoutArgs<RustcStrictCoherenceParser>>,
|
|
||||||
Single<WithoutArgs<RustcTrivialFieldReadsParser>>,
|
|
||||||
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
|
|
||||||
Single<WithoutArgs<RustcVarianceParser>>,
|
|
||||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||||
Single<WithoutArgs<StdInternalSymbolParser>>,
|
Single<WithoutArgs<StdInternalSymbolParser>>,
|
||||||
Single<WithoutArgs<ThreadLocalParser>>,
|
|
||||||
Single<WithoutArgs<TrackCallerParser>>,
|
Single<WithoutArgs<TrackCallerParser>>,
|
||||||
|
Single<WithoutArgs<TypeConstParser>>,
|
||||||
Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
|
Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
];
|
];
|
||||||
|
|
@ -341,6 +277,8 @@ pub trait Stage: Sized + 'static + Sealed {
|
||||||
) -> ErrorGuaranteed;
|
) -> ErrorGuaranteed;
|
||||||
|
|
||||||
fn should_emit(&self) -> ShouldEmit;
|
fn should_emit(&self) -> ShouldEmit;
|
||||||
|
|
||||||
|
fn id_is_crate_root(id: Self::Id) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow because it's a sealed trait
|
// allow because it's a sealed trait
|
||||||
|
|
@ -362,6 +300,10 @@ impl Stage for Early {
|
||||||
fn should_emit(&self) -> ShouldEmit {
|
fn should_emit(&self) -> ShouldEmit {
|
||||||
self.emit_errors
|
self.emit_errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn id_is_crate_root(id: Self::Id) -> bool {
|
||||||
|
id == CRATE_NODE_ID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow because it's a sealed trait
|
// allow because it's a sealed trait
|
||||||
|
|
@ -381,7 +323,11 @@ impl Stage for Late {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_emit(&self) -> ShouldEmit {
|
fn should_emit(&self) -> ShouldEmit {
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }
|
ShouldEmit::ErrorsAndLints
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id_is_crate_root(id: Self::Id) -> bool {
|
||||||
|
id == CRATE_HIR_ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -435,19 +381,19 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
||||||
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
|
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
|
||||||
/// must be delayed until after HIR is built. This method will take care of the details of
|
/// must be delayed until after HIR is built. This method will take care of the details of
|
||||||
/// that.
|
/// that.
|
||||||
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
|
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
|
||||||
if !matches!(
|
if !matches!(
|
||||||
self.stage.should_emit(),
|
self.stage.should_emit(),
|
||||||
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(self.emit_lint)(LintId::of(lint), span, kind);
|
let id = self.target_id;
|
||||||
|
(self.emit_lint)(AttributeLint { id, span, kind: lint });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
|
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
|
||||||
self.emit_lint(
|
self.emit_lint(
|
||||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
|
||||||
AttributeLintKind::UnusedDuplicate {
|
AttributeLintKind::UnusedDuplicate {
|
||||||
this: unused_span,
|
this: unused_span,
|
||||||
other: used_span,
|
other: used_span,
|
||||||
|
|
@ -463,7 +409,6 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
||||||
unused_span: Span,
|
unused_span: Span,
|
||||||
) {
|
) {
|
||||||
self.emit_lint(
|
self.emit_lint(
|
||||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
|
||||||
AttributeLintKind::UnusedDuplicate {
|
AttributeLintKind::UnusedDuplicate {
|
||||||
this: unused_span,
|
this: unused_span,
|
||||||
other: used_span,
|
other: used_span,
|
||||||
|
|
@ -475,20 +420,13 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||||
fn emit_parse_error(
|
pub(crate) fn unknown_key(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
reason: AttributeParseErrorReason<'_>,
|
found: String,
|
||||||
|
options: &'static [&'static str],
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
self.emit_err(AttributeParseError {
|
self.emit_err(UnknownMetaItem { span, item: found, expected: options })
|
||||||
span,
|
|
||||||
attr_span: self.attr_span,
|
|
||||||
template: self.template.clone(),
|
|
||||||
path: self.attr_path.clone(),
|
|
||||||
description: self.parsed_description,
|
|
||||||
reason,
|
|
||||||
suggestions: self.suggestions(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// error that a string literal was expected.
|
/// error that a string literal was expected.
|
||||||
|
|
@ -500,101 +438,133 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||||
span: Span,
|
span: Span,
|
||||||
actual_literal: Option<&MetaItemLit>,
|
actual_literal: Option<&MetaItemLit>,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(
|
self.emit_err(AttributeParseError {
|
||||||
span,
|
span,
|
||||||
AttributeParseErrorReason::ExpectedStringLiteral {
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedStringLiteral {
|
||||||
byte_string: actual_literal.and_then(|i| {
|
byte_string: actual_literal.and_then(|i| {
|
||||||
i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
|
i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
)
|
suggestions: self.suggestions(),
|
||||||
}
|
})
|
||||||
|
|
||||||
/// Error that a filename string literal was expected.
|
|
||||||
pub(crate) fn expected_filename_literal(&self, span: Span) {
|
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedFilenameLiteral);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
|
pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral)
|
self.emit_err(AttributeParseError {
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn expected_integer_literal_in_range(
|
|
||||||
&self,
|
|
||||||
span: Span,
|
|
||||||
lower_bound: isize,
|
|
||||||
upper_bound: isize,
|
|
||||||
) -> ErrorGuaranteed {
|
|
||||||
self.emit_parse_error(
|
|
||||||
span,
|
span,
|
||||||
AttributeParseErrorReason::ExpectedIntegerLiteralInRange { lower_bound, upper_bound },
|
attr_span: self.attr_span,
|
||||||
)
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
|
||||||
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
|
pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
|
||||||
let span = match args {
|
self.emit_err(AttributeParseError {
|
||||||
ArgParser::NoArgs => span,
|
|
||||||
ArgParser::List(list) => list.span,
|
|
||||||
ArgParser::NameValue(nv) => nv.args_span(),
|
|
||||||
};
|
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedList)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn expected_list_with_num_args_or_more(
|
|
||||||
&self,
|
|
||||||
args: usize,
|
|
||||||
span: Span,
|
|
||||||
) -> ErrorGuaranteed {
|
|
||||||
self.emit_parse_error(
|
|
||||||
span,
|
span,
|
||||||
AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args },
|
attr_span: self.attr_span,
|
||||||
)
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedList,
|
||||||
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expected_list_or_no_args(&self, span: Span) -> ErrorGuaranteed {
|
pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedListOrNoArgs)
|
self.emit_err(AttributeParseError {
|
||||||
}
|
span: args_span,
|
||||||
|
attr_span: self.attr_span,
|
||||||
pub(crate) fn expected_nv_or_no_args(&self, span: Span) -> ErrorGuaranteed {
|
template: self.template.clone(),
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValueOrNoArgs)
|
path: self.attr_path.clone(),
|
||||||
}
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedNoArgs,
|
||||||
pub(crate) fn expected_non_empty_string_literal(&self, span: Span) -> ErrorGuaranteed {
|
suggestions: self.suggestions(),
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNonEmptyStringLiteral)
|
})
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn expected_no_args(&self, span: Span) -> ErrorGuaranteed {
|
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNoArgs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emit an error that a `name` was expected here
|
/// emit an error that a `name` was expected here
|
||||||
pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
|
pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIdentifier)
|
self.emit_err(AttributeParseError {
|
||||||
|
span,
|
||||||
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedIdentifier,
|
||||||
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
|
/// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
|
||||||
/// a nicer error message talking about the specific name that was found lacking a value.
|
/// a nicer error message talking about the specific name that was found lacking a value.
|
||||||
pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
|
pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValue(name))
|
self.emit_err(AttributeParseError {
|
||||||
|
span,
|
||||||
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedNameValue(name),
|
||||||
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emit an error that a `name = value` pair was found where that name was already seen.
|
/// emit an error that a `name = value` pair was found where that name was already seen.
|
||||||
pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
|
pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::DuplicateKey(key))
|
self.emit_err(AttributeParseError {
|
||||||
|
span,
|
||||||
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::DuplicateKey(key),
|
||||||
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
|
/// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
|
||||||
/// was expected *not* to be a literal, but instead a meta item.
|
/// was expected *not* to be a literal, but instead a meta item.
|
||||||
pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
|
pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::UnexpectedLiteral)
|
self.emit_err(AttributeParseError {
|
||||||
|
span,
|
||||||
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::UnexpectedLiteral,
|
||||||
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
|
pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedSingleArgument)
|
self.emit_err(AttributeParseError {
|
||||||
|
span,
|
||||||
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedSingleArgument,
|
||||||
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
|
pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedAtLeastOneArgument)
|
self.emit_err(AttributeParseError {
|
||||||
|
span,
|
||||||
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
|
||||||
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// produces an error along the lines of `expected one of [foo, meow]`
|
/// produces an error along the lines of `expected one of [foo, meow]`
|
||||||
|
|
@ -603,14 +573,19 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||||
span: Span,
|
span: Span,
|
||||||
possibilities: &[Symbol],
|
possibilities: &[Symbol],
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(
|
self.emit_err(AttributeParseError {
|
||||||
span,
|
span,
|
||||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||||
possibilities,
|
possibilities,
|
||||||
strings: false,
|
strings: false,
|
||||||
list: false,
|
list: false,
|
||||||
},
|
},
|
||||||
)
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// produces an error along the lines of `expected one of [foo, meow] as an argument`.
|
/// produces an error along the lines of `expected one of [foo, meow] as an argument`.
|
||||||
|
|
@ -620,14 +595,19 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||||
span: Span,
|
span: Span,
|
||||||
possibilities: &[Symbol],
|
possibilities: &[Symbol],
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(
|
self.emit_err(AttributeParseError {
|
||||||
span,
|
span,
|
||||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||||
possibilities,
|
possibilities,
|
||||||
strings: false,
|
strings: false,
|
||||||
list: true,
|
list: true,
|
||||||
},
|
},
|
||||||
)
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// produces an error along the lines of `expected one of ["foo", "meow"]`
|
/// produces an error along the lines of `expected one of ["foo", "meow"]`
|
||||||
|
|
@ -636,36 +616,30 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||||
span: Span,
|
span: Span,
|
||||||
possibilities: &[Symbol],
|
possibilities: &[Symbol],
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(
|
self.emit_err(AttributeParseError {
|
||||||
span,
|
span,
|
||||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
attr_span: self.attr_span,
|
||||||
|
template: self.template.clone(),
|
||||||
|
path: self.attr_path.clone(),
|
||||||
|
description: self.parsed_description,
|
||||||
|
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||||
possibilities,
|
possibilities,
|
||||||
strings: true,
|
strings: true,
|
||||||
list: false,
|
list: false,
|
||||||
},
|
},
|
||||||
)
|
suggestions: self.suggestions(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
|
pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
|
||||||
let attr_path = self.attr_path.clone().to_string();
|
let attr_path = self.attr_path.clone();
|
||||||
let valid_without_list = self.template.word;
|
let valid_without_list = self.template.word;
|
||||||
self.emit_lint(
|
self.emit_lint(
|
||||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
|
||||||
AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list },
|
AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list },
|
||||||
span,
|
span,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn warn_ill_formed_attribute_input(&mut self, lint: &'static Lint) {
|
|
||||||
let suggestions = self.suggestions();
|
|
||||||
let span = self.attr_span;
|
|
||||||
self.emit_lint(
|
|
||||||
lint,
|
|
||||||
AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None },
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn suggestions(&self) -> Vec<String> {
|
pub(crate) fn suggestions(&self) -> Vec<String> {
|
||||||
let style = match self.parsed_description {
|
let style = match self.parsed_description {
|
||||||
// If the outer and inner spans are equal, we are parsing an embedded attribute
|
// If the outer and inner spans are equal, we are parsing an embedded attribute
|
||||||
|
|
@ -704,11 +678,10 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
|
||||||
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
|
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
|
||||||
/// The span of the syntactical component this attribute was applied to
|
/// The span of the syntactical component this attribute was applied to
|
||||||
pub(crate) target_span: Span,
|
pub(crate) target_span: Span,
|
||||||
pub(crate) target: rustc_hir::Target,
|
/// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
|
||||||
|
pub(crate) target_id: S::Id,
|
||||||
|
|
||||||
/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
|
pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
|
||||||
/// is `Late` and is the ID of the syntactical component this attribute was applied to.
|
|
||||||
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Context given to every attribute parser during finalization.
|
/// Context given to every attribute parser during finalization.
|
||||||
|
|
@ -724,7 +697,7 @@ pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
|
||||||
///
|
///
|
||||||
/// Usually, you should use normal attribute parsing logic instead,
|
/// Usually, you should use normal attribute parsing logic instead,
|
||||||
/// especially when making a *denylist* of other attributes.
|
/// especially when making a *denylist* of other attributes.
|
||||||
pub(crate) all_attrs: &'p [RefPathParser<'p>],
|
pub(crate) all_attrs: &'p [PathParser<'p>],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
|
impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
|
||||||
|
|
@ -770,18 +743,9 @@ pub enum ShouldEmit {
|
||||||
EarlyFatal { also_emit_lints: bool },
|
EarlyFatal { also_emit_lints: bool },
|
||||||
/// The operation will emit errors and lints.
|
/// The operation will emit errors and lints.
|
||||||
/// This is usually what you need.
|
/// This is usually what you need.
|
||||||
ErrorsAndLints {
|
ErrorsAndLints,
|
||||||
/// Whether [`ArgParser`] will attempt to recover from errors.
|
/// The operation will emit *not* errors and lints.
|
||||||
///
|
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
|
||||||
/// Whether it is allowed to recover from bad input (like an invalid literal). Setting
|
|
||||||
/// this to `Forbidden` will instead return early, and not raise errors except at the top
|
|
||||||
/// level (in [`ArgParser::from_attr_args`]).
|
|
||||||
recovery: Recovery,
|
|
||||||
},
|
|
||||||
/// The operation will *not* emit errors and lints.
|
|
||||||
///
|
|
||||||
/// The parser can still call `delay_bug`, so you *must* ensure that this operation will also be
|
|
||||||
/// called with `ShouldEmit::ErrorsAndLints`.
|
|
||||||
Nothing,
|
Nothing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -790,7 +754,7 @@ impl ShouldEmit {
|
||||||
match self {
|
match self {
|
||||||
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
|
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
|
||||||
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
|
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
|
||||||
ShouldEmit::ErrorsAndLints { .. } => diag.emit(),
|
ShouldEmit::ErrorsAndLints => diag.emit(),
|
||||||
ShouldEmit::Nothing => diag.delay_as_bug(),
|
ShouldEmit::Nothing => diag.delay_as_bug(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
use rustc_ast::EarlyParsedAttribute;
|
|
||||||
use rustc_ast::attr::data_structures::CfgEntry;
|
|
||||||
use rustc_hir::Attribute;
|
|
||||||
use rustc_hir::attrs::AttributeKind;
|
|
||||||
use rustc_span::{Span, Symbol, sym};
|
|
||||||
use thin_vec::ThinVec;
|
|
||||||
|
|
||||||
pub(crate) const EARLY_PARSED_ATTRIBUTES: &[&[Symbol]] =
|
|
||||||
&[&[sym::cfg_trace], &[sym::cfg_attr_trace]];
|
|
||||||
|
|
||||||
/// This struct contains the state necessary to convert early parsed attributes to hir attributes
|
|
||||||
/// The only conversion that really happens here is that multiple early parsed attributes are
|
|
||||||
/// merged into a single hir attribute, representing their combined state.
|
|
||||||
/// FIXME: We should make this a nice and extendable system if this is going to be used more often
|
|
||||||
#[derive(Default)]
|
|
||||||
pub(crate) struct EarlyParsedState {
|
|
||||||
/// Attribute state for `#[cfg]` trace attributes
|
|
||||||
cfg_trace: ThinVec<(CfgEntry, Span)>,
|
|
||||||
|
|
||||||
/// Attribute state for `#[cfg_attr]` trace attributes
|
|
||||||
/// The arguments of these attributes is no longer relevant for any later passes, only their presence.
|
|
||||||
/// So we discard the arguments here.
|
|
||||||
cfg_attr_trace: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EarlyParsedState {
|
|
||||||
pub(crate) fn accept_early_parsed_attribute(
|
|
||||||
&mut self,
|
|
||||||
attr_span: Span,
|
|
||||||
lower_span: impl Copy + Fn(Span) -> Span,
|
|
||||||
parsed: &EarlyParsedAttribute,
|
|
||||||
) {
|
|
||||||
match parsed {
|
|
||||||
EarlyParsedAttribute::CfgTrace(cfg) => {
|
|
||||||
let mut cfg = cfg.clone();
|
|
||||||
cfg.lower_spans(lower_span);
|
|
||||||
self.cfg_trace.push((cfg, attr_span));
|
|
||||||
}
|
|
||||||
EarlyParsedAttribute::CfgAttrTrace => {
|
|
||||||
self.cfg_attr_trace = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn finalize_early_parsed_attributes(self, attributes: &mut Vec<Attribute>) {
|
|
||||||
if !self.cfg_trace.is_empty() {
|
|
||||||
attributes.push(Attribute::Parsed(AttributeKind::CfgTrace(self.cfg_trace)));
|
|
||||||
}
|
|
||||||
if self.cfg_attr_trace {
|
|
||||||
attributes.push(Attribute::Parsed(AttributeKind::CfgAttrTrace));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +1,17 @@
|
||||||
use std::convert::identity;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::token::DocFragmentKind;
|
use rustc_ast::{AttrStyle, NodeId, Safety};
|
||||||
use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
|
|
||||||
use rustc_errors::DiagCtxtHandle;
|
use rustc_errors::DiagCtxtHandle;
|
||||||
use rustc_feature::{AttributeTemplate, Features};
|
use rustc_feature::{AttributeTemplate, Features};
|
||||||
use rustc_hir::attrs::AttributeKind;
|
use rustc_hir::attrs::AttributeKind;
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
use rustc_hir::lints::AttributeLint;
|
||||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
|
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::lint::{BuiltinLintDiag, LintId};
|
|
||||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||||
|
|
||||||
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
|
use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
|
||||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
use crate::parser::{ArgParser, MetaItemParser, PathParser};
|
||||||
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
|
||||||
use crate::session_diagnostics::ParsedDescription;
|
use crate::session_diagnostics::ParsedDescription;
|
||||||
use crate::{Early, Late, OmitDoc, ShouldEmit};
|
use crate::{Early, Late, OmitDoc, ShouldEmit};
|
||||||
|
|
||||||
|
|
@ -113,16 +110,12 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||||
p.parse_attribute_list(
|
p.parse_attribute_list(
|
||||||
attrs,
|
attrs,
|
||||||
target_span,
|
target_span,
|
||||||
|
target_node_id,
|
||||||
target,
|
target,
|
||||||
OmitDoc::Skip,
|
OmitDoc::Skip,
|
||||||
std::convert::identity,
|
std::convert::identity,
|
||||||
|lint_id, span, kind| {
|
|lint| {
|
||||||
sess.psess.buffer_lint(
|
crate::lints::emit_attribute_lint(&lint, sess);
|
||||||
lint_id.lint,
|
|
||||||
span,
|
|
||||||
target_node_id,
|
|
||||||
BuiltinLintDiag::AttributeLint(kind),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -134,10 +127,9 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||||
attr: &ast::Attribute,
|
attr: &ast::Attribute,
|
||||||
target_span: Span,
|
target_span: Span,
|
||||||
target_node_id: NodeId,
|
target_node_id: NodeId,
|
||||||
target: Target,
|
|
||||||
features: Option<&'sess Features>,
|
features: Option<&'sess Features>,
|
||||||
emit_errors: ShouldEmit,
|
emit_errors: ShouldEmit,
|
||||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
|
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option<T>,
|
||||||
template: &AttributeTemplate,
|
template: &AttributeTemplate,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
|
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
|
||||||
|
|
@ -145,28 +137,22 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||||
};
|
};
|
||||||
let parts =
|
let parts =
|
||||||
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||||
|
let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?;
|
||||||
let path = AttrPath::from_ast(&normal_attr.item.path, identity);
|
let path = meta_parser.path();
|
||||||
let args = ArgParser::from_attr_args(
|
let args = meta_parser.args();
|
||||||
&normal_attr.item.args.unparsed_ref().unwrap(),
|
|
||||||
&parts,
|
|
||||||
&sess.psess,
|
|
||||||
emit_errors,
|
|
||||||
)?;
|
|
||||||
Self::parse_single_args(
|
Self::parse_single_args(
|
||||||
sess,
|
sess,
|
||||||
attr.span,
|
attr.span,
|
||||||
normal_attr.item.span(),
|
normal_attr.item.span(),
|
||||||
attr.style,
|
attr.style,
|
||||||
path,
|
path.get_attribute_path(),
|
||||||
Some(normal_attr.item.unsafety),
|
Some(normal_attr.item.unsafety),
|
||||||
ParsedDescription::Attribute,
|
ParsedDescription::Attribute,
|
||||||
target_span,
|
target_span,
|
||||||
target_node_id,
|
target_node_id,
|
||||||
target,
|
|
||||||
features,
|
features,
|
||||||
emit_errors,
|
emit_errors,
|
||||||
&args,
|
args,
|
||||||
parse_fn,
|
parse_fn,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
|
|
@ -184,7 +170,6 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||||
parsed_description: ParsedDescription,
|
parsed_description: ParsedDescription,
|
||||||
target_span: Span,
|
target_span: Span,
|
||||||
target_node_id: NodeId,
|
target_node_id: NodeId,
|
||||||
target: Target,
|
|
||||||
features: Option<&'sess Features>,
|
features: Option<&'sess Features>,
|
||||||
emit_errors: ShouldEmit,
|
emit_errors: ShouldEmit,
|
||||||
args: &I,
|
args: &I,
|
||||||
|
|
@ -198,22 +183,23 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||||
sess,
|
sess,
|
||||||
stage: Early { emit_errors },
|
stage: Early { emit_errors },
|
||||||
};
|
};
|
||||||
let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
|
let mut emit_lint = |lint| {
|
||||||
sess.psess.buffer_lint(
|
crate::lints::emit_attribute_lint(&lint, sess);
|
||||||
lint_id.lint,
|
|
||||||
span,
|
|
||||||
target_node_id,
|
|
||||||
BuiltinLintDiag::AttributeLint(kind),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
if let Some(safety) = attr_safety {
|
if let Some(safety) = attr_safety {
|
||||||
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
|
parser.check_attribute_safety(
|
||||||
|
&attr_path,
|
||||||
|
inner_span,
|
||||||
|
safety,
|
||||||
|
&mut emit_lint,
|
||||||
|
target_node_id,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
|
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
|
||||||
shared: SharedContext {
|
shared: SharedContext {
|
||||||
cx: &mut parser,
|
cx: &mut parser,
|
||||||
target_span,
|
target_span,
|
||||||
target,
|
target_id: target_node_id,
|
||||||
emit_lint: &mut emit_lint,
|
emit_lint: &mut emit_lint,
|
||||||
},
|
},
|
||||||
attr_span,
|
attr_span,
|
||||||
|
|
@ -261,16 +247,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
&mut self,
|
&mut self,
|
||||||
attrs: &[ast::Attribute],
|
attrs: &[ast::Attribute],
|
||||||
target_span: Span,
|
target_span: Span,
|
||||||
|
target_id: S::Id,
|
||||||
target: Target,
|
target: Target,
|
||||||
omit_doc: OmitDoc,
|
omit_doc: OmitDoc,
|
||||||
|
|
||||||
lower_span: impl Copy + Fn(Span) -> Span,
|
lower_span: impl Copy + Fn(Span) -> Span,
|
||||||
mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
|
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
|
||||||
) -> Vec<Attribute> {
|
) -> Vec<Attribute> {
|
||||||
let mut attributes = Vec::new();
|
let mut attributes = Vec::new();
|
||||||
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
|
let mut attr_paths = Vec::new();
|
||||||
let mut early_parsed_state = EarlyParsedState::default();
|
|
||||||
|
|
||||||
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
|
|
||||||
|
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||||
|
|
@ -285,12 +270,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
// that's expanded right? But no, sometimes, when parsing attributes on macros,
|
// that's expanded right? But no, sometimes, when parsing attributes on macros,
|
||||||
// we already use the lowering logic and these are still there. So, when `omit_doc`
|
// we already use the lowering logic and these are still there. So, when `omit_doc`
|
||||||
// is set we *also* want to ignore these.
|
// is set we *also* want to ignore these.
|
||||||
let is_doc_attribute = attr.has_name(sym::doc);
|
if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
|
||||||
if omit_doc == OmitDoc::Skip && is_doc_attribute {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let attr_span = lower_span(attr.span);
|
|
||||||
match &attr.kind {
|
match &attr.kind {
|
||||||
ast::AttrKind::DocComment(comment_kind, symbol) => {
|
ast::AttrKind::DocComment(comment_kind, symbol) => {
|
||||||
if omit_doc == OmitDoc::Skip {
|
if omit_doc == OmitDoc::Skip {
|
||||||
|
|
@ -299,95 +282,67 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
|
|
||||||
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
||||||
style: attr.style,
|
style: attr.style,
|
||||||
kind: DocFragmentKind::Sugared(*comment_kind),
|
kind: *comment_kind,
|
||||||
span: attr_span,
|
span: lower_span(attr.span),
|
||||||
comment: *symbol,
|
comment: *symbol,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
// // FIXME: make doc attributes go through a proper attribute parser
|
||||||
|
// ast::AttrKind::Normal(n) if n.has_name(sym::doc) => {
|
||||||
|
// let p = GenericMetaItemParser::from_attr(&n, self.dcx());
|
||||||
|
//
|
||||||
|
// attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
||||||
|
// style: attr.style,
|
||||||
|
// kind: CommentKind::Line,
|
||||||
|
// span: attr.span,
|
||||||
|
// comment: p.args().name_value(),
|
||||||
|
// }))
|
||||||
|
// }
|
||||||
ast::AttrKind::Normal(n) => {
|
ast::AttrKind::Normal(n) => {
|
||||||
attr_paths.push(PathParser(&n.item.path));
|
attr_paths.push(PathParser(Cow::Borrowed(&n.item.path)));
|
||||||
let attr_path = AttrPath::from_ast(&n.item.path, lower_span);
|
let attr_path = AttrPath::from_ast(&n.item.path, lower_span);
|
||||||
|
|
||||||
let args = match &n.item.args {
|
|
||||||
AttrItemKind::Unparsed(args) => args,
|
|
||||||
AttrItemKind::Parsed(parsed) => {
|
|
||||||
early_parsed_state
|
|
||||||
.accept_early_parsed_attribute(attr_span, lower_span, parsed);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.check_attribute_safety(
|
self.check_attribute_safety(
|
||||||
&attr_path,
|
&attr_path,
|
||||||
lower_span(n.item.span()),
|
lower_span(n.item.span()),
|
||||||
n.item.unsafety,
|
n.item.unsafety,
|
||||||
&mut emit_lint,
|
&mut emit_lint,
|
||||||
|
target_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
let parts =
|
let parts =
|
||||||
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||||
|
|
||||||
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
|
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||||
let Some(args) = ArgParser::from_attr_args(
|
let Some(parser) = MetaItemParser::from_attr(
|
||||||
args,
|
n,
|
||||||
&parts,
|
&parts,
|
||||||
&self.sess.psess,
|
&self.sess.psess,
|
||||||
self.stage.should_emit(),
|
self.stage.should_emit(),
|
||||||
) else {
|
) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
let args = parser.args();
|
||||||
|
for accept in accepts {
|
||||||
|
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||||
|
shared: SharedContext {
|
||||||
|
cx: self,
|
||||||
|
target_span,
|
||||||
|
target_id,
|
||||||
|
emit_lint: &mut emit_lint,
|
||||||
|
},
|
||||||
|
attr_span: lower_span(attr.span),
|
||||||
|
inner_span: lower_span(n.item.span()),
|
||||||
|
attr_style: attr.style,
|
||||||
|
parsed_description: ParsedDescription::Attribute,
|
||||||
|
template: &accept.template,
|
||||||
|
attr_path: attr_path.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
// Special-case handling for `#[doc = "..."]`: if we go through with
|
(accept.accept_fn)(&mut cx, args);
|
||||||
// `DocParser`, the order of doc comments will be messed up because `///`
|
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
||||||
// doc comments are added into `attributes` whereas attributes parsed with
|
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||||
// `DocParser` are added into `parsed_attributes` which are then appended
|
}
|
||||||
// to `attributes`. So if you have:
|
|
||||||
//
|
|
||||||
// /// bla
|
|
||||||
// #[doc = "a"]
|
|
||||||
// /// blob
|
|
||||||
//
|
|
||||||
// You would get:
|
|
||||||
//
|
|
||||||
// bla
|
|
||||||
// blob
|
|
||||||
// a
|
|
||||||
if is_doc_attribute
|
|
||||||
&& let ArgParser::NameValue(nv) = &args
|
|
||||||
// If not a string key/value, it should emit an error, but to make
|
|
||||||
// things simpler, it's handled in `DocParser` because it's simpler to
|
|
||||||
// emit an error with `AcceptContext`.
|
|
||||||
&& let Some(comment) = nv.value_as_str()
|
|
||||||
{
|
|
||||||
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
|
||||||
style: attr.style,
|
|
||||||
kind: DocFragmentKind::Raw(nv.value_span),
|
|
||||||
span: attr_span,
|
|
||||||
comment,
|
|
||||||
}));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
|
||||||
shared: SharedContext {
|
|
||||||
cx: self,
|
|
||||||
target_span,
|
|
||||||
target,
|
|
||||||
emit_lint: &mut emit_lint,
|
|
||||||
},
|
|
||||||
attr_span,
|
|
||||||
inner_span: lower_span(n.item.span()),
|
|
||||||
attr_style: attr.style,
|
|
||||||
parsed_description: ParsedDescription::Attribute,
|
|
||||||
template: &accept.template,
|
|
||||||
attr_path: attr_path.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
(accept.accept_fn)(&mut cx, &args);
|
|
||||||
finalizers.push(&accept.finalizer);
|
|
||||||
|
|
||||||
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
|
||||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If we're here, we must be compiling a tool attribute... Or someone
|
// If we're here, we must be compiling a tool attribute... Or someone
|
||||||
|
|
@ -407,43 +362,39 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
|
|
||||||
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
|
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
|
||||||
path: attr_path.clone(),
|
path: attr_path.clone(),
|
||||||
args: self
|
args: self.lower_attr_args(&n.item.args, lower_span),
|
||||||
.lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span),
|
|
||||||
id: HashIgnoredAttrId { attr_id: attr.id },
|
id: HashIgnoredAttrId { attr_id: attr.id },
|
||||||
style: attr.style,
|
style: attr.style,
|
||||||
span: attr_span,
|
span: lower_span(attr.span),
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
|
let mut parsed_attributes = Vec::new();
|
||||||
for f in &finalizers {
|
for f in &S::parsers().finalizers {
|
||||||
if let Some(attr) = f(&mut FinalizeContext {
|
if let Some(attr) = f(&mut FinalizeContext {
|
||||||
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
|
shared: SharedContext {
|
||||||
|
cx: self,
|
||||||
|
target_span,
|
||||||
|
target_id,
|
||||||
|
emit_lint: &mut emit_lint,
|
||||||
|
},
|
||||||
all_attrs: &attr_paths,
|
all_attrs: &attr_paths,
|
||||||
}) {
|
}) {
|
||||||
attributes.push(Attribute::Parsed(attr));
|
parsed_attributes.push(Attribute::Parsed(attr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attributes.extend(parsed_attributes);
|
||||||
|
|
||||||
attributes
|
attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether there is a parser for an attribute with this name
|
/// Returns whether there is a parser for an attribute with this name
|
||||||
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
|
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
|
||||||
/// The list of attributes that are parsed attributes,
|
|
||||||
/// even though they don't have a parser in `Late::parsers()`
|
|
||||||
const SPECIAL_ATTRIBUTES: &[&[Symbol]] = &[
|
|
||||||
// Cfg attrs are removed after being early-parsed, so don't need to be in the parser list
|
|
||||||
&[sym::cfg],
|
|
||||||
&[sym::cfg_attr],
|
|
||||||
];
|
|
||||||
|
|
||||||
Late::parsers().accepters.contains_key(path)
|
Late::parsers().accepters.contains_key(path)
|
||||||
|| EARLY_PARSED_ATTRIBUTES.contains(&path)
|
|
||||||
|| SPECIAL_ATTRIBUTES.contains(&path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
|
fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,6 @@
|
||||||
|
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(if_let_guard)]
|
|
||||||
#![feature(iter_intersperse)]
|
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
|
|
@ -99,7 +97,7 @@ mod interface;
|
||||||
/// like lists or name-value pairs.
|
/// like lists or name-value pairs.
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
||||||
mod early_parsed;
|
mod lints;
|
||||||
mod safety;
|
mod safety;
|
||||||
mod session_diagnostics;
|
mod session_diagnostics;
|
||||||
mod target_checking;
|
mod target_checking;
|
||||||
|
|
@ -108,8 +106,12 @@ pub mod validate_attr;
|
||||||
pub use attributes::cfg::{
|
pub use attributes::cfg::{
|
||||||
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
|
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
|
||||||
};
|
};
|
||||||
|
pub use attributes::cfg_old::*;
|
||||||
pub use attributes::cfg_select::*;
|
pub use attributes::cfg_select::*;
|
||||||
pub use attributes::util::{is_builtin_attr, parse_version};
|
pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version};
|
||||||
pub use context::{Early, Late, OmitDoc, ShouldEmit};
|
pub use context::{Early, Late, OmitDoc, ShouldEmit};
|
||||||
pub use interface::AttributeParser;
|
pub use interface::AttributeParser;
|
||||||
|
pub use lints::emit_attribute_lint;
|
||||||
pub use session_diagnostics::ParsedDescription;
|
pub use session_diagnostics::ParsedDescription;
|
||||||
|
|
||||||
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
|
||||||
114
compiler/rustc_attr_parsing/src/lints.rs
Normal file
114
compiler/rustc_attr_parsing/src/lints.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use rustc_errors::{DiagArgValue, LintEmitter};
|
||||||
|
use rustc_hir::Target;
|
||||||
|
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
|
||||||
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
use crate::session_diagnostics;
|
||||||
|
|
||||||
|
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emitter: L) {
|
||||||
|
let AttributeLint { id, span, kind } = lint;
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
&AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter
|
||||||
|
.emit_node_span_lint(
|
||||||
|
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||||
|
*id,
|
||||||
|
*span,
|
||||||
|
session_diagnostics::UnusedDuplicate { this, other, warning },
|
||||||
|
),
|
||||||
|
AttributeLintKind::IllFormedAttributeInput { suggestions } => {
|
||||||
|
lint_emitter.emit_node_span_lint(
|
||||||
|
rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT,
|
||||||
|
*id,
|
||||||
|
*span,
|
||||||
|
session_diagnostics::IllFormedAttributeInput {
|
||||||
|
num_suggestions: suggestions.len(),
|
||||||
|
suggestions: DiagArgValue::StrListSepByAnd(
|
||||||
|
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AttributeLintKind::InvalidMacroExportArguments { suggestions } => lint_emitter
|
||||||
|
.emit_node_span_lint(
|
||||||
|
rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS,
|
||||||
|
*id,
|
||||||
|
*span,
|
||||||
|
session_diagnostics::IllFormedAttributeInput {
|
||||||
|
num_suggestions: suggestions.len(),
|
||||||
|
suggestions: DiagArgValue::StrListSepByAnd(
|
||||||
|
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => {
|
||||||
|
lint_emitter.emit_node_span_lint(
|
||||||
|
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||||
|
*id,
|
||||||
|
*first_span,
|
||||||
|
session_diagnostics::EmptyAttributeList {
|
||||||
|
attr_span: *first_span,
|
||||||
|
attr_path: attr_path.clone(),
|
||||||
|
valid_without_list: *valid_without_list,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AttributeLintKind::InvalidTarget { name, target, applied, only } => lint_emitter
|
||||||
|
.emit_node_span_lint(
|
||||||
|
// This check is here because `deprecated` had its own lint group and removing this would be a breaking change
|
||||||
|
if name.segments[0].name == sym::deprecated
|
||||||
|
&& ![
|
||||||
|
Target::Closure,
|
||||||
|
Target::Expression,
|
||||||
|
Target::Statement,
|
||||||
|
Target::Arm,
|
||||||
|
Target::MacroCall,
|
||||||
|
]
|
||||||
|
.contains(target)
|
||||||
|
{
|
||||||
|
rustc_session::lint::builtin::USELESS_DEPRECATED
|
||||||
|
} else {
|
||||||
|
rustc_session::lint::builtin::UNUSED_ATTRIBUTES
|
||||||
|
},
|
||||||
|
*id,
|
||||||
|
*span,
|
||||||
|
session_diagnostics::InvalidTargetLint {
|
||||||
|
name: name.clone(),
|
||||||
|
target: target.plural_name(),
|
||||||
|
applied: DiagArgValue::StrListSepByAnd(
|
||||||
|
applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(),
|
||||||
|
),
|
||||||
|
only,
|
||||||
|
attr_span: *span,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
&AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => {
|
||||||
|
lint_emitter.emit_node_span_lint(
|
||||||
|
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||||
|
*id,
|
||||||
|
*span,
|
||||||
|
session_diagnostics::InvalidAttrStyle {
|
||||||
|
name: name.clone(),
|
||||||
|
is_used_as_inner,
|
||||||
|
target_span: (!is_used_as_inner).then_some(target_span),
|
||||||
|
target,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
&AttributeLintKind::UnsafeAttrOutsideUnsafe {
|
||||||
|
attribute_name_span,
|
||||||
|
sugg_spans: (left, right),
|
||||||
|
} => lint_emitter.emit_node_span_lint(
|
||||||
|
rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE,
|
||||||
|
*id,
|
||||||
|
*span,
|
||||||
|
session_diagnostics::UnsafeAttrOutsideUnsafeLint {
|
||||||
|
span: attribute_name_span,
|
||||||
|
suggestion: session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right },
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue