commit
a45071b797
4130 changed files with 53441 additions and 29095 deletions
1
.github/ISSUE_TEMPLATE/ice.md
vendored
1
.github/ISSUE_TEMPLATE/ice.md
vendored
|
|
@ -2,6 +2,7 @@
|
|||
name: Internal Compiler Error
|
||||
about: Create a report for an internal compiler error in rustc.
|
||||
labels: C-bug, I-ICE, T-compiler
|
||||
title: "[ICE]: "
|
||||
---
|
||||
<!--
|
||||
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
||||
|
|
|
|||
35
.github/workflows/ci.yml
vendored
35
.github/workflows/ci.yml
vendored
|
|
@ -11,11 +11,9 @@ name: CI
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- auto
|
||||
- try
|
||||
- try-perf
|
||||
- automation/bors/try
|
||||
- automation/bors/auto
|
||||
- automation/bors/try
|
||||
- try-perf
|
||||
pull_request:
|
||||
branches:
|
||||
- "**"
|
||||
|
|
@ -33,9 +31,10 @@ defaults:
|
|||
|
||||
concurrency:
|
||||
# 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 (try branch) and unrolled rollup builds (try-perf), which
|
||||
# are all triggered on the same branch, but which should be able to run 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 }}
|
||||
# We add an exception for try builds (automation/bors/try branch) and unrolled rollup builds
|
||||
# (try-perf), which are all triggered on the same branch, but which should be able to run
|
||||
# concurrently.
|
||||
group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }}
|
||||
cancel-in-progress: true
|
||||
env:
|
||||
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
|
||||
|
|
@ -57,7 +56,7 @@ jobs:
|
|||
- name: Test citool
|
||||
# Only test citool on the auto branch, to reduce latency of the calculate matrix job
|
||||
# on PR/try builds.
|
||||
if: ${{ github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto' }}
|
||||
if: ${{ github.ref == 'refs/heads/automation/bors/auto' }}
|
||||
run: |
|
||||
cd src/ci/citool
|
||||
CARGO_INCREMENTAL=0 cargo test
|
||||
|
|
@ -80,7 +79,7 @@ jobs:
|
|||
# access the environment.
|
||||
#
|
||||
# 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' || 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') || '' }}
|
||||
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') || '' }}
|
||||
env:
|
||||
CI_JOB_NAME: ${{ matrix.name }}
|
||||
CI_JOB_DOC_URL: ${{ matrix.doc_url }}
|
||||
|
|
@ -289,7 +288,7 @@ jobs:
|
|||
fi
|
||||
|
||||
# Get closest bors merge commit
|
||||
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
|
||||
PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
|
||||
|
||||
./build/citool/debug/citool postprocess-metrics \
|
||||
--job-name ${CI_JOB_NAME} \
|
||||
|
|
@ -306,30 +305,22 @@ jobs:
|
|||
DD_GITHUB_JOB_NAME: ${{ matrix.full_name }}
|
||||
run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv
|
||||
|
||||
# This job isused to tell bors the final status of the build, as there is no practical way to detect
|
||||
# when a workflow is successful listening to webhooks only in our current bors implementation (homu).
|
||||
# This job is used to publish toolstate for successful auto builds.
|
||||
outcome:
|
||||
name: bors build finished
|
||||
name: publish toolstate
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [ calculate_matrix, job ]
|
||||
# !cancelled() executes the job regardless of whether the previous jobs passed or failed
|
||||
if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }}
|
||||
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') || '' }}
|
||||
if: ${{ needs.calculate_matrix.outputs.run_type == 'auto' }}
|
||||
environment: ${{ (github.repository == 'rust-lang/rust' && 'bors') || '' }}
|
||||
steps:
|
||||
- name: checkout the source code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
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)
|
||||
- name: publish toolstate
|
||||
run: src/ci/publish_toolstate.sh
|
||||
shell: bash
|
||||
if: needs.calculate_matrix.outputs.run_type == 'auto'
|
||||
env:
|
||||
TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
|
||||
TOOLSTATE_PUBLISH: 1
|
||||
|
|
|
|||
16
.github/workflows/dependencies.yml
vendored
16
.github/workflows/dependencies.yml
vendored
|
|
@ -62,19 +62,9 @@ jobs:
|
|||
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
|
||||
rustup default $TOOLCHAIN
|
||||
|
||||
- name: cargo update compiler & tools
|
||||
# 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: cargo update
|
||||
run: ./src/tools/update-lockfile.sh
|
||||
|
||||
- name: upload Cargo.lock artifact for use in PR
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
|
|||
2
.github/workflows/post-merge.yml
vendored
2
.github/workflows/post-merge.yml
vendored
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
sleep 60
|
||||
|
||||
# Get closest bors merge commit
|
||||
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
|
||||
PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
|
||||
echo "Parent: ${PARENT_COMMIT}"
|
||||
|
||||
# Find PR for the current commit
|
||||
|
|
|
|||
1
.mailmap
1
.mailmap
|
|
@ -96,6 +96,7 @@ boolean_coercion <booleancoercion@gmail.com>
|
|||
Boris Egorov <jightuse@gmail.com> <egorov@linux.com>
|
||||
bors <bors@rust-lang.org> bors[bot] <26634292+bors[bot]@users.noreply.github.com>
|
||||
bors <bors@rust-lang.org> bors[bot] <bors[bot]@users.noreply.github.com>
|
||||
bors <bors@rust-lang.org> <122020455+rust-bors[bot]@users.noreply.github.com>
|
||||
BoxyUwU <rust@boxyuwu.dev>
|
||||
BoxyUwU <rust@boxyuwu.dev> <supbscripter@gmail.com>
|
||||
Braden Nelson <moonheart08@users.noreply.github.com>
|
||||
|
|
|
|||
171
Cargo.lock
171
Cargo.lock
|
|
@ -182,19 +182,6 @@ version = "0.7.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
|
||||
dependencies = [
|
||||
"askama_derive 0.14.0",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.15.1"
|
||||
|
|
@ -208,30 +195,13 @@ dependencies = [
|
|||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
|
||||
dependencies = [
|
||||
"askama_parser 0.14.0",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994"
|
||||
dependencies = [
|
||||
"askama_parser 0.15.1",
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
|
|
@ -248,19 +218,7 @@ version = "0.15.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46"
|
||||
dependencies = [
|
||||
"askama_derive 0.15.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winnow 0.7.13",
|
||||
"askama_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -445,22 +403,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "capstone"
|
||||
version = "0.13.0"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
|
||||
checksum = "f442ae0f2f3f1b923334b4a5386c95c69c1cfa072bafa23d6fae6d9682eb1dd4"
|
||||
dependencies = [
|
||||
"capstone-sys",
|
||||
"libc",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "capstone-sys"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
|
||||
checksum = "a4e8087cab6731295f5a2a2bd82989ba4f41d3a428aab2e7c98d8f4db38aac05"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -673,10 +630,10 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama 0.14.0",
|
||||
"askama",
|
||||
"cargo_metadata 0.18.1",
|
||||
"clippy_config",
|
||||
"clippy_lints",
|
||||
|
|
@ -700,7 +657,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
dependencies = [
|
||||
"clippy_utils",
|
||||
"itertools",
|
||||
|
|
@ -724,7 +681,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.18.1",
|
||||
|
|
@ -756,7 +713,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"itertools",
|
||||
|
|
@ -1160,7 +1117,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.94"
|
||||
version = "0.1.95"
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
|
|
@ -1567,7 +1524,7 @@ name = "generate-copyright"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama 0.15.1",
|
||||
"askama",
|
||||
"cargo_metadata 0.21.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -1713,9 +1670,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"foldhash 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
|
@ -1993,12 +1953,12 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.12.0"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.16.0",
|
||||
"hashbrown 0.16.1",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
|
@ -2232,9 +2192,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libffi"
|
||||
version = "5.0.0"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0444124f3ffd67e1b0b0c661a7f81a278a135eb54aaad4078e79fbc8be50c8a5"
|
||||
checksum = "0498fe5655f857803e156523e644dcdcdc3b3c7edda42ea2afdae2e09b2db87b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libffi-sys",
|
||||
|
|
@ -2242,9 +2202,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libffi-sys"
|
||||
version = "4.0.0"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d722da8817ea580d0669da6babe2262d7b86a1af1103da24102b8bb9c101ce7"
|
||||
checksum = "71d4f1d4ce15091955144350b75db16a96d4a63728500122706fb4d29a26afbb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
|
@ -3377,6 +3337,7 @@ dependencies = [
|
|||
"rustdoc-json-types",
|
||||
"serde_json",
|
||||
"similar",
|
||||
"tempfile",
|
||||
"wasmparser 0.236.1",
|
||||
]
|
||||
|
||||
|
|
@ -3395,9 +3356,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.26"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
|
|
@ -3413,9 +3374,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
|||
|
||||
[[package]]
|
||||
name = "rustc-literal-escaper"
|
||||
version = "0.0.5"
|
||||
version = "0.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b"
|
||||
checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-main"
|
||||
|
|
@ -3773,7 +3734,7 @@ dependencies = [
|
|||
"either",
|
||||
"elsa",
|
||||
"ena",
|
||||
"hashbrown 0.15.5",
|
||||
"hashbrown 0.16.1",
|
||||
"indexmap",
|
||||
"jobserver",
|
||||
"libc",
|
||||
|
|
@ -3810,6 +3771,7 @@ dependencies = [
|
|||
name = "rustc_driver_impl"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"ctrlc",
|
||||
"jiff",
|
||||
"libc",
|
||||
|
|
@ -3835,6 +3797,7 @@ dependencies = [
|
|||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_interface",
|
||||
"rustc_lexer",
|
||||
"rustc_lint",
|
||||
"rustc_log",
|
||||
"rustc_macros",
|
||||
|
|
@ -3902,7 +3865,6 @@ dependencies = [
|
|||
"rustc_fluent_macro",
|
||||
"rustc_hashes",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
|
|
@ -3930,11 +3892,13 @@ dependencies = [
|
|||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_parse",
|
||||
"rustc_proc_macro",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"scoped-tls",
|
||||
"smallvec",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
|
|
@ -4389,7 +4353,7 @@ name = "rustc_mir_transform"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"hashbrown 0.15.5",
|
||||
"hashbrown 0.16.1",
|
||||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
|
|
@ -4403,7 +4367,6 @@ dependencies = [
|
|||
"rustc_infer",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_mir_build",
|
||||
"rustc_mir_dataflow",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -4422,6 +4385,7 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
|
|
@ -4600,7 +4564,7 @@ dependencies = [
|
|||
name = "rustc_query_system"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.5",
|
||||
"hashbrown 0.16.1",
|
||||
"parking_lot",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
|
|
@ -4624,7 +4588,6 @@ dependencies = [
|
|||
name = "rustc_resolve"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"pulldown-cmark",
|
||||
|
|
@ -4914,7 +4877,7 @@ name = "rustdoc"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"askama 0.15.1",
|
||||
"askama",
|
||||
"base64",
|
||||
"expect-test",
|
||||
"indexmap",
|
||||
|
|
@ -5660,6 +5623,7 @@ dependencies = [
|
|||
"build_helper",
|
||||
"cargo_metadata 0.21.0",
|
||||
"fluent-syntax",
|
||||
"globset",
|
||||
"ignore",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
|
|
@ -6223,9 +6187,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasi-preview1-component-adapter-provider"
|
||||
version = "38.0.4"
|
||||
version = "40.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ec3ef3783e18f2457796ed91b1e6c2adc46f2905f740d1527ab3053fe8e5682"
|
||||
checksum = "bb5e2b9858989c3a257de4ca169977f4f79897b64e4f482f188f4fcf8ac557d1"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
|
|
@ -6274,17 +6238,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-component-ld"
|
||||
version = "0.5.19"
|
||||
version = "0.5.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bfc50dd0b883d841bc1dba5ff7020ca52fa7b2c3bb1266d8bf6a09dd032e115"
|
||||
checksum = "846d20ed66ae37b7a237e36dfcd2fdc979eae82a46cdb0586f9bba80782fd789"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap_lex",
|
||||
"lexopt",
|
||||
"libc",
|
||||
"tempfile",
|
||||
"wasi-preview1-component-adapter-provider",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
"wat",
|
||||
"windows-sys 0.61.2",
|
||||
"winsplit",
|
||||
|
|
@ -6311,24 +6276,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8"
|
||||
checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167"
|
||||
checksum = "eae05bf9579f45a62e8d0a4e3f52eaa8da518883ac5afa482ec8256c329ecd56"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"wasm-encoder 0.241.2",
|
||||
"wasmparser 0.241.2",
|
||||
"wasm-encoder 0.243.0",
|
||||
"wasmparser 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6353,9 +6318,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8"
|
||||
checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"hashbrown 0.15.5",
|
||||
|
|
@ -6366,22 +6331,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "241.0.2"
|
||||
version = "243.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63f66e07e2ddf531fef6344dbf94d112df7c2f23ed6ffb10962e711500b8d816"
|
||||
checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.2",
|
||||
"wasm-encoder 0.241.2",
|
||||
"wasm-encoder 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.241.2"
|
||||
version = "1.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45f923705c40830af909c5dec2352ec2821202e4a66008194585e1917458a26d"
|
||||
checksum = "226a9a91cd80a50449312fef0c75c23478fcecfcc4092bdebe1dc8e760ef521b"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
|
@ -6777,9 +6742,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241"
|
||||
checksum = "36f9fc53513e461ce51dcf17a3e331752cb829f1d187069e54af5608fc998fe4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
|
|
@ -6788,17 +6753,17 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder 0.241.2",
|
||||
"wasm-encoder 0.243.0",
|
||||
"wasm-metadata",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91"
|
||||
checksum = "df983a8608e513d8997f435bb74207bf0933d0e49ca97aa9d8a6157164b9b7fc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
|
@ -6809,7 +6774,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ See [the rustc-dev-guide for more info][sysllvm].
|
|||
--set llvm.ninja=false \
|
||||
--set rust.debug-assertions=false \
|
||||
--set rust.jemalloc \
|
||||
--set rust.use-lld=true \
|
||||
--set rust.bootstrap-override-lld=true \
|
||||
--set rust.lto=thin \
|
||||
--set rust.codegen-units=1
|
||||
```
|
||||
|
|
|
|||
111
RELEASES.md
111
RELEASES.md
|
|
@ -1,3 +1,114 @@
|
|||
Version 1.93.0 (2026-01-22)
|
||||
==========================
|
||||
|
||||
<a id="1.93.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize several s390x `vector`-related target features and the `is_s390x_feature_detected!` macro](https://github.com/rust-lang/rust/pull/145656)
|
||||
- [Stabilize declaration of C-style variadic functions for the `system` ABI](https://github.com/rust-lang/rust/pull/145954)
|
||||
- [Emit error when using some keyword as a `cfg` predicate](https://github.com/rust-lang/rust/pull/146978)
|
||||
- [Stabilize `asm_cfg`](https://github.com/rust-lang/rust/pull/147736)
|
||||
- [During const-evaluation, support copying pointers byte-by-byte](https://github.com/rust-lang/rust/pull/148259)
|
||||
- [LUB coercions now correctly handle function item types, and functions with differing safeties](https://github.com/rust-lang/rust/pull/148602)
|
||||
- [Allow `const` items that contain mutable references to `static` (which is *very* unsafe, but not *always* UB)](https://github.com/rust-lang/rust/pull/148746)
|
||||
- [Add warn-by-default `const_item_interior_mutations` lint to warn against calls which mutate interior mutable `const` items](https://github.com/rust-lang/rust/pull/148407)
|
||||
- [Add warn-by-default `function_casts_as_integer` lint](https://github.com/rust-lang/rust/pull/141470)
|
||||
|
||||
|
||||
<a id="1.93.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Stabilize `-Cjump-tables=bool`](https://github.com/rust-lang/rust/pull/145974). The flag was previously called `-Zno-jump-tables`.
|
||||
|
||||
<a id="1.93.0-Platform-Support"></a>
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
|
||||
- [Promote `riscv64a23-unknown-linux-gnu` to Tier 2 (without host tools)](https://github.com/rust-lang/rust/pull/148435)
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
|
||||
|
||||
<a id="1.93.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Stop internally using `specialization` on the `Copy` trait as it is unsound in the presence of lifetime dependent `Copy` implementations. This may result in some performance regressions as some standard library APIs may now call `Clone::clone` instead of performing bitwise copies](https://github.com/rust-lang/rust/pull/135634)
|
||||
- [Allow the global allocator to use thread-local storage and `std::thread::current()`](https://github.com/rust-lang/rust/pull/144465)
|
||||
- [Make `BTree::append` not update existing keys when appending an entry which already exists](https://github.com/rust-lang/rust/pull/145628)
|
||||
- [Don't require `T: RefUnwindSafe` for `vec::IntoIter<T>: UnwindSafe`](https://github.com/rust-lang/rust/pull/145665)
|
||||
|
||||
|
||||
<a id="1.93.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`<[MaybeUninit<T>]>::assume_init_drop`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_drop)
|
||||
- [`<[MaybeUninit<T>]>::assume_init_ref`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_ref)
|
||||
- [`<[MaybeUninit<T>]>::assume_init_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_mut)
|
||||
- [`<[MaybeUninit<T>]>::write_copy_of_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.write_copy_of_slice)
|
||||
- [`<[MaybeUninit<T>]>::write_clone_of_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.write_clone_of_slice)
|
||||
- [`String::into_raw_parts`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.into_raw_parts)
|
||||
- [`Vec::into_raw_parts`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.into_raw_parts)
|
||||
- [`<iN>::unchecked_neg`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_neg)
|
||||
- [`<iN>::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_shl)
|
||||
- [`<iN>::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_shr)
|
||||
- [`<uN>::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shl)
|
||||
- [`<uN>::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shr)
|
||||
- [`<[T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_array)
|
||||
- [`<[T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array)
|
||||
- [`<*const [T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_array)
|
||||
- [`<*mut [T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array)
|
||||
- [`VecDeque::pop_front_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_front_if)
|
||||
- [`VecDeque::pop_back_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_back_if)
|
||||
- [`Duration::from_nanos_u128`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_nanos_u128)
|
||||
- [`char::MAX_LEN_UTF8`](https://doc.rust-lang.org/stable/std/primitive.char.html#associatedconstant.MAX_LEN_UTF8)
|
||||
- [`char::MAX_LEN_UTF16`](https://doc.rust-lang.org/stable/std/primitive.char.html#associatedconstant.MAX_LEN_UTF16)
|
||||
- [`std::fmt::from_fn`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html)
|
||||
- [`std::fmt::FromFn`](https://doc.rust-lang.org/stable/std/fmt/struct.FromFn.html)
|
||||
|
||||
|
||||
<a id="1.93.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [Enable CARGO_CFG_DEBUG_ASSERTIONS in build scripts based on profile](https://github.com/rust-lang/cargo/pull/16160/)
|
||||
- [In `cargo tree`, support long forms for `--format` variables](https://github.com/rust-lang/cargo/pull/16204/)
|
||||
- [Add `--workspace` to `cargo clean`](https://github.com/rust-lang/cargo/pull/16263/)
|
||||
|
||||
<a id="1.93.0-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-----
|
||||
- [Remove `#![doc(document_private_items)]`](https://github.com/rust-lang/rust/pull/146495)
|
||||
- [Include attribute and derive macros in search filters for "macros"](https://github.com/rust-lang/rust/pull/148176)
|
||||
- [Include extern crates in search filters for `import`](https://github.com/rust-lang/rust/pull/148301)
|
||||
- [Validate usage of crate-level doc attributes](https://github.com/rust-lang/rust/pull/149197). This means if any of `html_favicon_url`, `html_logo_url`, `html_playground_url`, `issue_tracker_base_url`, or `html_no_source` either has a missing value, an unexpected value, or a value of the wrong type, rustdoc will emit the deny-by-default lint `rustdoc::invalid_doc_attributes`.
|
||||
|
||||
|
||||
<a id="1.93.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Introduce `pin_v2` into the builtin attributes namespace](https://github.com/rust-lang/rust/pull/139751)
|
||||
- [Update bundled musl to 1.2.5](https://github.com/rust-lang/rust/pull/142682)
|
||||
- [On Emscripten, the unwinding ABI used when compiling with `panic=unwind` was changed from the JS exception handling ABI to the wasm exception handling ABI.](https://github.com/rust-lang/rust/pull/147224) If linking C/C++ object files with Rust objects, `-fwasm-exceptions` must be passed to the linker now. On nightly Rust, it is possible to get the old behavior with `-Zwasm-emscripten-eh=false -Zbuild-std`, but it will be removed in a future release.
|
||||
- The `#[test]` attribute, used to define tests, was previously ignored in various places where it had no meaning (e.g on trait methods or types). Putting the `#[test]` attribute in these places is no longer ignored, and will now result in an error; this may also result in errors when generating rustdoc. [Error when `test` attribute is applied to structs](https://github.com/rust-lang/rust/pull/147841)
|
||||
- Cargo now sets the `CARGO_CFG_DEBUG_ASSERTIONS` environment variable in more situations. This will cause crates depending on `static-init` versions 1.0.1 to 1.0.3 to fail compilation with "failed to resolve: use of unresolved module or unlinked crate `parking_lot`". See [the linked issue](https://github.com/rust-lang/rust/issues/150646#issuecomment-3718964342) for details.
|
||||
- [User written types in the `offset_of!` macro are now checked to be well formed.](https://github.com/rust-lang/rust/issues/150465/)
|
||||
- `cargo publish` no longer emits `.crate` files as a final artifact for user access when the `build.build-dir` config is unset
|
||||
- [Upgrade the `deref_nullptr` lint from warn-by-default to deny-by-default](https://github.com/rust-lang/rust/pull/148122)
|
||||
- [Add future-incompatibility warning for `...` function parameters without a pattern outside of `extern` blocks](https://github.com/rust-lang/rust/pull/143619)
|
||||
- [Introduce future-compatibility warning for `repr(C)` enums whose discriminant values do not fit into a `c_int` or `c_uint`](https://github.com/rust-lang/rust/pull/147017)
|
||||
- [Introduce future-compatibility warning against ignoring `repr(C)` types as part of `repr(transparent)`](https://github.com/rust-lang/rust/pull/147185)
|
||||
|
||||
|
||||
Version 1.92.0 (2025-12-11)
|
||||
==========================
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ pub enum CanonAbi {
|
|||
C,
|
||||
Rust,
|
||||
RustCold,
|
||||
RustPreserveNone,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define.
|
||||
Custom,
|
||||
|
|
@ -54,7 +55,7 @@ pub enum CanonAbi {
|
|||
impl CanonAbi {
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
match self {
|
||||
CanonAbi::Rust | CanonAbi::RustCold => true,
|
||||
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
|
||||
CanonAbi::C
|
||||
| CanonAbi::Custom
|
||||
| CanonAbi::Arm(_)
|
||||
|
|
@ -74,6 +75,7 @@ impl fmt::Display for CanonAbi {
|
|||
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||
CanonAbi::Rust => ExternAbi::Rust,
|
||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
|
||||
CanonAbi::Custom => ExternAbi::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||
|
|
|
|||
|
|
@ -42,6 +42,13 @@ pub enum ExternAbi {
|
|||
/// in a platform-agnostic way.
|
||||
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.
|
||||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
|
@ -67,7 +74,6 @@ pub enum ExternAbi {
|
|||
|
||||
/* gpu */
|
||||
/// 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,
|
||||
/// An entry-point function called by the GPU's host
|
||||
// FIXME: why do we have two of these?
|
||||
|
|
@ -164,6 +170,7 @@ abi_impls! {
|
|||
RustCall =><= "rust-call",
|
||||
RustCold =><= "rust-cold",
|
||||
RustInvalid =><= "rust-invalid",
|
||||
RustPreserveNone =><= "rust-preserve-none",
|
||||
Stdcall { unwind: false } =><= "stdcall",
|
||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||
System { unwind: false } =><= "system",
|
||||
|
|
@ -244,7 +251,7 @@ impl ExternAbi {
|
|||
/// - are subject to change between compiler versions
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
use ExternAbi::*;
|
||||
matches!(self, Rust | RustCall | RustCold)
|
||||
matches!(self, Rust | RustCall | RustCold | RustPreserveNone)
|
||||
}
|
||||
|
||||
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
|
||||
|
|
@ -316,7 +323,8 @@ impl ExternAbi {
|
|||
| Self::Thiscall { .. }
|
||||
| Self::Vectorcall { .. }
|
||||
| Self::SysV64 { .. }
|
||||
| Self::Win64 { .. } => true,
|
||||
| Self::Win64 { .. }
|
||||
| Self::RustPreserveNone => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
use std::str::FromStr;
|
||||
|
||||
use rustc_data_structures::assert_matches;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ impl DroplessArena {
|
|||
/// - Types that are `!Copy` and `Drop`: these must be specified in the
|
||||
/// arguments. The `TypedArena` will be used for them.
|
||||
///
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
|
||||
#[derive(Default)]
|
||||
pub struct Arena<'tcx> {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ edition = "2024"
|
|||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
memchr = "2.7.6"
|
||||
rustc-literal-escaper = "0.0.5"
|
||||
rustc-literal-escaper = "0.0.7"
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use rustc_span::source_map::{Spanned, respan};
|
|||
use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::attr::data_structures::CfgEntry;
|
||||
pub use crate::format::*;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
|
|
@ -2108,18 +2109,19 @@ pub struct MacroDef {
|
|||
/// `true` if macro was defined with `macro_rules`.
|
||||
pub macro_rules: bool,
|
||||
|
||||
/// If this is a macro used for externally implementable items,
|
||||
/// it refers to an extern item which is its "target". This requires
|
||||
/// name resolution so can't just be an attribute, so we store it in this field.
|
||||
pub eii_extern_target: Option<EiiExternTarget>,
|
||||
/// 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 EiiExternTarget {
|
||||
/// path to the extern item we're targetting
|
||||
pub extern_item_path: Path,
|
||||
pub struct EiiDecl {
|
||||
/// path to the extern item we're targeting
|
||||
pub foreign_item: Path,
|
||||
pub impl_unsafe: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
|
||||
|
|
@ -2394,7 +2396,7 @@ impl FnSig {
|
|||
/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
|
||||
/// * the `A: Bound` in `Trait<A: Bound>`
|
||||
/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
|
||||
/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
|
||||
/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `min_generic_const_args`)
|
||||
/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct AssocItemConstraint {
|
||||
|
|
@ -3346,7 +3348,8 @@ impl UseTree {
|
|||
/// Distinguishes between `Attribute`s that decorate items and Attributes that
|
||||
/// are contained as statements within items. These two cases need to be
|
||||
/// distinguished for pretty-printing.
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic, Walkable)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
pub enum AttrStyle {
|
||||
Outer,
|
||||
Inner,
|
||||
|
|
@ -3390,7 +3393,7 @@ impl NormalAttr {
|
|||
item: AttrItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(ident),
|
||||
args: AttrArgs::Empty,
|
||||
args: AttrItemKind::Unparsed(AttrArgs::Empty),
|
||||
tokens: None,
|
||||
},
|
||||
tokens: None,
|
||||
|
|
@ -3402,11 +3405,53 @@ impl NormalAttr {
|
|||
pub struct AttrItem {
|
||||
pub unsafety: Safety,
|
||||
pub path: Path,
|
||||
pub args: AttrArgs,
|
||||
pub args: AttrItemKind,
|
||||
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
|
||||
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 {
|
||||
pub fn is_valid_for_outer_style(&self) -> bool {
|
||||
self.path == sym::cfg_attr
|
||||
|
|
@ -3581,6 +3626,7 @@ impl Item {
|
|||
pub fn opt_generics(&self) -> Option<&Generics> {
|
||||
match &self.kind {
|
||||
ItemKind::ExternCrate(..)
|
||||
| ItemKind::ConstBlock(_)
|
||||
| ItemKind::Use(_)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(_)
|
||||
|
|
@ -3770,6 +3816,19 @@ pub struct Fn {
|
|||
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,
|
||||
|
|
@ -3837,6 +3896,17 @@ impl ConstItemRhs {
|
|||
}
|
||||
}
|
||||
|
||||
#[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`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ItemKind {
|
||||
|
|
@ -3856,6 +3926,11 @@ pub enum ItemKind {
|
|||
///
|
||||
/// E.g., `const FOO: i32 = 42;`.
|
||||
Const(Box<ConstItem>),
|
||||
/// A module-level const block.
|
||||
/// Equivalent to `const _: () = const { ... };`.
|
||||
///
|
||||
/// E.g., `const { assert!(true) }`.
|
||||
ConstBlock(ConstBlockItem),
|
||||
/// A function declaration (`fn`).
|
||||
///
|
||||
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
|
||||
|
|
@ -3932,6 +4007,8 @@ impl ItemKind {
|
|||
| ItemKind::MacroDef(ident, _)
|
||||
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
|
||||
|
||||
ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT),
|
||||
|
||||
ItemKind::Use(_)
|
||||
| ItemKind::ForeignMod(_)
|
||||
| ItemKind::GlobalAsm(_)
|
||||
|
|
@ -3945,9 +4022,9 @@ impl ItemKind {
|
|||
pub fn article(&self) -> &'static str {
|
||||
use ItemKind::*;
|
||||
match self {
|
||||
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
||||
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
||||
| Delegation(..) | DelegationMac(..) => "a",
|
||||
Use(..) | Static(..) | Const(..) | ConstBlock(..) | Fn(..) | Mod(..)
|
||||
| GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..)
|
||||
| MacroDef(..) | Delegation(..) | DelegationMac(..) => "a",
|
||||
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
||||
}
|
||||
}
|
||||
|
|
@ -3958,6 +4035,7 @@ impl ItemKind {
|
|||
ItemKind::Use(..) => "`use` import",
|
||||
ItemKind::Static(..) => "static item",
|
||||
ItemKind::Const(..) => "constant item",
|
||||
ItemKind::ConstBlock(..) => "const block",
|
||||
ItemKind::Fn(..) => "function",
|
||||
ItemKind::Mod(..) => "module",
|
||||
ItemKind::ForeignMod(..) => "extern block",
|
||||
|
|
@ -3987,7 +4065,18 @@ impl ItemKind {
|
|||
| Self::Trait(box Trait { generics, .. })
|
||||
| Self::TraitAlias(box TraitAlias { 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
101
compiler/rustc_ast/src/attr/data_structures.rs
Normal file
101
compiler/rustc_ast/src/attr/data_structures.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
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,5 +1,8 @@
|
|||
//! Functions dealing with attributes and meta items.
|
||||
|
||||
pub mod data_structures;
|
||||
pub mod version;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
|
|
@ -8,6 +11,7 @@ use rustc_span::{Ident, Span, Symbol, sym};
|
|||
use smallvec::{SmallVec, smallvec};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::AttrItemKind;
|
||||
use crate::ast::{
|
||||
AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
|
||||
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
|
||||
|
|
@ -62,6 +66,15 @@ 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 {
|
||||
match self.kind {
|
||||
AttrKind::Normal(normal) => normal.item,
|
||||
|
|
@ -77,7 +90,7 @@ impl AttributeExt for Attribute {
|
|||
|
||||
fn value_span(&self) -> Option<Span> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => match &normal.item.args {
|
||||
AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
||||
_ => None,
|
||||
},
|
||||
|
|
@ -96,11 +109,11 @@ impl AttributeExt for Attribute {
|
|||
}
|
||||
|
||||
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
|
||||
fn ident(&self) -> Option<Ident> {
|
||||
fn name(&self) -> Option<Symbol> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
if let [ident] = &*normal.item.path.segments {
|
||||
Some(ident.ident)
|
||||
Some(ident.ident.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -109,9 +122,18 @@ impl AttributeExt for Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
|
||||
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()),
|
||||
AttrKind::Normal(p) => {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +160,7 @@ impl AttributeExt for Attribute {
|
|||
|
||||
fn is_word(&self) -> bool {
|
||||
if let AttrKind::Normal(normal) = &self.kind {
|
||||
matches!(normal.item.args, AttrArgs::Empty)
|
||||
matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
@ -213,6 +235,34 @@ 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> {
|
||||
match &self.kind {
|
||||
AttrKind::DocComment(..) => Some(self.style),
|
||||
|
|
@ -255,6 +305,7 @@ impl Attribute {
|
|||
|
||||
pub fn may_have_doc_links(&self) -> bool {
|
||||
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|
||||
|| self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|
||||
}
|
||||
|
||||
/// Extracts the MetaItem from inside this Attribute.
|
||||
|
|
@ -294,7 +345,7 @@ impl AttrItem {
|
|||
}
|
||||
|
||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
MetaItemKind::list_from_tokens(args.tokens.clone())
|
||||
}
|
||||
|
|
@ -315,7 +366,7 @@ impl AttrItem {
|
|||
/// #[attr("value")]
|
||||
/// ```
|
||||
fn value_str(&self) -> Option<Symbol> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => match expr.kind {
|
||||
ExprKind::Lit(token_lit) => {
|
||||
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
|
||||
|
|
@ -339,7 +390,7 @@ impl AttrItem {
|
|||
/// #[attr("value")]
|
||||
/// ```
|
||||
fn value_span(&self) -> Option<Span> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
||||
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
|
||||
}
|
||||
|
|
@ -355,7 +406,7 @@ impl AttrItem {
|
|||
}
|
||||
|
||||
pub fn meta_kind(&self) -> Option<MetaItemKind> {
|
||||
MetaItemKind::from_attr_args(&self.args)
|
||||
MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -690,7 +741,13 @@ fn mk_attr(
|
|||
args: AttrArgs,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
|
||||
mk_attr_from_item(
|
||||
g,
|
||||
AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
|
||||
None,
|
||||
style,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn mk_attr_from_item(
|
||||
|
|
@ -794,9 +851,7 @@ pub trait AttributeExt: Debug {
|
|||
|
||||
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
|
||||
/// return the name of the attribute; otherwise, returns `None`.
|
||||
fn name(&self) -> Option<Symbol> {
|
||||
self.ident().map(|ident| ident.name)
|
||||
}
|
||||
fn name(&self) -> Option<Symbol>;
|
||||
|
||||
/// Get the meta item list, `#[attr(meta item list)]`
|
||||
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
|
||||
|
|
@ -807,9 +862,6 @@ pub trait AttributeExt: Debug {
|
|||
/// Gets the span of the value literal, as string, when using `#[attr = value]`
|
||||
fn value_span(&self) -> Option<Span>;
|
||||
|
||||
/// For a single-segment attribute, returns its ident; otherwise, returns `None`.
|
||||
fn ident(&self) -> Option<Ident>;
|
||||
|
||||
/// Checks whether the path of this attribute matches the name.
|
||||
///
|
||||
/// Matches one segment of the path to each element in `name`
|
||||
|
|
@ -822,7 +874,7 @@ pub trait AttributeExt: Debug {
|
|||
|
||||
#[inline]
|
||||
fn has_name(&self, name: Symbol) -> bool {
|
||||
self.ident().map(|x| x.name == name).unwrap_or(false)
|
||||
self.name().map(|x| x == name).unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -836,13 +888,13 @@ pub trait AttributeExt: Debug {
|
|||
fn is_word(&self) -> bool;
|
||||
|
||||
fn path(&self) -> SmallVec<[Symbol; 1]> {
|
||||
self.ident_path()
|
||||
.map(|i| i.into_iter().map(|i| i.name).collect())
|
||||
.unwrap_or(smallvec![sym::doc])
|
||||
self.symbol_path().unwrap_or(smallvec![sym::doc])
|
||||
}
|
||||
|
||||
fn path_span(&self) -> Option<Span>;
|
||||
|
||||
/// Returns None for doc comments
|
||||
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
|
||||
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
|
||||
|
||||
/// Returns the documentation if this is a doc comment or a sugared doc comment.
|
||||
/// * `///doc` returns `Some("doc")`.
|
||||
|
|
@ -850,6 +902,11 @@ pub trait AttributeExt: Debug {
|
|||
/// * `#[doc(...)]` returns `None`.
|
||||
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 {
|
||||
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
|
||||
.iter()
|
||||
|
|
@ -903,10 +960,6 @@ impl Attribute {
|
|||
AttributeExt::value_span(self)
|
||||
}
|
||||
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
AttributeExt::ident(self)
|
||||
}
|
||||
|
||||
pub fn path_matches(&self, name: &[Symbol]) -> bool {
|
||||
AttributeExt::path_matches(self, name)
|
||||
}
|
||||
|
|
@ -938,10 +991,6 @@ impl Attribute {
|
|||
AttributeExt::path(self)
|
||||
}
|
||||
|
||||
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
|
||||
AttributeExt::ident_path(self)
|
||||
}
|
||||
|
||||
pub fn doc_str(&self) -> Option<Symbol> {
|
||||
AttributeExt::doc_str(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt::{self, Display};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_macros::{
|
||||
BlobDecodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
|
||||
};
|
||||
|
||||
use crate::attrs::PrintAttribute;
|
||||
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, current_rustc_version};
|
||||
|
||||
#[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(HashStable_Generic, PrintAttribute)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct RustcVersion {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
|
|
@ -47,9 +41,3 @@ impl Display for RustcVersion {
|
|||
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for RustcVersion {
|
||||
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
|
||||
DiagArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@
|
|||
//! This API is completely unstable and subject to change.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
|||
|
|
@ -40,13 +40,13 @@ impl DocFragmentKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum CommentKind {
|
||||
Line,
|
||||
Block,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum InvisibleOrigin {
|
||||
// From the expansion of a metavariable in a declarative macro.
|
||||
MetaVar(MetaVarKind),
|
||||
|
|
@ -123,7 +123,7 @@ impl fmt::Display for MetaVarKind {
|
|||
/// Describes how a sequence of token trees is delimited.
|
||||
/// Cannot use `proc_macro::Delimiter` directly because this
|
||||
/// structure should implement some additional traits.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum Delimiter {
|
||||
/// `( ... )`
|
||||
Parenthesis,
|
||||
|
|
@ -186,7 +186,7 @@ impl Delimiter {
|
|||
// 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
|
||||
// given the `Float` kind.
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum LitKind {
|
||||
Bool, // AST only, must never appear in a `Token`
|
||||
Byte,
|
||||
|
|
@ -203,7 +203,7 @@ pub enum LitKind {
|
|||
}
|
||||
|
||||
/// A literal token.
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct Lit {
|
||||
pub kind: LitKind,
|
||||
pub symbol: Symbol,
|
||||
|
|
@ -349,7 +349,7 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
|
|||
.contains(&name)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)]
|
||||
#[derive(PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy, Clone, HashStable_Generic)]
|
||||
pub enum IdentIsRaw {
|
||||
No,
|
||||
Yes,
|
||||
|
|
@ -376,7 +376,7 @@ impl From<bool> for IdentIsRaw {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum TokenKind {
|
||||
/* Expression-operator symbols. */
|
||||
/// `=`
|
||||
|
|
@ -526,7 +526,7 @@ pub enum TokenKind {
|
|||
Eof,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct Token {
|
||||
pub kind: TokenKind,
|
||||
pub span: Span,
|
||||
|
|
@ -625,12 +625,12 @@ impl TokenKind {
|
|||
}
|
||||
|
||||
impl Token {
|
||||
pub fn new(kind: TokenKind, span: Span) -> Self {
|
||||
pub const fn new(kind: TokenKind, span: Span) -> Self {
|
||||
Token { kind, span }
|
||||
}
|
||||
|
||||
/// Some token that will be thrown away later.
|
||||
pub fn dummy() -> Self {
|
||||
pub const fn dummy() -> Self {
|
||||
Token::new(TokenKind::Question, DUMMY_SP)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
//! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use std::{cmp, fmt, iter, mem};
|
||||
|
|
@ -22,7 +23,7 @@ use crate::token::{self, Delimiter, Token, TokenKind};
|
|||
use crate::{AttrVec, Attribute};
|
||||
|
||||
/// Part of a `TokenStream`.
|
||||
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum TokenTree {
|
||||
/// A single token. Should never be `OpenDelim` or `CloseDelim`, because
|
||||
/// delimiters are implicitly represented by `Delimited`.
|
||||
|
|
@ -538,7 +539,7 @@ pub struct AttrsTarget {
|
|||
/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to
|
||||
/// guide pretty-printing, which is where the `JointHidden` value (which isn't
|
||||
/// part of `proc_macro::Spacing`) comes in useful.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum Spacing {
|
||||
/// The token cannot join with the following token to form a compound
|
||||
/// token.
|
||||
|
|
@ -595,7 +596,7 @@ pub enum Spacing {
|
|||
}
|
||||
|
||||
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
|
||||
#[derive(Clone, Debug, Default, Encodable, Decodable)]
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
|
||||
|
||||
impl TokenStream {
|
||||
|
|
@ -811,14 +812,6 @@ 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 {
|
||||
fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
|
||||
TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
|
||||
|
|
@ -970,7 +963,8 @@ impl TokenCursor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
pub struct DelimSpan {
|
||||
pub open: Span,
|
||||
pub close: Span,
|
||||
|
|
@ -994,7 +988,7 @@ impl DelimSpan {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct DelimSpacing {
|
||||
pub open: Spacing,
|
||||
pub close: Spacing,
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
crate::token::LitKind,
|
||||
crate::tokenstream::LazyAttrTokenStream,
|
||||
crate::tokenstream::TokenStream,
|
||||
EarlyParsedAttribute,
|
||||
Movability,
|
||||
Mutability,
|
||||
Pinnedness,
|
||||
|
|
@ -424,6 +425,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
ByRef,
|
||||
Closure,
|
||||
Const,
|
||||
ConstBlockItem,
|
||||
ConstItem,
|
||||
ConstItemRhs,
|
||||
Defaultness,
|
||||
|
|
@ -457,6 +459,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
ModSpans,
|
||||
MutTy,
|
||||
NormalAttr,
|
||||
AttrItemKind,
|
||||
Parens,
|
||||
ParenthesizedArgs,
|
||||
PatFieldsRest,
|
||||
|
|
@ -487,7 +490,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
WhereEqPredicate,
|
||||
WhereRegionPredicate,
|
||||
YieldKind,
|
||||
EiiExternTarget,
|
||||
EiiDecl,
|
||||
EiiImpl,
|
||||
);
|
||||
|
||||
|
|
@ -823,6 +826,8 @@ macro_rules! common_visitor_and_walkers {
|
|||
visit_visitable!($($mut)? vis, use_tree),
|
||||
ItemKind::Static(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::ConstBlock(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::Const(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::Mod(safety, ident, mod_kind) =>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| asm::InlineAsmArch::LoongArch64
|
||||
| asm::InlineAsmArch::S390x
|
||||
);
|
||||
if !is_stable && !self.tcx.features().asm_experimental_arch() {
|
||||
if !is_stable
|
||||
&& !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(
|
||||
&self.tcx.sess,
|
||||
sym::asm_experimental_arch,
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Let statements are allowed to have impl trait in bindings.
|
||||
let super_ = l.super_.map(|span| self.lower_span(span));
|
||||
let ty = l.ty.as_ref().map(|t| {
|
||||
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||
self.lower_ty_alloc(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||
});
|
||||
let init = l.kind.init().map(|init| self.lower_expr(init));
|
||||
let hir_id = self.lower_node_id(l.id);
|
||||
|
|
|
|||
|
|
@ -152,10 +152,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) -> DelegationResults<'hir> {
|
||||
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
||||
|
||||
let ids = self.get_delegation_ids(
|
||||
self.resolver.delegation_infos[&self.local_def_id(item_id)].resolution_node,
|
||||
span,
|
||||
);
|
||||
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
|
||||
let ids = if let Some(delegation_info) =
|
||||
self.resolver.delegation_infos.get(&self.local_def_id(item_id))
|
||||
{
|
||||
self.get_delegation_ids(delegation_info.resolution_node, span)
|
||||
} else {
|
||||
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) => {
|
||||
|
|
|
|||
|
|
@ -158,14 +158,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ExprKind::Cast(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
hir::ExprKind::Cast(expr, ty)
|
||||
}
|
||||
ExprKind::Type(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
hir::ExprKind::Type(expr, ty)
|
||||
}
|
||||
ExprKind::AddrOf(k, m, ohs) => {
|
||||
|
|
@ -335,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
|
||||
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
|
||||
self.lower_ty(
|
||||
self.lower_ty_alloc(
|
||||
container,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
|
||||
),
|
||||
|
|
@ -371,7 +371,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
*kind,
|
||||
self.lower_expr(expr),
|
||||
ty.as_ref().map(|ty| {
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
|
||||
self.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Cast),
|
||||
)
|
||||
}),
|
||||
),
|
||||
|
||||
|
|
@ -617,7 +620,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
|
||||
if let Some(ty) = opt_ty {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
|
||||
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
|
||||
self.insert(
|
||||
const_arg.as_unambig_ct().span(),
|
||||
const_arg.as_unambig_ct().span,
|
||||
const_arg.hir_id,
|
||||
Node::ConstArg(const_arg.as_unambig_ct()),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
|
||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_hir::{
|
||||
|
|
@ -134,6 +134,56 @@ 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,
|
||||
|
|
@ -143,53 +193,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
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()
|
||||
.flat_map(
|
||||
|EiiImpl {
|
||||
node_id,
|
||||
eii_macro_path,
|
||||
impl_safety,
|
||||
span,
|
||||
inner_span,
|
||||
is_default,
|
||||
}| {
|
||||
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
|
||||
hir::attrs::EiiImpl {
|
||||
eii_macro: did,
|
||||
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,
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
|
||||
))]
|
||||
}
|
||||
ItemKind::MacroDef(
|
||||
_,
|
||||
MacroDef {
|
||||
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
|
||||
..
|
||||
},
|
||||
) => self
|
||||
.lower_path_simple_eii(id, extern_item_path)
|
||||
.map(|did| {
|
||||
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
|
||||
eii_extern_target: did,
|
||||
impl_unsafe: *impl_unsafe,
|
||||
span: self.lower_span(*span),
|
||||
}))]
|
||||
})
|
||||
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(..)
|
||||
|
|
@ -227,10 +243,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
vis_span,
|
||||
span: self.lower_span(i.span),
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
eii: find_attr!(
|
||||
attrs,
|
||||
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
|
||||
),
|
||||
eii: find_attr!(attrs, AttributeKind::EiiImpls(..) | AttributeKind::EiiDeclaration(..)),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -264,14 +277,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
define_opaque,
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let body_id = self.lower_const_body(span, e.as_deref());
|
||||
self.lower_define_opaque(hir_id, define_opaque);
|
||||
hir::ItemKind::Static(*m, ident, ty, body_id)
|
||||
}
|
||||
ItemKind::Const(box ast::ConstItem {
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
ItemKind::Const(box ConstItem {
|
||||
defaultness: _,
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs,
|
||||
define_opaque,
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let (generics, (ty, rhs)) = self.lower_generics(
|
||||
|
|
@ -279,8 +297,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
|
||||
(ty, rhs)
|
||||
},
|
||||
|
|
@ -288,6 +308,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_define_opaque(hir_id, &define_opaque);
|
||||
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 {
|
||||
sig: FnSig { decl, header, span: fn_sig_span },
|
||||
ident,
|
||||
|
|
@ -379,7 +412,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
|
||||
}
|
||||
Some(ty) => this.lower_ty(
|
||||
Some(ty) => this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||
|
|
@ -453,7 +486,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
.as_deref()
|
||||
.map(|of_trait| this.lower_trait_impl_header(of_trait));
|
||||
|
||||
let lowered_ty = this.lower_ty(
|
||||
let lowered_ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
|
||||
);
|
||||
|
|
@ -522,7 +555,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
hir::ItemKind::TraitAlias(constness, ident, generics, bounds)
|
||||
}
|
||||
ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_extern_target: _ }) => {
|
||||
ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_declaration: _ }) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let body = Box::new(self.lower_delim_args(body));
|
||||
let def_id = self.local_def_id(id);
|
||||
|
|
@ -536,7 +569,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let macro_def = self.arena.alloc(ast::MacroDef {
|
||||
body,
|
||||
macro_rules: *macro_rules,
|
||||
eii_extern_target: None,
|
||||
eii_declaration: None,
|
||||
});
|
||||
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
|
||||
}
|
||||
|
|
@ -676,7 +709,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
has_delayed_lints: !this.delayed_lints.is_empty(),
|
||||
eii: find_attr!(
|
||||
attrs,
|
||||
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
|
||||
AttributeKind::EiiImpls(..) | AttributeKind::EiiDeclaration(..)
|
||||
),
|
||||
};
|
||||
hir::OwnerNode::Item(this.arena.alloc(item))
|
||||
|
|
@ -758,8 +791,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
safety,
|
||||
define_opaque,
|
||||
}) => {
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let safety = self.lower_safety(*safety, hir::Safety::Unsafe);
|
||||
if define_opaque.is_some() {
|
||||
self.dcx().span_err(i.span, "foreign statics cannot define opaque types");
|
||||
|
|
@ -870,7 +903,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut self,
|
||||
(index, f): (usize, &FieldDef),
|
||||
) -> hir::FieldDef<'hir> {
|
||||
let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
|
||||
let ty =
|
||||
self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
|
||||
let hir_id = self.lower_node_id(f.id);
|
||||
self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field);
|
||||
hir::FieldDef {
|
||||
|
|
@ -908,8 +942,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
let rhs = rhs
|
||||
.as_ref()
|
||||
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
|
||||
|
|
@ -1008,7 +1044,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = ty.as_ref().map(|x| {
|
||||
this.lower_ty(
|
||||
this.lower_ty_alloc(
|
||||
x,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
|
||||
)
|
||||
|
|
@ -1120,8 +1156,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
this.lower_define_opaque(hir_id, &define_opaque);
|
||||
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
|
||||
hir::ImplItemKind::Const(ty, rhs)
|
||||
|
|
@ -1180,7 +1218,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ImplItemKind::Type(ty)
|
||||
}
|
||||
Some(ty) => {
|
||||
let ty = this.lower_ty(
|
||||
let ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||
|
|
@ -1916,7 +1954,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
bound_generic_params,
|
||||
hir::GenericParamSource::Binder,
|
||||
),
|
||||
bounded_ty: self.lower_ty(
|
||||
bounded_ty: self.lower_ty_alloc(
|
||||
bounded_ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
|
|
@ -1945,10 +1983,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
|
||||
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty: self
|
||||
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
rhs_ty: self
|
||||
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
lhs_ty: self.lower_ty_alloc(
|
||||
lhs_ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
rhs_ty: self.lower_ty_alloc(
|
||||
rhs_ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
})
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ use rustc_hir::attrs::AttributeKind;
|
|||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::lints::{AttributeLint, DelayedLint};
|
||||
use rustc_hir::{
|
||||
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
|
||||
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
|
||||
|
|
@ -1022,12 +1022,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.attribute_parser.parse_attribute_list(
|
||||
attrs,
|
||||
target_span,
|
||||
target_hir_id,
|
||||
target,
|
||||
OmitDoc::Lower,
|
||||
|s| l.lower(s),
|
||||
|l| {
|
||||
self.delayed_lints.push(DelayedLint::AttributeParsing(l));
|
||||
|lint_id, span, kind| {
|
||||
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
|
||||
lint_id,
|
||||
id: target_hir_id,
|
||||
span,
|
||||
kind,
|
||||
}));
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -1125,8 +1129,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let kind = match &constraint.kind {
|
||||
AssocItemConstraintKind::Equality { term } => {
|
||||
let term = match term {
|
||||
Term::Ty(ty) => self.lower_ty(ty, itctx).into(),
|
||||
Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(),
|
||||
Term::Ty(ty) => self.lower_ty_alloc(ty, itctx).into(),
|
||||
Term::Const(c) => self.lower_anon_const_to_const_arg_and_alloc(c).into(),
|
||||
};
|
||||
hir::AssocItemConstraintKind::Equality { term }
|
||||
}
|
||||
|
|
@ -1250,17 +1254,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
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())
|
||||
GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().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))]
|
||||
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
|
||||
self.arena.alloc(self.lower_ty_direct(t, itctx))
|
||||
fn lower_ty_alloc(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
|
||||
self.arena.alloc(self.lower_ty(t, itctx))
|
||||
}
|
||||
|
||||
fn lower_path_ty(
|
||||
|
|
@ -1324,11 +1328,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.ty(span, hir::TyKind::Tup(tys))
|
||||
}
|
||||
|
||||
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
||||
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
||||
let kind = match &t.kind {
|
||||
TyKind::Infer => hir::TyKind::Infer(()),
|
||||
TyKind::Err(guar) => hir::TyKind::Err(*guar),
|
||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty_alloc(ty, itctx)),
|
||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||
TyKind::Ref(region, mt) => {
|
||||
let lifetime = self.lower_ty_direct_lifetime(t, *region);
|
||||
|
|
@ -1362,15 +1366,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
||||
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
|
||||
generic_params,
|
||||
inner_ty: self.lower_ty(&f.inner_ty, itctx),
|
||||
inner_ty: self.lower_ty_alloc(&f.inner_ty, itctx),
|
||||
}))
|
||||
}
|
||||
TyKind::Never => hir::TyKind::Never,
|
||||
TyKind::Tup(tys) => hir::TyKind::Tup(
|
||||
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
|
||||
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty(ty, itctx))),
|
||||
),
|
||||
TyKind::Paren(ty) => {
|
||||
return self.lower_ty_direct(ty, itctx);
|
||||
return self.lower_ty(ty, itctx);
|
||||
}
|
||||
TyKind::Path(qself, path) => {
|
||||
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
|
||||
|
|
@ -1393,7 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
))
|
||||
}
|
||||
TyKind::Array(ty, length) => hir::TyKind::Array(
|
||||
self.lower_ty(ty, itctx),
|
||||
self.lower_ty_alloc(ty, itctx),
|
||||
self.lower_array_length_to_const_arg(length),
|
||||
),
|
||||
TyKind::TraitObject(bounds, kind) => {
|
||||
|
|
@ -1493,7 +1497,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
TyKind::Pat(ty, pat) => {
|
||||
hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span))
|
||||
hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span))
|
||||
}
|
||||
TyKind::MacCall(_) => {
|
||||
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
|
||||
|
|
@ -1693,7 +1697,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
|
||||
}
|
||||
};
|
||||
self.lower_ty_direct(¶m.ty, itctx)
|
||||
self.lower_ty(¶m.ty, itctx)
|
||||
}));
|
||||
|
||||
let output = match coro {
|
||||
|
|
@ -1732,7 +1736,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn)
|
||||
}
|
||||
};
|
||||
hir::FnRetTy::Return(self.lower_ty(ty, itctx))
|
||||
hir::FnRetTy::Return(self.lower_ty_alloc(ty, itctx))
|
||||
}
|
||||
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
|
||||
},
|
||||
|
|
@ -1843,7 +1847,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
|
||||
// `impl Future` opaque type that `async fn` implicitly
|
||||
// generates.
|
||||
self.lower_ty(ty, itctx)
|
||||
self.lower_ty_alloc(ty, itctx)
|
||||
}
|
||||
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
|
||||
};
|
||||
|
|
@ -1986,8 +1990,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let (name, kind) = self.lower_generic_param_kind(param, source);
|
||||
|
||||
let hir_id = self.lower_node_id(param.id);
|
||||
self.lower_attrs(hir_id, ¶m.attrs, param.span(), Target::Param);
|
||||
hir::GenericParam {
|
||||
let param_attrs = ¶m.attrs;
|
||||
let param_span = param.span();
|
||||
let param = hir::GenericParam {
|
||||
hir_id,
|
||||
def_id: self.local_def_id(param.id),
|
||||
name,
|
||||
|
|
@ -1996,7 +2001,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
kind,
|
||||
colon_span: param.colon_span.map(|s| self.lower_span(s)),
|
||||
source,
|
||||
}
|
||||
};
|
||||
self.lower_attrs(hir_id, param_attrs, param_span, Target::from_generic_param(¶m));
|
||||
param
|
||||
}
|
||||
|
||||
fn lower_generic_param_kind(
|
||||
|
|
@ -2036,7 +2043,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
})
|
||||
.map(|def| {
|
||||
self.lower_ty(
|
||||
self.lower_ty_alloc(
|
||||
def,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
)
|
||||
|
|
@ -2047,8 +2054,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||
}
|
||||
GenericParamKind::Const { ty, span: _, default } => {
|
||||
let ty = self
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
|
||||
let ty = self.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
);
|
||||
|
||||
// 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).
|
||||
|
|
@ -2064,7 +2073,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
false
|
||||
}
|
||||
})
|
||||
.map(|def| self.lower_anon_const_to_const_arg(def));
|
||||
.map(|def| self.lower_anon_const_to_const_arg_and_alloc(def));
|
||||
|
||||
(
|
||||
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
||||
|
|
@ -2198,7 +2207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
|
||||
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
|
||||
hir::MutTy { ty: self.lower_ty_alloc(&mt.ty, itctx), mutbl: mt.mutbl }
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
|
|
@ -2283,10 +2292,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer`
|
||||
match c.value.peel_parens().kind {
|
||||
ExprKind::Underscore => {
|
||||
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
|
||||
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
|
||||
let ct_kind = hir::ConstArgKind::Infer(());
|
||||
self.arena.alloc(hir::ConstArg {
|
||||
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(c),
|
||||
_ => self.lower_anon_const_to_const_arg_and_alloc(c),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2354,7 +2367,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::ConstArgKind::Anon(ct)
|
||||
};
|
||||
|
||||
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
|
||||
self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: ct_kind,
|
||||
span: self.lower_span(span),
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_const_item_rhs(
|
||||
|
|
@ -2365,15 +2382,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
) -> hir::ConstItemRhs<'hir> {
|
||||
match rhs {
|
||||
Some(ConstItemRhs::TypeConst(anon)) => {
|
||||
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon))
|
||||
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
|
||||
}
|
||||
None if attr::contains_name(attrs, sym::type_const) => {
|
||||
None if find_attr!(attrs, AttributeKind::TypeConst(_)) => {
|
||||
let const_arg = ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Error(
|
||||
DUMMY_SP,
|
||||
self.dcx().span_delayed_bug(DUMMY_SP, "no block"),
|
||||
),
|
||||
span: DUMMY_SP,
|
||||
};
|
||||
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
|
||||
}
|
||||
|
|
@ -2386,16 +2403,65 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
#[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(expr.span, e.emit()) }
|
||||
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 = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
let def_kind = self.tcx.def_kind(def_id);
|
||||
assert_eq!(DefKind::AnonConst, def_kind);
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
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) => {
|
||||
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
|
||||
let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
let def_kind = self.tcx.def_kind(def_id);
|
||||
assert_eq!(DefKind::AnonConst, def_kind);
|
||||
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
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,
|
||||
|
|
@ -2408,7 +2474,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
None,
|
||||
);
|
||||
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) }
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span }
|
||||
}
|
||||
ExprKind::Struct(se) => {
|
||||
let path = self.lower_qpath(
|
||||
|
|
@ -2436,7 +2502,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let def_kind = self.tcx.def_kind(def_id);
|
||||
assert_eq!(DefKind::AnonConst, def_kind);
|
||||
|
||||
self.lower_anon_const_to_const_arg_direct(anon_const)
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(&f.expr)
|
||||
};
|
||||
|
|
@ -2449,18 +2515,50 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
})
|
||||
}));
|
||||
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) }
|
||||
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 = if let ExprKind::ConstBlock(anon_const) = &element.kind {
|
||||
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)
|
||||
} else {
|
||||
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(expr.span, ()),
|
||||
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::Block(..)
|
||||
| ExprKind::Path(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::Tup(..)
|
||||
| ExprKind::Array(..)
|
||||
)
|
||||
{
|
||||
return self.lower_expr_to_const_arg_direct(expr);
|
||||
|
|
@ -2468,18 +2566,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
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(literal.node),
|
||||
span,
|
||||
}
|
||||
}
|
||||
_ => overly_complex_const(self),
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
/// [`Self::lower_anon_const_to_anon_const`].
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
|
||||
self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon))
|
||||
fn lower_anon_const_to_const_arg_and_alloc(
|
||||
&mut self,
|
||||
anon: &AnonConst,
|
||||
) -> &'hir hir::ConstArg<'hir> {
|
||||
self.arena.alloc(self.lower_anon_const_to_const_arg(anon))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// We cannot change parsing depending on feature gates available,
|
||||
|
|
@ -2491,7 +2602,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
return match anon.mgca_disambiguation {
|
||||
MgcaDisambiguation::AnonConst => {
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
|
||||
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),
|
||||
};
|
||||
|
|
@ -2528,11 +2643,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
return ConstArg {
|
||||
hir_id: self.lower_node_id(anon.id),
|
||||
kind: hir::ConstArgKind::Path(qpath),
|
||||
span: self.lower_span(expr.span),
|
||||
};
|
||||
}
|
||||
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
|
||||
ConstArg {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -444,16 +444,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let pat_hir_id = self.lower_node_id(pattern.id);
|
||||
let node = match &pattern.kind {
|
||||
TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
|
||||
e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| {
|
||||
self.lower_ty_pat_range_end(
|
||||
hir::LangItem::RangeMin,
|
||||
span.shrink_to_lo(),
|
||||
base_type,
|
||||
)
|
||||
}),
|
||||
e1.as_deref()
|
||||
.map(|e| self.lower_anon_const_to_const_arg_and_alloc(e))
|
||||
.unwrap_or_else(|| {
|
||||
self.lower_ty_pat_range_end(
|
||||
hir::LangItem::RangeMin,
|
||||
span.shrink_to_lo(),
|
||||
base_type,
|
||||
)
|
||||
}),
|
||||
e2.as_deref()
|
||||
.map(|e| match end {
|
||||
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e),
|
||||
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg_and_alloc(e),
|
||||
RangeEnd::Excluded => self.lower_excluded_range_end(e),
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
|
|
@ -511,6 +513,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -555,6 +558,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
})
|
||||
});
|
||||
let hir_id = self.next_id();
|
||||
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id })
|
||||
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id, span })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let qself = qself
|
||||
.as_ref()
|
||||
// Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
|
||||
.map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
|
||||
.map(|q| {
|
||||
self.lower_ty_alloc(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))
|
||||
});
|
||||
|
||||
let partial_res =
|
||||
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||
|
|
@ -510,7 +512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// we generally don't permit such things (see #51008).
|
||||
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
|
||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
|
||||
self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||
}));
|
||||
let output_ty = match output {
|
||||
// Only allow `impl Trait` in return position. i.e.:
|
||||
|
|
@ -520,9 +522,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// ```
|
||||
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
|
||||
if self.tcx.features().impl_trait_in_fn_trait_return() {
|
||||
self.lower_ty(ty, itctx)
|
||||
self.lower_ty_alloc(ty, itctx)
|
||||
} else {
|
||||
self.lower_ty(
|
||||
self.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::FeatureGated(
|
||||
ImplTraitPosition::FnTraitReturn,
|
||||
|
|
@ -531,9 +533,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
)
|
||||
}
|
||||
}
|
||||
FnRetTy::Ty(ty) => {
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
|
||||
}
|
||||
FnRetTy::Ty(ty) => self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
|
||||
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ pub(crate) fn extern_abi_enabled(
|
|||
})
|
||||
}
|
||||
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
|
||||
match extern_abi_enabled(features, span, abi) {
|
||||
Ok(_) => (),
|
||||
|
|
@ -96,6 +95,11 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
ExternAbi::RustCold => {
|
||||
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 => {
|
||||
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,10 +400,18 @@ impl<'a> AstValidator<'a> {
|
|||
CanonAbi::C
|
||||
| CanonAbi::Rust
|
||||
| CanonAbi::RustCold
|
||||
| CanonAbi::RustPreserveNone
|
||||
| CanonAbi::Arm(_)
|
||||
| CanonAbi::GpuKernel
|
||||
| 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 => {
|
||||
// An `extern "custom"` function must be unsafe.
|
||||
self.reject_safe_fn(abi, ctxt, sig);
|
||||
|
|
@ -433,18 +441,7 @@ impl<'a> AstValidator<'a> {
|
|||
self.dcx().emit_err(errors::AbiX86Interrupt { spans, param_count });
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
self.reject_return(abi, sig);
|
||||
} else {
|
||||
// An `extern "interrupt"` function must have type `fn()`.
|
||||
self.reject_params_or_return(abi, ident, sig);
|
||||
|
|
@ -496,6 +493,18 @@ 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) {
|
||||
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
|
||||
|
|
|
|||
|
|
@ -13,15 +13,11 @@ use crate::errors;
|
|||
macro_rules! gate {
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
|
||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||
// 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();
|
||||
}
|
||||
}};
|
||||
|
|
@ -31,13 +27,11 @@ macro_rules! gate {
|
|||
macro_rules! gate_alt {
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
|
||||
if !$has_feature && !$span.allows_unstable($name) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
||||
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);
|
||||
for note in $notes {
|
||||
diag.note(*note);
|
||||
|
|
@ -160,7 +154,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
|||
|
||||
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
||||
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
let attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
|
||||
// Check feature gates for built-in attributes.
|
||||
if let Some(BuiltinAttribute {
|
||||
gate: AttributeGate::Gated { feature, message, check, notes, .. },
|
||||
|
|
@ -491,7 +485,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
|
||||
&& (!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
|
||||
// as coroutines and gen_blocks imply yield_expr.
|
||||
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
|
||||
|
|
@ -505,7 +498,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
half_open_range_patterns_in_slices,
|
||||
"half-open range patterns in slices are unstable"
|
||||
);
|
||||
gate_all!(associated_const_equality, "associated const equality is incomplete");
|
||||
gate_all!(yeet_expr, "`do yeet` expression is experimental");
|
||||
gate_all!(const_closures, "const closures are experimental");
|
||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||
|
|
@ -518,6 +510,22 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(postfix_match, "postfix match is 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
gate_all!(global_registration, "global registration is experimental");
|
||||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||
|
|
@ -529,6 +537,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(super_let, "`super let` is experimental");
|
||||
gate_all!(frontmatter, "frontmatters are experimental");
|
||||
gate_all!(coroutines, "coroutine syntax is experimental");
|
||||
gate_all!(const_block_items, "const block items are experimental");
|
||||
|
||||
if !visitor.features.never_patterns() {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
@ -543,7 +552,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
if let Ok(snippet) = sm.span_to_snippet(span)
|
||||
&& snippet == "!"
|
||||
{
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
|
||||
.emit();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||
}
|
||||
match &item.args {
|
||||
match &item.args.unparsed_ref().expect("Parsed attributes are never printed") {
|
||||
AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
|
||||
Some(MacHeader::Path(&item.path)),
|
||||
false,
|
||||
|
|
@ -865,10 +865,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
sp: Span,
|
||||
print_visibility: impl FnOnce(&mut Self),
|
||||
) {
|
||||
if let Some(eii_extern_target) = ¯o_def.eii_extern_target {
|
||||
self.word("#[eii_extern_target(");
|
||||
self.print_path(&eii_extern_target.extern_item_path, false, 0);
|
||||
if eii_extern_target.impl_unsafe {
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -205,6 +205,17 @@ impl<'a> State<'a> {
|
|||
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 {
|
||||
defaultness,
|
||||
ident,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ attr_parsing_doc_alias_malformed =
|
|||
attr_parsing_doc_alias_start_end =
|
||||
{$attr_str} cannot start or end with ' '
|
||||
|
||||
attr_parsing_doc_attr_not_crate_level =
|
||||
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
|
||||
|
||||
attr_parsing_doc_attribute_not_attribute =
|
||||
nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]`
|
||||
.help = only existing builtin attributes are allowed in core/std
|
||||
|
|
@ -227,7 +230,7 @@ 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]`
|
||||
.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_instruction_set = target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_feature::{
|
|||
};
|
||||
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::{exp, parse_in};
|
||||
use rustc_session::Session;
|
||||
|
|
@ -94,7 +94,6 @@ pub fn parse_cfg_entry<S: Stage>(
|
|||
LitKind::Bool(b) => CfgEntry::Bool(b, lit.span),
|
||||
_ => return Err(cx.expected_identifier(lit.span)),
|
||||
},
|
||||
MetaItemOrLitParser::Err(_, err) => return Err(*err),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -294,11 +293,9 @@ pub fn parse_cfg_attr(
|
|||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
|
||||
match cfg_attr.get_normal_item().args {
|
||||
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
|
||||
if !tokens.is_empty() =>
|
||||
{
|
||||
check_cfg_attr_bad_delim(&sess.psess, dspan, delim);
|
||||
match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() {
|
||||
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => {
|
||||
check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim);
|
||||
match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
|
||||
parse_cfg_attr_internal(p, sess, features, cfg_attr)
|
||||
}) {
|
||||
|
|
@ -322,7 +319,7 @@ pub fn parse_cfg_attr(
|
|||
}
|
||||
_ => {
|
||||
let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) =
|
||||
cfg_attr.get_normal_item().args
|
||||
cfg_attr.get_normal_item().args.unparsed_ref()?
|
||||
{
|
||||
(dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument)
|
||||
} else {
|
||||
|
|
@ -363,7 +360,8 @@ fn parse_cfg_attr_internal<'a>(
|
|||
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
|
||||
// Parse cfg predicate
|
||||
let pred_start = parser.token.span;
|
||||
let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?;
|
||||
let meta =
|
||||
MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints { recover: true })?;
|
||||
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
||||
|
||||
let cfg_predicate = AttributeParser::parse_single_args(
|
||||
|
|
@ -371,19 +369,14 @@ fn parse_cfg_attr_internal<'a>(
|
|||
attribute.span,
|
||||
attribute.get_normal_item().span(),
|
||||
attribute.style,
|
||||
AttrPath {
|
||||
segments: attribute
|
||||
.ident_path()
|
||||
.expect("cfg_attr is not a doc comment")
|
||||
.into_boxed_slice(),
|
||||
span: attribute.span,
|
||||
},
|
||||
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
|
||||
Some(attribute.get_normal_item().unsafety),
|
||||
ParsedDescription::Attribute,
|
||||
pred_span,
|
||||
CRATE_NODE_ID,
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&CFG_ATTR_TEMPLATE,
|
||||
|
|
@ -420,7 +413,6 @@ fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Feat
|
|||
}
|
||||
}
|
||||
|
||||
#[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) {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ use rustc_ast::token::Token;
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrStyle, NodeId, token};
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_hir::{AttrPath, Target};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span};
|
||||
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
|
|
@ -78,24 +78,24 @@ pub fn parse_cfg_select(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let meta =
|
||||
MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints { recover: true })
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
sess,
|
||||
cfg_span,
|
||||
cfg_span,
|
||||
AttrStyle::Inner,
|
||||
AttrPath {
|
||||
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
|
||||
span: cfg_span,
|
||||
},
|
||||
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
|
||||
None,
|
||||
ParsedDescription::Macro,
|
||||
cfg_span,
|
||||
lint_node_id,
|
||||
// Doesn't matter what the target actually is here.
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&AttributeTemplate::default(),
|
||||
|
|
|
|||
|
|
@ -709,11 +709,108 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisPa
|
|||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
|
||||
}
|
||||
|
||||
pub(crate) struct EiiExternItemParser;
|
||||
pub(crate) struct EiiForeignItemParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for EiiExternItemParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_eii_extern_item];
|
||||
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::EiiExternItem;
|
||||
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),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
use rustc_hir::attrs::WindowsSubsystemKind;
|
||||
use rustc_hir::attrs::{CrateType, 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::*;
|
||||
|
||||
|
|
@ -9,7 +13,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(n) = args else {
|
||||
|
|
@ -26,6 +30,56 @@ 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;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
||||
|
|
@ -33,7 +87,7 @@ impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
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 ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
|
|
@ -56,7 +110,7 @@ impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
|
|
@ -79,7 +133,7 @@ impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
|
|
@ -102,7 +156,7 @@ impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
|
|
@ -123,7 +177,7 @@ pub(crate) struct NoCoreParser;
|
|||
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
|
||||
const PATH: &[Symbol] = &[sym::no_core];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
|
||||
}
|
||||
|
||||
|
|
@ -132,16 +186,25 @@ pub(crate) struct NoStdParser;
|
|||
impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
|
||||
const PATH: &[Symbol] = &[sym::no_std];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
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;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +214,7 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
|||
const PATH: &[Symbol] = &[sym::windows_subsystem];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
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> {
|
||||
|
|
@ -175,3 +238,39 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@ fn get<S: Stage>(
|
|||
name: Symbol,
|
||||
param_span: Span,
|
||||
arg: &ArgParser,
|
||||
item: &Option<Symbol>,
|
||||
) -> Option<Symbol> {
|
||||
item: Option<Symbol>,
|
||||
) -> Option<Ident> {
|
||||
if item.is_some() {
|
||||
cx.duplicate_key(param_span, name);
|
||||
return None;
|
||||
}
|
||||
if let Some(v) = arg.name_value() {
|
||||
if let Some(value_str) = v.value_as_str() {
|
||||
if let Some(value_str) = v.value_as_ident() {
|
||||
Some(value_str)
|
||||
} else {
|
||||
cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
|
||||
|
|
@ -72,7 +72,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
|||
let features = cx.features();
|
||||
|
||||
let mut since = None;
|
||||
let mut note = None;
|
||||
let mut note: Option<Ident> = None;
|
||||
let mut suggestion = None;
|
||||
|
||||
let is_rustc = features.staged_api();
|
||||
|
|
@ -92,10 +92,16 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
|||
|
||||
match ident_name {
|
||||
Some(name @ sym::since) => {
|
||||
since = Some(get(cx, name, param.span(), param.args(), &since)?);
|
||||
since = Some(get(cx, name, param.span(), param.args(), since)?.name);
|
||||
}
|
||||
Some(name @ sym::note) => {
|
||||
note = Some(get(cx, name, param.span(), param.args(), ¬e)?);
|
||||
note = Some(get(
|
||||
cx,
|
||||
name,
|
||||
param.span(),
|
||||
param.args(),
|
||||
note.map(|ident| ident.name),
|
||||
)?);
|
||||
}
|
||||
Some(name @ sym::suggestion) => {
|
||||
if !features.deprecated_suggestion() {
|
||||
|
|
@ -107,7 +113,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
|||
}
|
||||
|
||||
suggestion =
|
||||
Some(get(cx, name, param.span(), param.args(), &suggestion)?);
|
||||
Some(get(cx, name, param.span(), param.args(), suggestion)?.name);
|
||||
}
|
||||
_ => {
|
||||
cx.expected_specific_argument(
|
||||
|
|
@ -124,7 +130,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
|||
}
|
||||
}
|
||||
ArgParser::NameValue(v) => {
|
||||
let Some(value) = v.value_as_str() else {
|
||||
let Some(value) = v.value_as_ident() else {
|
||||
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
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,5 +1,6 @@
|
|||
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,
|
||||
};
|
||||
|
|
@ -12,8 +13,8 @@ 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, DocAttributeNotAttribute,
|
||||
DocKeywordNotKeyword,
|
||||
DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel,
|
||||
DocAttributeNotAttribute, DocKeywordNotKeyword,
|
||||
};
|
||||
|
||||
fn check_keyword<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool {
|
||||
|
|
@ -43,16 +44,39 @@ fn check_attribute<S: Stage>(
|
|||
false
|
||||
}
|
||||
|
||||
fn parse_keyword_and_attribute<S, F>(
|
||||
/// 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
|
||||
}
|
||||
|
||||
fn parse_keyword_and_attribute<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
path: &OwnedPathParser,
|
||||
args: &ArgParser,
|
||||
attr_value: &mut Option<(Symbol, Span)>,
|
||||
callback: F,
|
||||
) where
|
||||
S: Stage,
|
||||
F: FnOnce(&mut AcceptContext<'_, '_, S>, Symbol, Span) -> bool,
|
||||
{
|
||||
attr_name: Symbol,
|
||||
) {
|
||||
let Some(nv) = args.name_value() else {
|
||||
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
|
||||
return;
|
||||
|
|
@ -63,16 +87,26 @@ fn parse_keyword_and_attribute<S, F>(
|
|||
return;
|
||||
};
|
||||
|
||||
if !callback(cx, value, nv.value_span) {
|
||||
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(path.span(), path.word_sym().unwrap());
|
||||
cx.duplicate_key(span, path.word_sym().unwrap());
|
||||
return;
|
||||
}
|
||||
|
||||
*attr_value = Some((value, path.span()));
|
||||
if !check_attr_not_crate_level(cx, span, attr_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
*attr_value = Some((value, span));
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
|
@ -102,6 +136,10 @@ impl DocParser {
|
|||
return;
|
||||
}
|
||||
|
||||
if !check_attr_crate_level(cx, path.span()) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.attribute.no_crate_inject = Some(path.span())
|
||||
}
|
||||
Some(sym::attr) => {
|
||||
|
|
@ -155,6 +193,9 @@ impl DocParser {
|
|||
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(
|
||||
|
|
@ -366,7 +407,33 @@ impl DocParser {
|
|||
self.attribute.$ident = Some(path.span());
|
||||
}};
|
||||
}
|
||||
macro_rules! string_arg {
|
||||
macro_rules! no_args_and_not_crate_level {
|
||||
($ident: ident) => {{
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.expected_no_args(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() {
|
||||
cx.expected_no_args(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 {
|
||||
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
|
||||
|
|
@ -378,6 +445,10 @@ impl DocParser {
|
|||
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
|
||||
|
|
@ -394,12 +465,14 @@ impl DocParser {
|
|||
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!(html_favicon_url),
|
||||
Some(sym::html_logo_url) => string_arg!(html_logo_url),
|
||||
Some(sym::html_no_source) => no_args!(html_no_source),
|
||||
Some(sym::html_playground_url) => string_arg!(html_playground_url),
|
||||
Some(sym::html_root_url) => string_arg!(html_root_url),
|
||||
Some(sym::issue_tracker_base_url) => string_arg!(issue_tracker_base_url),
|
||||
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),
|
||||
|
|
@ -410,18 +483,18 @@ impl DocParser {
|
|||
path,
|
||||
args,
|
||||
&mut self.attribute.keyword,
|
||||
check_keyword,
|
||||
sym::keyword,
|
||||
),
|
||||
Some(sym::attribute) => parse_keyword_and_attribute(
|
||||
cx,
|
||||
path,
|
||||
args,
|
||||
&mut self.attribute.attribute,
|
||||
check_attribute,
|
||||
sym::attribute,
|
||||
),
|
||||
Some(sym::fake_variadic) => no_args!(fake_variadic),
|
||||
Some(sym::search_unbox) => no_args!(search_unbox),
|
||||
Some(sym::rust_logo) => no_args!(rust_logo),
|
||||
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 {
|
||||
|
|
@ -441,9 +514,6 @@ impl DocParser {
|
|||
MetaItemOrLitParser::Lit(lit) => {
|
||||
cx.unexpected_literal(lit.span);
|
||||
}
|
||||
MetaItemOrLitParser::Err(..) => {
|
||||
// already had an error here, move on.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -527,9 +597,6 @@ impl DocParser {
|
|||
MetaItemOrLitParser::Lit(lit) => {
|
||||
cx.expected_name_value(lit.span, None);
|
||||
}
|
||||
MetaItemOrLitParser::Err(..) => {
|
||||
// already had an error here, move on.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,8 +141,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
|||
|
||||
macro report_unstable_modifier($feature: ident) {
|
||||
if !features.$feature() {
|
||||
// FIXME: make this translatable
|
||||
#[expect(rustc::untranslatable_diagnostic)]
|
||||
feature_err(
|
||||
sess,
|
||||
sym::$feature,
|
||||
|
|
@ -658,3 +656,21 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_hir::attrs::MacroUseArgs;
|
||||
use rustc_hir::attrs::{CollapseMacroDebuginfo, MacroUseArgs};
|
||||
use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS;
|
||||
|
||||
use super::prelude::*;
|
||||
|
|
@ -163,3 +163,46 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
|
|||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ pub(crate) mod confusables;
|
|||
pub(crate) mod crate_level;
|
||||
pub(crate) mod debugger;
|
||||
pub(crate) mod deprecation;
|
||||
pub(crate) mod do_not_recommend;
|
||||
pub(crate) mod doc;
|
||||
pub(crate) mod dummy;
|
||||
pub(crate) mod inline;
|
||||
|
|
@ -47,6 +48,7 @@ pub(crate) mod link_attrs;
|
|||
pub(crate) mod lint_helpers;
|
||||
pub(crate) mod loop_match;
|
||||
pub(crate) mod macro_attrs;
|
||||
pub(crate) mod must_not_suspend;
|
||||
pub(crate) mod must_use;
|
||||
pub(crate) mod no_implicit_prelude;
|
||||
pub(crate) mod no_link;
|
||||
|
|
@ -56,6 +58,8 @@ pub(crate) mod pin_v2;
|
|||
pub(crate) mod proc_macro_attrs;
|
||||
pub(crate) mod prototype;
|
||||
pub(crate) mod repr;
|
||||
pub(crate) mod rustc_allocator;
|
||||
pub(crate) mod rustc_dump;
|
||||
pub(crate) mod rustc_internal;
|
||||
pub(crate) mod semantics;
|
||||
pub(crate) mod stability;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
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 })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
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;
|
||||
}
|
||||
62
compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
Normal file
62
compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
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 RustcDumpUserArgs;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgs {
|
||||
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 RustcDumpDefParents;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParents {
|
||||
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 RustcDumpItemBounds;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBounds {
|
||||
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 RustcDumpPredicates;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicates {
|
||||
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 RustcDumpVtable;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtable {
|
||||
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;
|
||||
}
|
||||
|
|
@ -164,21 +164,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcLintDiagnosticsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintDiagnosticsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_diagnostics];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintDiagnostics;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcLintOptDenyFieldAccessParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
|
||||
|
|
@ -305,3 +290,42 @@ impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
|
|||
Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcHasIncoherentInherentImplsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Trait),
|
||||
Allow(Target::Struct),
|
||||
Allow(Target::Enum),
|
||||
Allow(Target::Union),
|
||||
Allow(Target::ForeignTy),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcNounwindParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_nounwind];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::ForeignFn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcOffloadKernelParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_offload_kernel];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::num::NonZero;
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::target::GenericParamKind;
|
||||
use rustc_hir::{
|
||||
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
|
||||
StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
|
||||
|
|
@ -43,7 +44,7 @@ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|||
Allow(Target::TyAlias),
|
||||
Allow(Target::Variant),
|
||||
Allow(Target::Field),
|
||||
Allow(Target::Param),
|
||||
Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
|
||||
Allow(Target::Static),
|
||||
Allow(Target::ForeignFn),
|
||||
Allow(Target::ForeignStatic),
|
||||
|
|
|
|||
|
|
@ -91,3 +91,25 @@ 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,12 +94,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
|
|||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
|
||||
}
|
||||
|
||||
pub(crate) struct DoNotImplementViaObjectParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object];
|
||||
pub(crate) struct DynIncompatibleTraitParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DynIncompatibleTrait;
|
||||
}
|
||||
|
||||
// Specialization
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@ use super::prelude::*;
|
|||
|
||||
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 {
|
||||
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
|
|
@ -15,7 +12,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
});
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
|
||||
template!(NameValueStr: ["transparent", "semiopaque", "opaque"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
|
|
@ -24,12 +21,12 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
};
|
||||
match nv.value_as_str() {
|
||||
Some(sym::transparent) => Some(Transparency::Transparent),
|
||||
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
|
||||
Some(sym::semiopaque) => Some(Transparency::SemiOpaque),
|
||||
Some(sym::opaque) => Some(Transparency::Opaque),
|
||||
Some(_) => {
|
||||
cx.expected_specific_argument_strings(
|
||||
nv.value_span,
|
||||
&[sym::transparent, sym::semitransparent, sym::opaque],
|
||||
&[sym::transparent, sym::semiopaque, sym::opaque],
|
||||
);
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
|
|||
}
|
||||
|
||||
pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
|
||||
attr.is_doc_comment().is_some()
|
||||
|| attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
|
||||
attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
|
||||
}
|
||||
|
||||
/// Parse a single integer.
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ use std::ops::{Deref, DerefMut};
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use private::Sealed;
|
||||
use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
|
||||
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
|
||||
use rustc_errors::{Diag, Diagnostic, Level};
|
||||
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_hir::{AttrPath, HirId};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
|
|
@ -21,26 +21,29 @@ use crate::attributes::allow_unstable::{
|
|||
use crate::attributes::body::CoroutineParser;
|
||||
use crate::attributes::cfi_encoding::CfiEncodingParser;
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, EiiExternItemParser, ExportNameParser, ForceTargetFeatureParser,
|
||||
ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser,
|
||||
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
|
||||
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
|
||||
ThreadLocalParser, TrackCallerParser, UsedParser,
|
||||
PatchableFunctionEntryParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser,
|
||||
TargetFeatureParser, ThreadLocalParser, TrackCallerParser, UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::crate_level::{
|
||||
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
|
||||
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
|
||||
WindowsSubsystemParser,
|
||||
CrateNameParser, CrateTypeParser, MoveSizeLimitParser, NeedsPanicRuntimeParser,
|
||||
NoBuiltinsParser, NoCoreParser, NoMainParser, NoStdParser, PanicRuntimeParser,
|
||||
PatternComplexityLimitParser, ProfilerRuntimeParser, RecursionLimitParser,
|
||||
RustcCoherenceIsCoreParser, TypeLengthLimitParser, WindowsSubsystemParser,
|
||||
};
|
||||
use crate::attributes::debugger::DebuggerViualizerParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::do_not_recommend::DoNotRecommendParser;
|
||||
use crate::attributes::doc::DocParser;
|
||||
use crate::attributes::dummy::DummyParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
use crate::attributes::instruction_set::InstructionSetParser;
|
||||
use crate::attributes::link_attrs::{
|
||||
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
|
||||
LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
|
||||
CompilerBuiltinsParser, ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser,
|
||||
LinkOrdinalParser, LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser,
|
||||
StdInternalSymbolParser,
|
||||
};
|
||||
use crate::attributes::lint_helpers::{
|
||||
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
|
||||
|
|
@ -48,8 +51,10 @@ use crate::attributes::lint_helpers::{
|
|||
};
|
||||
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
|
||||
use crate::attributes::macro_attrs::{
|
||||
AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser,
|
||||
AllowInternalUnsafeParser, CollapseDebugInfoParser, MacroEscapeParser, MacroExportParser,
|
||||
MacroUseParser,
|
||||
};
|
||||
use crate::attributes::must_not_suspend::MustNotSuspendParser;
|
||||
use crate::attributes::must_use::MustUseParser;
|
||||
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
|
||||
use crate::attributes::no_link::NoLinkParser;
|
||||
|
|
@ -61,24 +66,34 @@ use crate::attributes::proc_macro_attrs::{
|
|||
};
|
||||
use crate::attributes::prototype::CustomMirParser;
|
||||
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||
use crate::attributes::rustc_allocator::{
|
||||
RustcAllocatorParser, RustcAllocatorZeroedParser, RustcAllocatorZeroedVariantParser,
|
||||
RustcDeallocatorParser, RustcReallocatorParser,
|
||||
};
|
||||
use crate::attributes::rustc_dump::{
|
||||
RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs,
|
||||
RustcDumpVtable,
|
||||
};
|
||||
use crate::attributes::rustc_internal::{
|
||||
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
|
||||
RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser,
|
||||
RustcLintOptTyParser, RustcLintQueryInstabilityParser,
|
||||
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
|
||||
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
|
||||
RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
|
||||
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
|
||||
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, RustcNounwindParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcOffloadKernelParser, RustcScalableVectorParser,
|
||||
RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
};
|
||||
use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
|
||||
use crate::attributes::test_attrs::{
|
||||
IgnoreParser, RustcVarianceOfOpaquesParser, RustcVarianceParser, ShouldPanicParser,
|
||||
};
|
||||
use crate::attributes::traits::{
|
||||
AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
|
||||
DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
|
||||
PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
|
||||
DynIncompatibleTraitParser, FundamentalParser, MarkerParser, ParenSugarParser, PointeeParser,
|
||||
SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
|
||||
UnsafeSpecializationMarkerParser,
|
||||
};
|
||||
use crate::attributes::transparency::TransparencyParser;
|
||||
|
|
@ -88,23 +103,22 @@ use crate::session_diagnostics::{
|
|||
AttributeParseError, AttributeParseErrorReason, ParsedDescription,
|
||||
};
|
||||
use crate::target_checking::AllowedTargets;
|
||||
|
||||
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
||||
|
||||
pub(super) struct GroupTypeInner<S: Stage> {
|
||||
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
|
||||
pub(super) finalizers: Vec<FinalizeFn<S>>,
|
||||
}
|
||||
|
||||
pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
||||
pub(super) template: AttributeTemplate,
|
||||
pub(super) accept_fn: AcceptFn<S>,
|
||||
pub(super) allowed_targets: AllowedTargets,
|
||||
pub(super) finalizer: FinalizeFn<S>,
|
||||
}
|
||||
|
||||
type AcceptFn<S> =
|
||||
pub(crate) type AcceptFn<S> =
|
||||
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
|
||||
type FinalizeFn<S> =
|
||||
pub(crate) type FinalizeFn<S> =
|
||||
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
||||
|
||||
macro_rules! attribute_parsers {
|
||||
|
|
@ -132,8 +146,7 @@ macro_rules! attribute_parsers {
|
|||
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
|
||||
let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||
let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
|
||||
let mut accepters = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||
$(
|
||||
{
|
||||
thread_local! {
|
||||
|
|
@ -141,7 +154,7 @@ macro_rules! attribute_parsers {
|
|||
};
|
||||
|
||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||
accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||
accepters.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||
template: *template,
|
||||
accept_fn: Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
|
|
@ -149,17 +162,16 @@ macro_rules! attribute_parsers {
|
|||
})
|
||||
}),
|
||||
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
||||
finalizer: Box::new(|cx| {
|
||||
let state = STATE_OBJECT.take();
|
||||
state.finalize(cx)
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
finalizes.push(Box::new(|cx| {
|
||||
let state = STATE_OBJECT.take();
|
||||
state.finalize(cx)
|
||||
}));
|
||||
}
|
||||
)*
|
||||
|
||||
GroupTypeInner { accepters:accepts, finalizers:finalizes }
|
||||
GroupTypeInner { accepters }
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -181,6 +193,7 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-start
|
||||
Combine<AllowConstFnUnstableParser>,
|
||||
Combine<AllowInternalUnstableParser>,
|
||||
Combine<CrateTypeParser>,
|
||||
Combine<DebuggerViualizerParser>,
|
||||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<LinkParser>,
|
||||
|
|
@ -191,10 +204,12 @@ attribute_parsers!(
|
|||
|
||||
// tidy-alphabetical-start
|
||||
Single<CfiEncodingParser>,
|
||||
Single<CollapseDebugInfoParser>,
|
||||
Single<CoverageParser>,
|
||||
Single<CrateNameParser>,
|
||||
Single<CustomMirParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<DoNotRecommendParser>,
|
||||
Single<DummyParser>,
|
||||
Single<ExportNameParser>,
|
||||
Single<IgnoreParser>,
|
||||
|
|
@ -206,14 +221,17 @@ attribute_parsers!(
|
|||
Single<LinkageParser>,
|
||||
Single<MacroExportParser>,
|
||||
Single<MoveSizeLimitParser>,
|
||||
Single<MustNotSuspendParser>,
|
||||
Single<MustUseParser>,
|
||||
Single<ObjcClassParser>,
|
||||
Single<ObjcSelectorParser>,
|
||||
Single<OptimizeParser>,
|
||||
Single<PatchableFunctionEntryParser>,
|
||||
Single<PathAttributeParser>,
|
||||
Single<PatternComplexityLimitParser>,
|
||||
Single<ProcMacroDeriveParser>,
|
||||
Single<RecursionLimitParser>,
|
||||
Single<RustcAllocatorZeroedVariantParser>,
|
||||
Single<RustcBuiltinMacroParser>,
|
||||
Single<RustcForceInlineParser>,
|
||||
Single<RustcLayoutScalarValidRangeEndParser>,
|
||||
|
|
@ -236,12 +254,13 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
||||
Single<WithoutArgs<CoinductiveParser>>,
|
||||
Single<WithoutArgs<ColdParser>>,
|
||||
Single<WithoutArgs<CompilerBuiltinsParser>>,
|
||||
Single<WithoutArgs<ConstContinueParser>>,
|
||||
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
||||
Single<WithoutArgs<CoroutineParser>>,
|
||||
Single<WithoutArgs<DenyExplicitImplParser>>,
|
||||
Single<WithoutArgs<DoNotImplementViaObjectParser>>,
|
||||
Single<WithoutArgs<EiiExternItemParser>>,
|
||||
Single<WithoutArgs<DynIncompatibleTraitParser>>,
|
||||
Single<WithoutArgs<EiiForeignItemParser>>,
|
||||
Single<WithoutArgs<ExportStableParser>>,
|
||||
Single<WithoutArgs<FfiConstParser>>,
|
||||
Single<WithoutArgs<FfiPureParser>>,
|
||||
|
|
@ -250,29 +269,48 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<MacroEscapeParser>>,
|
||||
Single<WithoutArgs<MarkerParser>>,
|
||||
Single<WithoutArgs<MayDangleParser>>,
|
||||
Single<WithoutArgs<NeedsAllocatorParser>>,
|
||||
Single<WithoutArgs<NeedsPanicRuntimeParser>>,
|
||||
Single<WithoutArgs<NoBuiltinsParser>>,
|
||||
Single<WithoutArgs<NoCoreParser>>,
|
||||
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
||||
Single<WithoutArgs<NoLinkParser>>,
|
||||
Single<WithoutArgs<NoMainParser>>,
|
||||
Single<WithoutArgs<NoMangleParser>>,
|
||||
Single<WithoutArgs<NoStdParser>>,
|
||||
Single<WithoutArgs<NonExhaustiveParser>>,
|
||||
Single<WithoutArgs<PanicRuntimeParser>>,
|
||||
Single<WithoutArgs<ParenSugarParser>>,
|
||||
Single<WithoutArgs<PassByValueParser>>,
|
||||
Single<WithoutArgs<PinV2Parser>>,
|
||||
Single<WithoutArgs<PointeeParser>>,
|
||||
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
||||
Single<WithoutArgs<ProcMacroParser>>,
|
||||
Single<WithoutArgs<ProfilerRuntimeParser>>,
|
||||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
|
||||
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
||||
Single<WithoutArgs<RustcLintDiagnosticsParser>>,
|
||||
Single<WithoutArgs<RustcDeallocatorParser>>,
|
||||
Single<WithoutArgs<RustcDumpDefParents>>,
|
||||
Single<WithoutArgs<RustcDumpItemBounds>>,
|
||||
Single<WithoutArgs<RustcDumpPredicates>>,
|
||||
Single<WithoutArgs<RustcDumpUserArgs>>,
|
||||
Single<WithoutArgs<RustcDumpVtable>>,
|
||||
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
||||
Single<WithoutArgs<RustcLintOptTyParser>>,
|
||||
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
|
||||
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
|
||||
Single<WithoutArgs<RustcMainParser>>,
|
||||
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
||||
Single<WithoutArgs<RustcNounwindParser>>,
|
||||
Single<WithoutArgs<RustcOffloadKernelParser>>,
|
||||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||
Single<WithoutArgs<RustcReallocatorParser>>,
|
||||
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
||||
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
|
||||
Single<WithoutArgs<RustcVarianceParser>>,
|
||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||
Single<WithoutArgs<StdInternalSymbolParser>>,
|
||||
Single<WithoutArgs<ThreadLocalParser>>,
|
||||
|
|
@ -303,8 +341,6 @@ pub trait Stage: Sized + 'static + Sealed {
|
|||
) -> ErrorGuaranteed;
|
||||
|
||||
fn should_emit(&self) -> ShouldEmit;
|
||||
|
||||
fn id_is_crate_root(id: Self::Id) -> bool;
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
|
|
@ -326,10 +362,6 @@ impl Stage for Early {
|
|||
fn should_emit(&self) -> ShouldEmit {
|
||||
self.emit_errors
|
||||
}
|
||||
|
||||
fn id_is_crate_root(id: Self::Id) -> bool {
|
||||
id == CRATE_NODE_ID
|
||||
}
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
|
|
@ -349,11 +381,7 @@ impl Stage for Late {
|
|||
}
|
||||
|
||||
fn should_emit(&self) -> ShouldEmit {
|
||||
ShouldEmit::ErrorsAndLints
|
||||
}
|
||||
|
||||
fn id_is_crate_root(id: Self::Id) -> bool {
|
||||
id == CRATE_HIR_ID
|
||||
ShouldEmit::ErrorsAndLints { recover: true }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -410,12 +438,11 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
|||
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
|
||||
if !matches!(
|
||||
self.stage.should_emit(),
|
||||
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let id = self.target_id;
|
||||
(self.emit_lint)(AttributeLint { lint_id: LintId::of(lint), id, span, kind });
|
||||
(self.emit_lint)(LintId::of(lint), span, kind);
|
||||
}
|
||||
|
||||
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
|
||||
|
|
@ -487,6 +514,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_integer_literal_in_range(
|
||||
&self,
|
||||
span: Span,
|
||||
lower_bound: isize,
|
||||
upper_bound: isize,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
AttributeParseErrorReason::ExpectedIntegerLiteralInRange { lower_bound, upper_bound },
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
|
||||
let span = match args {
|
||||
ArgParser::NoArgs => span,
|
||||
|
|
@ -660,10 +699,11 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
|
|||
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
|
||||
/// The span of the syntactical component this attribute was applied to
|
||||
pub(crate) target_span: Span,
|
||||
/// 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,
|
||||
pub(crate) target: rustc_hir::Target,
|
||||
|
||||
pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
|
||||
/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
|
||||
/// 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.
|
||||
|
|
@ -725,9 +765,18 @@ pub enum ShouldEmit {
|
|||
EarlyFatal { also_emit_lints: bool },
|
||||
/// The operation will emit errors and lints.
|
||||
/// This is usually what you need.
|
||||
ErrorsAndLints,
|
||||
/// 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`.
|
||||
ErrorsAndLints {
|
||||
/// Whether [`ArgParser`] will attempt to recover from errors.
|
||||
///
|
||||
/// If true, it will attempt to recover from bad input (like an invalid literal). Setting
|
||||
/// this to false will instead return early, and not raise errors except at the top level
|
||||
/// (in [`ArgParser::from_attr_args`]).
|
||||
recover: bool,
|
||||
},
|
||||
/// 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,
|
||||
}
|
||||
|
||||
|
|
@ -736,7 +785,7 @@ impl ShouldEmit {
|
|||
match self {
|
||||
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
|
||||
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
|
||||
ShouldEmit::ErrorsAndLints => diag.emit(),
|
||||
ShouldEmit::ErrorsAndLints { .. } => diag.emit(),
|
||||
ShouldEmit::Nothing => diag.delay_as_bug(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
53
compiler/rustc_attr_parsing/src/early_parsed.rs
Normal file
53
compiler/rustc_attr_parsing/src/early_parsed.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,17 +2,18 @@ use std::convert::identity;
|
|||
|
||||
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_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLint;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::{BuiltinLintDiag, LintId};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
||||
use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
|
||||
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
|
||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
||||
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
||||
use crate::session_diagnostics::ParsedDescription;
|
||||
use crate::{Early, Late, OmitDoc, ShouldEmit};
|
||||
|
|
@ -112,16 +113,15 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
p.parse_attribute_list(
|
||||
attrs,
|
||||
target_span,
|
||||
target_node_id,
|
||||
target,
|
||||
OmitDoc::Skip,
|
||||
std::convert::identity,
|
||||
|lint| {
|
||||
|lint_id, span, kind| {
|
||||
sess.psess.buffer_lint(
|
||||
lint.lint_id.lint,
|
||||
lint.span,
|
||||
lint.id,
|
||||
BuiltinLintDiag::AttributeLint(lint.kind),
|
||||
lint_id.lint,
|
||||
span,
|
||||
target_node_id,
|
||||
BuiltinLintDiag::AttributeLint(kind),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -134,6 +134,7 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
attr: &ast::Attribute,
|
||||
target_span: Span,
|
||||
target_node_id: NodeId,
|
||||
target: Target,
|
||||
features: Option<&'sess Features>,
|
||||
emit_errors: ShouldEmit,
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
|
||||
|
|
@ -146,8 +147,12 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||
|
||||
let path = AttrPath::from_ast(&normal_attr.item.path, identity);
|
||||
let args =
|
||||
ArgParser::from_attr_args(&normal_attr.item.args, &parts, &sess.psess, emit_errors)?;
|
||||
let args = ArgParser::from_attr_args(
|
||||
&normal_attr.item.args.unparsed_ref().unwrap(),
|
||||
&parts,
|
||||
&sess.psess,
|
||||
emit_errors,
|
||||
)?;
|
||||
Self::parse_single_args(
|
||||
sess,
|
||||
attr.span,
|
||||
|
|
@ -158,6 +163,7 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
ParsedDescription::Attribute,
|
||||
target_span,
|
||||
target_node_id,
|
||||
target,
|
||||
features,
|
||||
emit_errors,
|
||||
&args,
|
||||
|
|
@ -178,6 +184,7 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
parsed_description: ParsedDescription,
|
||||
target_span: Span,
|
||||
target_node_id: NodeId,
|
||||
target: Target,
|
||||
features: Option<&'sess Features>,
|
||||
emit_errors: ShouldEmit,
|
||||
args: &I,
|
||||
|
|
@ -191,28 +198,22 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
sess,
|
||||
stage: Early { emit_errors },
|
||||
};
|
||||
let mut emit_lint = |lint: AttributeLint<NodeId>| {
|
||||
let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
|
||||
sess.psess.buffer_lint(
|
||||
lint.lint_id.lint,
|
||||
lint.span,
|
||||
lint.id,
|
||||
BuiltinLintDiag::AttributeLint(lint.kind),
|
||||
lint_id.lint,
|
||||
span,
|
||||
target_node_id,
|
||||
BuiltinLintDiag::AttributeLint(kind),
|
||||
)
|
||||
};
|
||||
if let Some(safety) = attr_safety {
|
||||
parser.check_attribute_safety(
|
||||
&attr_path,
|
||||
inner_span,
|
||||
safety,
|
||||
&mut emit_lint,
|
||||
target_node_id,
|
||||
)
|
||||
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
|
||||
}
|
||||
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
cx: &mut parser,
|
||||
target_span,
|
||||
target_id: target_node_id,
|
||||
target,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span,
|
||||
|
|
@ -260,15 +261,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
target_span: Span,
|
||||
target_id: S::Id,
|
||||
target: Target,
|
||||
omit_doc: OmitDoc,
|
||||
|
||||
lower_span: impl Copy + Fn(Span) -> Span,
|
||||
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
|
||||
mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
|
||||
) -> Vec<Attribute> {
|
||||
let mut attributes = Vec::new();
|
||||
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
|
||||
let mut early_parsed_state = EarlyParsedState::default();
|
||||
|
||||
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
|
||||
|
||||
for attr in attrs {
|
||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||
|
|
@ -288,6 +290,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let attr_span = lower_span(attr.span);
|
||||
match &attr.kind {
|
||||
ast::AttrKind::DocComment(comment_kind, symbol) => {
|
||||
if omit_doc == OmitDoc::Skip {
|
||||
|
|
@ -297,7 +300,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
||||
style: attr.style,
|
||||
kind: DocFragmentKind::Sugared(*comment_kind),
|
||||
span: lower_span(attr.span),
|
||||
span: attr_span,
|
||||
comment: *symbol,
|
||||
}))
|
||||
}
|
||||
|
|
@ -305,12 +308,20 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
attr_paths.push(PathParser(&n.item.path));
|
||||
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(
|
||||
&attr_path,
|
||||
lower_span(n.item.span()),
|
||||
n.item.unsafety,
|
||||
&mut emit_lint,
|
||||
target_id,
|
||||
);
|
||||
|
||||
let parts =
|
||||
|
|
@ -318,7 +329,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
|
||||
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
let Some(args) = ArgParser::from_attr_args(
|
||||
&n.item.args,
|
||||
args,
|
||||
&parts,
|
||||
&self.sess.psess,
|
||||
self.stage.should_emit(),
|
||||
|
|
@ -351,7 +362,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
||||
style: attr.style,
|
||||
kind: DocFragmentKind::Raw(nv.value_span),
|
||||
span: attr.span,
|
||||
span: attr_span,
|
||||
comment,
|
||||
}));
|
||||
continue;
|
||||
|
|
@ -362,10 +373,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
shared: SharedContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target_id,
|
||||
target,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span: lower_span(attr.span),
|
||||
attr_span,
|
||||
inner_span: lower_span(n.item.span()),
|
||||
attr_style: attr.style,
|
||||
parsed_description: ParsedDescription::Attribute,
|
||||
|
|
@ -374,6 +385,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
};
|
||||
|
||||
(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);
|
||||
}
|
||||
|
|
@ -396,39 +409,43 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
|
||||
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
|
||||
path: attr_path.clone(),
|
||||
args: self.lower_attr_args(&n.item.args, lower_span),
|
||||
args: self
|
||||
.lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span),
|
||||
id: HashIgnoredAttrId { attr_id: attr.id },
|
||||
style: attr.style,
|
||||
span: lower_span(attr.span),
|
||||
span: attr_span,
|
||||
})));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut parsed_attributes = Vec::new();
|
||||
for f in &S::parsers().finalizers {
|
||||
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
|
||||
for f in &finalizers {
|
||||
if let Some(attr) = f(&mut FinalizeContext {
|
||||
shared: SharedContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target_id,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
|
||||
all_attrs: &attr_paths,
|
||||
}) {
|
||||
parsed_attributes.push(Attribute::Parsed(attr));
|
||||
attributes.push(Attribute::Parsed(attr));
|
||||
}
|
||||
}
|
||||
|
||||
attributes.extend(parsed_attributes);
|
||||
|
||||
attributes
|
||||
}
|
||||
|
||||
/// Returns whether there is a parser for an attribute with this name
|
||||
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)
|
||||
|| EARLY_PARSED_ATTRIBUTES.contains(&path)
|
||||
|| SPECIAL_ATTRIBUTES.contains(&path)
|
||||
}
|
||||
|
||||
fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ mod interface;
|
|||
/// like lists or name-value pairs.
|
||||
pub mod parser;
|
||||
|
||||
mod early_parsed;
|
||||
mod safety;
|
||||
mod session_diagnostics;
|
||||
mod target_checking;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ use rustc_errors::{Diag, PResult};
|
|||
use rustc_hir::{self as hir, AttrPath};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
|
||||
use rustc_session::errors::{create_lit_error, report_lit_error};
|
||||
use rustc_session::errors::create_lit_error;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::ShouldEmit;
|
||||
|
|
@ -36,7 +36,7 @@ pub type RefPathParser<'p> = PathParser<&'p Path>;
|
|||
impl<P: Borrow<Path>> PathParser<P> {
|
||||
pub fn get_attribute_path(&self) -> hir::AttrPath {
|
||||
AttrPath {
|
||||
segments: self.segments().copied().collect::<Vec<_>>().into_boxed_slice(),
|
||||
segments: self.segments().map(|s| s.name).collect::<Vec<_>>().into_boxed_slice(),
|
||||
span: self.span(),
|
||||
}
|
||||
}
|
||||
|
|
@ -113,19 +113,36 @@ impl ArgParser {
|
|||
Some(match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
AttrArgs::Delimited(args) => {
|
||||
// The arguments of rustc_dummy are not validated if the arguments are delimited
|
||||
if parts == &[sym::rustc_dummy] {
|
||||
return Some(ArgParser::List(MetaItemListParser {
|
||||
sub_parsers: ThinVec::new(),
|
||||
span: args.dspan.entire(),
|
||||
}));
|
||||
// Diagnostic attributes can't error if they encounter non meta item syntax.
|
||||
// However, the current syntax for diagnostic attributes is meta item syntax.
|
||||
// Therefore we can substitute with a dummy value on invalid syntax.
|
||||
if matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
|
||||
match MetaItemListParser::new(
|
||||
&args.tokens,
|
||||
args.dspan.entire(),
|
||||
psess,
|
||||
ShouldEmit::ErrorsAndLints { recover: false },
|
||||
) {
|
||||
Ok(p) => return Some(ArgParser::List(p)),
|
||||
Err(e) => {
|
||||
// We can just dispose of the diagnostic and not bother with a lint,
|
||||
// because this will look like `#[diagnostic::attr()]` was used. This
|
||||
// is invalid for all diagnostic attrs, so a lint explaining the proper
|
||||
// form will be issued later.
|
||||
e.cancel();
|
||||
return Some(ArgParser::List(MetaItemListParser {
|
||||
sub_parsers: ThinVec::new(),
|
||||
span: args.dspan.entire(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if args.delim != Delimiter::Parenthesis {
|
||||
psess.dcx().emit_err(MetaBadDelim {
|
||||
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
|
||||
span: args.dspan.entire(),
|
||||
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
|
||||
});
|
||||
}));
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +154,9 @@ impl ArgParser {
|
|||
}
|
||||
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
||||
eq_span: *eq_span,
|
||||
value: expr_to_lit(psess, &expr, expr.span, should_emit)?,
|
||||
value: expr_to_lit(psess, &expr, expr.span, should_emit)
|
||||
.map_err(|e| should_emit.emit_err(e))
|
||||
.ok()??,
|
||||
value_span: expr.span,
|
||||
}),
|
||||
})
|
||||
|
|
@ -192,7 +211,6 @@ impl ArgParser {
|
|||
pub enum MetaItemOrLitParser {
|
||||
MetaItemParser(MetaItemParser),
|
||||
Lit(MetaItemLit),
|
||||
Err(Span, ErrorGuaranteed),
|
||||
}
|
||||
|
||||
impl MetaItemOrLitParser {
|
||||
|
|
@ -210,21 +228,20 @@ impl MetaItemOrLitParser {
|
|||
generic_meta_item_parser.span()
|
||||
}
|
||||
MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
|
||||
MetaItemOrLitParser::Err(span, _) => *span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lit(&self) -> Option<&MetaItemLit> {
|
||||
match self {
|
||||
MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit),
|
||||
_ => None,
|
||||
MetaItemOrLitParser::MetaItemParser(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn meta_item(&self) -> Option<&MetaItemParser> {
|
||||
match self {
|
||||
MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
|
||||
_ => None,
|
||||
MetaItemOrLitParser::Lit(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -322,63 +339,65 @@ impl NameValueParser {
|
|||
self.value_as_lit().kind.str()
|
||||
}
|
||||
|
||||
/// If the value is a string literal, it will return its value associated with its span (an
|
||||
/// `Ident` in short).
|
||||
pub fn value_as_ident(&self) -> Option<Ident> {
|
||||
let meta_item = self.value_as_lit();
|
||||
meta_item.kind.str().map(|name| Ident { name, span: meta_item.span })
|
||||
}
|
||||
|
||||
pub fn args_span(&self) -> Span {
|
||||
self.eq_span.to(self.value_span)
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_to_lit(
|
||||
psess: &ParseSess,
|
||||
fn expr_to_lit<'sess>(
|
||||
psess: &'sess ParseSess,
|
||||
expr: &Expr,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<MetaItemLit> {
|
||||
) -> PResult<'sess, Option<MetaItemLit>> {
|
||||
if let ExprKind::Lit(token_lit) = expr.kind {
|
||||
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
|
||||
match res {
|
||||
Ok(lit) => {
|
||||
if token_lit.suffix.is_some() {
|
||||
should_emit.emit_err(
|
||||
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
None
|
||||
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
|
||||
} else {
|
||||
if !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
should_emit.emit_err(
|
||||
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
if lit.kind.is_unsuffixed() {
|
||||
Ok(Some(lit))
|
||||
} else {
|
||||
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
|
||||
}
|
||||
|
||||
Some(lit)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let guar = report_lit_error(psess, err, token_lit, expr.span);
|
||||
let lit = MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::Err(guar),
|
||||
span: expr.span,
|
||||
};
|
||||
Some(lit)
|
||||
let err = create_lit_error(psess, err, token_lit, expr.span);
|
||||
if matches!(should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
|
||||
Err(err)
|
||||
} else {
|
||||
let lit = MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::Err(err.emit()),
|
||||
span: expr.span,
|
||||
};
|
||||
Ok(Some(lit))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if matches!(should_emit, ShouldEmit::Nothing) {
|
||||
return None;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Example cases:
|
||||
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
|
||||
// - `#[foo = include_str!("nonexistent-file.rs")]`:
|
||||
// results in `ast::ExprKind::Err`. In that case we delay
|
||||
// the error because an earlier error will have already
|
||||
// been reported.
|
||||
// results in `ast::ExprKind::Err`.
|
||||
let msg = "attribute value must be a literal";
|
||||
let err = psess.dcx().struct_span_err(span, msg);
|
||||
should_emit.emit_err(err);
|
||||
None
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -411,9 +430,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
|||
|
||||
if !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
self.should_emit.emit_err(
|
||||
self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
|
||||
if matches!(self.should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
|
||||
return Err(err);
|
||||
} else {
|
||||
self.should_emit.emit_err(err)
|
||||
};
|
||||
}
|
||||
|
||||
Ok(lit)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use rustc_ast::Safety;
|
||||
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::LintId;
|
||||
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::context::Stage;
|
||||
use crate::{AttributeParser, ShouldEmit};
|
||||
|
|
@ -15,19 +15,13 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
attr_path: &AttrPath,
|
||||
attr_span: Span,
|
||||
attr_safety: Safety,
|
||||
emit_lint: &mut impl FnMut(AttributeLint<S::Id>),
|
||||
target_id: S::Id,
|
||||
emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
|
||||
) {
|
||||
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name);
|
||||
if let Some(name) = name
|
||||
&& [sym::cfg_trace, sym::cfg_attr_trace].contains(&name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]);
|
||||
|
||||
// FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP`
|
||||
let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
|
||||
|
|
@ -87,16 +81,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
},
|
||||
);
|
||||
} else {
|
||||
emit_lint(AttributeLint {
|
||||
lint_id: LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
|
||||
id: target_id,
|
||||
span: path_span,
|
||||
kind: AttributeLintKind::UnsafeAttrOutsideUnsafe {
|
||||
emit_lint(
|
||||
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
|
||||
path_span,
|
||||
AttributeLintKind::UnsafeAttrOutsideUnsafe {
|
||||
attribute_name_span: path_span,
|
||||
sugg_spans: not_from_proc_macro
|
||||
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())),
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,14 @@ pub(crate) struct DocAliasStartEnd<'a> {
|
|||
pub attr_str: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_attr_not_crate_level)]
|
||||
pub(crate) struct DocAttrNotCrateLevel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_keyword_not_keyword)]
|
||||
#[help]
|
||||
|
|
@ -517,6 +525,10 @@ pub(crate) enum AttributeParseErrorReason<'a> {
|
|||
byte_string: Option<Span>,
|
||||
},
|
||||
ExpectedIntegerLiteral,
|
||||
ExpectedIntegerLiteralInRange {
|
||||
lower_bound: isize,
|
||||
upper_bound: isize,
|
||||
},
|
||||
ExpectedAtLeastOneArgument,
|
||||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
|
|
@ -588,6 +600,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
AttributeParseErrorReason::ExpectedIntegerLiteral => {
|
||||
diag.span_label(self.span, "expected an integer literal here");
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedIntegerLiteralInRange {
|
||||
lower_bound,
|
||||
upper_bound,
|
||||
} => {
|
||||
diag.span_label(
|
||||
self.span,
|
||||
format!(
|
||||
"expected an integer literal in the range of {lower_bound}..={upper_bound}"
|
||||
),
|
||||
);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedSingleArgument => {
|
||||
diag.span_label(self.span, "expected a single argument here");
|
||||
diag.code(E0805);
|
||||
|
|
|
|||
|
|
@ -10,16 +10,12 @@ use rustc_span::sym;
|
|||
use crate::AttributeParser;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::session_diagnostics::InvalidTarget;
|
||||
use crate::target_checking::Policy::Allow;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum AllowedTargets {
|
||||
AllowList(&'static [Policy]),
|
||||
AllowListWarnRest(&'static [Policy]),
|
||||
/// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`.
|
||||
/// For crate-level attributes we emit a specific set of lints to warn
|
||||
/// people about accidentally not using them on the crate.
|
||||
/// Only use this for attributes that are *exclusively* valid at the crate level.
|
||||
CrateLevel,
|
||||
}
|
||||
|
||||
pub(crate) enum AllowedResult {
|
||||
|
|
@ -53,7 +49,6 @@ impl AllowedTargets {
|
|||
AllowedResult::Warn
|
||||
}
|
||||
}
|
||||
AllowedTargets::CrateLevel => AllowedResult::Allowed,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +56,6 @@ impl AllowedTargets {
|
|||
match self {
|
||||
AllowedTargets::AllowList(list) => list,
|
||||
AllowedTargets::AllowListWarnRest(list) => list,
|
||||
AllowedTargets::CrateLevel => ALL_TARGETS,
|
||||
}
|
||||
.iter()
|
||||
.filter_map(|target| match target {
|
||||
|
|
@ -95,7 +89,12 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
target: Target,
|
||||
cx: &mut AcceptContext<'_, 'sess, S>,
|
||||
) {
|
||||
Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx);
|
||||
// For crate-level attributes we emit a specific set of lints to warn
|
||||
// people about accidentally not using them on the crate.
|
||||
if let &AllowedTargets::AllowList(&[Allow(Target::Crate)]) = allowed_targets {
|
||||
Self::check_crate_level(target, cx);
|
||||
return;
|
||||
}
|
||||
|
||||
match allowed_targets.is_allowed(target) {
|
||||
AllowedResult::Allowed => {}
|
||||
|
|
@ -104,7 +103,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features);
|
||||
let name = cx.attr_path.clone();
|
||||
|
||||
let lint = if name.segments[0].name == sym::deprecated
|
||||
let lint = if name.segments[0] == sym::deprecated
|
||||
&& ![
|
||||
Target::Closure,
|
||||
Target::Expression,
|
||||
|
|
@ -149,18 +148,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_type(
|
||||
crate_level: bool,
|
||||
target: Target,
|
||||
cx: &mut AcceptContext<'_, 'sess, S>,
|
||||
) {
|
||||
let is_crate_root = S::id_is_crate_root(cx.target_id);
|
||||
|
||||
if is_crate_root {
|
||||
return;
|
||||
}
|
||||
|
||||
if !crate_level {
|
||||
pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) {
|
||||
if target == Target::Crate {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -310,5 +299,29 @@ pub(crate) const ALL_TARGETS: &'static [Policy] = {
|
|||
Allow(Target::Crate),
|
||||
Allow(Target::Delegation { mac: false }),
|
||||
Allow(Target::Delegation { mac: true }),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Const,
|
||||
has_default: false,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Const,
|
||||
has_default: true,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Lifetime,
|
||||
has_default: false,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Lifetime,
|
||||
has_default: true,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Type,
|
||||
has_default: false,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Type,
|
||||
has_default: true,
|
||||
}),
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
|||
return;
|
||||
}
|
||||
|
||||
let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
|
||||
|
||||
// Check input tokens for built-in and key-value attributes.
|
||||
match builtin_attr_info {
|
||||
|
|
@ -48,7 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
|||
}
|
||||
_ => {
|
||||
let attr_item = attr.get_normal_item();
|
||||
if let AttrArgs::Eq { .. } = attr_item.args {
|
||||
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
|
||||
// All key-value attributes are restricted to meta-item syntax.
|
||||
match parse_meta(psess, attr) {
|
||||
Ok(_) => {}
|
||||
|
|
@ -67,7 +67,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
|
|||
unsafety: item.unsafety,
|
||||
span: attr.span,
|
||||
path: item.path.clone(),
|
||||
kind: match &item.args {
|
||||
kind: match &item.args.unparsed_ref().unwrap() {
|
||||
AttrArgs::Empty => MetaItemKind::Word,
|
||||
AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => {
|
||||
check_meta_bad_delim(psess, *dspan, *delim);
|
||||
|
|
|
|||
|
|
@ -253,19 +253,52 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let region = region.as_var();
|
||||
|
||||
let borrow = BorrowData {
|
||||
let borrow = |activation_location| BorrowData {
|
||||
kind,
|
||||
region,
|
||||
reserve_location: location,
|
||||
activation_location: TwoPhaseActivation::NotTwoPhase,
|
||||
activation_location,
|
||||
borrowed_place,
|
||||
assigned_place: *assigned_place,
|
||||
};
|
||||
let (idx, _) = self.location_map.insert_full(location, borrow);
|
||||
let idx = BorrowIndex::from(idx);
|
||||
|
||||
self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx);
|
||||
let idx = if !kind.is_two_phase_borrow() {
|
||||
debug!(" -> {:?}", location);
|
||||
let (idx, _) = self
|
||||
.location_map
|
||||
.insert_full(location, borrow(TwoPhaseActivation::NotTwoPhase));
|
||||
BorrowIndex::from(idx)
|
||||
} else {
|
||||
// When we encounter a 2-phase borrow statement, it will always
|
||||
// be assigning into a temporary TEMP:
|
||||
//
|
||||
// TEMP = &foo
|
||||
//
|
||||
// so extract `temp`.
|
||||
let Some(temp) = assigned_place.as_local() else {
|
||||
span_bug!(
|
||||
self.body.source_info(location).span,
|
||||
"expected 2-phase borrow to assign to a local, not `{:?}`",
|
||||
assigned_place,
|
||||
);
|
||||
};
|
||||
|
||||
// Consider the borrow not activated to start. When we find an activation, we'll update
|
||||
// this field.
|
||||
let (idx, _) = self
|
||||
.location_map
|
||||
.insert_full(location, borrow(TwoPhaseActivation::NotActivated));
|
||||
let idx = BorrowIndex::from(idx);
|
||||
|
||||
// Insert `temp` into the list of pending activations. From
|
||||
// now on, we'll be on the lookout for a use of it. Note that
|
||||
// we are guaranteed that this use will come after the
|
||||
// assignment.
|
||||
let prev = self.pending_activations.insert(temp, idx);
|
||||
assert_eq!(prev, None, "temporary associated with multiple two phase borrows");
|
||||
|
||||
idx
|
||||
};
|
||||
|
||||
self.local_map.entry(borrowed_place.local).or_default().insert(idx);
|
||||
}
|
||||
|
|
@ -334,62 +367,3 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
|
|||
self.super_rvalue(rvalue, location)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
|
||||
/// If this is a two-phase borrow, then we will record it
|
||||
/// as "pending" until we find the activating use.
|
||||
fn insert_as_pending_if_two_phase(
|
||||
&mut self,
|
||||
start_location: Location,
|
||||
assigned_place: &mir::Place<'tcx>,
|
||||
kind: mir::BorrowKind,
|
||||
borrow_index: BorrowIndex,
|
||||
) {
|
||||
debug!(
|
||||
"Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",
|
||||
start_location, assigned_place, borrow_index,
|
||||
);
|
||||
|
||||
if !kind.allows_two_phase_borrow() {
|
||||
debug!(" -> {:?}", start_location);
|
||||
return;
|
||||
}
|
||||
|
||||
// When we encounter a 2-phase borrow statement, it will always
|
||||
// be assigning into a temporary TEMP:
|
||||
//
|
||||
// TEMP = &foo
|
||||
//
|
||||
// so extract `temp`.
|
||||
let Some(temp) = assigned_place.as_local() else {
|
||||
span_bug!(
|
||||
self.body.source_info(start_location).span,
|
||||
"expected 2-phase borrow to assign to a local, not `{:?}`",
|
||||
assigned_place,
|
||||
);
|
||||
};
|
||||
|
||||
// Consider the borrow not activated to start. When we find an activation, we'll update
|
||||
// this field.
|
||||
{
|
||||
let borrow_data = &mut self.location_map[borrow_index.as_usize()];
|
||||
borrow_data.activation_location = TwoPhaseActivation::NotActivated;
|
||||
}
|
||||
|
||||
// Insert `temp` into the list of pending activations. From
|
||||
// now on, we'll be on the lookout for a use of it. Note that
|
||||
// we are guaranteed that this use will come after the
|
||||
// assignment.
|
||||
let old_value = self.pending_activations.insert(temp, borrow_index);
|
||||
if let Some(old_index) = old_value {
|
||||
span_bug!(
|
||||
self.body.source_info(start_location).span,
|
||||
"found already pending activation for temp: {:?} \
|
||||
at borrow_index: {:?} with associated data {:?}",
|
||||
temp,
|
||||
old_index,
|
||||
self.location_map[old_index.as_usize()]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
// ignore-tidy-filelength
|
||||
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
//! Print diagnostics to explain why values are borrowed.
|
||||
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
|
|||
|
|
@ -162,8 +162,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
|
||||
if count > 10 {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||
}
|
||||
self.buffer_error(diag);
|
||||
|
|
@ -236,7 +234,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// LL | for (key, value) in dict {
|
||||
/// | ^^^^
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
pub(super) fn add_moved_or_invoked_closure_note(
|
||||
&self,
|
||||
location: Location,
|
||||
|
|
@ -820,7 +817,6 @@ impl UseSpans<'_> {
|
|||
}
|
||||
|
||||
/// Add a span label to the arguments of the closure, if it exists.
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
|
||||
if let UseSpans::ClosureUse { args_span, .. } = self {
|
||||
err.subdiagnostic(f(args_span));
|
||||
|
|
@ -829,7 +825,6 @@ impl UseSpans<'_> {
|
|||
|
||||
/// Add a span label to the use of the captured variable, if it exists.
|
||||
/// only adds label to the `path_span`
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn var_path_only_subdiag(
|
||||
self,
|
||||
err: &mut Diag<'_>,
|
||||
|
|
@ -861,7 +856,6 @@ impl UseSpans<'_> {
|
|||
}
|
||||
|
||||
/// Add a subdiagnostic to the use of the captured variable, if it exists.
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn var_subdiag(
|
||||
self,
|
||||
err: &mut Diag<'_>,
|
||||
|
|
@ -1225,8 +1219,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.borrow_spans(span, borrow.reserve_location)
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn explain_captures(
|
||||
&mut self,
|
||||
err: &mut Diag<'infcx>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
use either::Either;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use either::Either;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
|
||||
//! outlives constraints.
|
||||
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
|
|
|
|||
|
|
@ -196,7 +196,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// For generic associated types (GATs) which implied 'static requirement
|
||||
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait
|
||||
// and the span which bounded to the trait for adding 'static lifetime suggestion
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
fn suggest_static_lifetime_for_gat_from_hrtb(
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
|
|
@ -421,9 +420,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// ```
|
||||
///
|
||||
/// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub(crate) fn report_region_error(
|
||||
&mut self,
|
||||
fr: RegionVid,
|
||||
|
|
@ -577,7 +573,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// executing...
|
||||
/// = note: ...therefore, returned references to captured variables will escape the closure
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
fn report_fnmut_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo<'tcx>,
|
||||
|
|
@ -686,18 +681,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
|
||||
|
||||
if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.span_label(
|
||||
outlived_fr_span,
|
||||
format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
|
||||
diag.span_label(
|
||||
fr_span,
|
||||
|
|
@ -732,9 +721,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
|
||||
outlived_fr_region_name.highlight_region_name(&mut diag);
|
||||
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!(
|
||||
|
|
@ -766,7 +752,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
|
||||
/// | is returning data with lifetime `'b`
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
|
||||
let ErrorConstraintInfo { fr, outlived_fr, span, category, .. } = errci;
|
||||
|
||||
|
|
@ -824,8 +809,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn add_static_impl_trait_suggestion(
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
|
|
@ -966,7 +949,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[instrument(skip(self, err), level = "debug")]
|
||||
fn suggest_constrain_dyn_trait_in_impl(
|
||||
&self,
|
||||
|
|
@ -1032,7 +1014,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
/// When encountering a lifetime error caused by the return type of a closure, check the
|
||||
/// corresponding trait bound and see if dereferencing the closure return value would satisfy
|
||||
/// them. If so, we produce a structured suggestion.
|
||||
|
|
@ -1160,7 +1141,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
|
||||
let body = self.infcx.tcx.hir_body_owned_by(self.mir_def_id());
|
||||
let expr = &body.value.peel_blocks();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::fmt::{self, Display};
|
||||
use std::iter;
|
||||
|
||||
|
|
|
|||
|
|
@ -1301,7 +1301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
(Read(kind), BorrowKind::Mut { .. }) => {
|
||||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(this.dominators(), borrow, location) {
|
||||
assert!(borrow.kind.allows_two_phase_borrow());
|
||||
assert!(borrow.kind.is_two_phase_borrow());
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
|
|
@ -1464,7 +1464,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if bk.allows_two_phase_borrow() {
|
||||
if bk.is_two_phase_borrow() {
|
||||
(Deep, Reservation(wk))
|
||||
} else {
|
||||
(Deep, Write(wk))
|
||||
|
|
|
|||
|
|
@ -287,8 +287,6 @@ pub(crate) fn emit_nll_mir<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub(super) fn dump_annotation<'tcx, 'infcx>(
|
||||
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if bk.allows_two_phase_borrow() {
|
||||
if bk.is_two_phase_borrow() {
|
||||
(Deep, Reservation(wk))
|
||||
} else {
|
||||
(Deep, Write(wk))
|
||||
|
|
@ -384,7 +384,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(this.dominators, borrow, location) {
|
||||
// If the borrow isn't active yet, reads don't invalidate it
|
||||
assert!(borrow.kind.allows_two_phase_borrow());
|
||||
assert!(borrow.kind.is_two_phase_borrow());
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ pub(super) fn convert_typeck_constraints<'tcx>(
|
|||
{
|
||||
localize_statement_constraint(
|
||||
tcx,
|
||||
body,
|
||||
stmt,
|
||||
&outlives_constraint,
|
||||
point,
|
||||
|
|
@ -74,7 +73,6 @@ pub(super) fn convert_typeck_constraints<'tcx>(
|
|||
/// needed CFG `from`-`to` intra-block nodes.
|
||||
fn localize_statement_constraint<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
stmt: &Statement<'tcx>,
|
||||
outlives_constraint: &OutlivesConstraint<'tcx>,
|
||||
current_point: PointIndex,
|
||||
|
|
@ -114,28 +112,22 @@ fn localize_statement_constraint<'tcx>(
|
|||
},
|
||||
"there should be no common regions between the LHS and RHS of an assignment"
|
||||
);
|
||||
|
||||
let lhs_ty = body.local_decls[lhs.local].ty;
|
||||
let successor_point = current_point;
|
||||
compute_constraint_direction(
|
||||
tcx,
|
||||
outlives_constraint,
|
||||
&lhs_ty,
|
||||
current_point,
|
||||
successor_point,
|
||||
universal_regions,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
// For the other cases, we localize an outlives constraint to where it arises.
|
||||
LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
}
|
||||
// Assignments should be the only statement that can both generate constraints that
|
||||
// apply on entry (specific to the RHS place) *and* others that only apply on exit (the
|
||||
// subset of RHS regions that actually flow into the LHS): i.e., where midpoints would
|
||||
// be used to ensure the former happen before the latter, within the same MIR Location.
|
||||
}
|
||||
}
|
||||
|
||||
// We generally localize an outlives constraint to where it arises.
|
||||
LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
}
|
||||
}
|
||||
|
||||
/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the
|
||||
|
|
@ -150,14 +142,12 @@ fn localize_terminator_constraint<'tcx>(
|
|||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> LocalizedOutlivesConstraint {
|
||||
// FIXME: check if other terminators need the same handling as `Call`s, in particular
|
||||
// Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some
|
||||
// coroutine tests, and that may be why.
|
||||
// Assert/Yield/Drop.
|
||||
match &terminator.kind {
|
||||
// FIXME: also handle diverging calls.
|
||||
TerminatorKind::Call { destination, target: Some(target), .. } => {
|
||||
// Calls are similar to assignments, and thus follow the same pattern. If there is a
|
||||
// target for the call we also relate what flows into the destination here to entry to
|
||||
// that successor.
|
||||
// If there is a target for the call we also relate what flows into the destination here
|
||||
// to entry to that successor.
|
||||
let destination_ty = destination.ty(&body.local_decls, tcx);
|
||||
let successor_location = Location { block: *target, statement_index: 0 };
|
||||
let successor_point = liveness.point_from_location(successor_location);
|
||||
|
|
|
|||
|
|
@ -229,8 +229,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
// not ready to process them yet.
|
||||
// - Then compute the implied bounds. This will adjust
|
||||
// the `region_bound_pairs` and so forth.
|
||||
// - After this is done, we'll process the constraints, once
|
||||
// the `relations` is built.
|
||||
// - After this is done, we'll register the constraints in
|
||||
// the `BorrowckInferCtxt`. Checking these constraints is
|
||||
// handled later by actual borrow checking.
|
||||
let mut normalized_inputs_and_output =
|
||||
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
|
||||
for ty in unnormalized_input_output_tys {
|
||||
|
|
@ -254,6 +255,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
constraints.push(c)
|
||||
}
|
||||
|
||||
// Currently `implied_outlives_bounds` will normalize the provided
|
||||
// `Ty`, despite this it's still important to normalize the ty ourselves
|
||||
// as normalization may introduce new region variables (#136547).
|
||||
//
|
||||
// If we do not add implied bounds for the type involving these new
|
||||
// region variables then we'll wind up with the normalized form of
|
||||
// the signature having not-wf types due to unsatisfied region
|
||||
// constraints.
|
||||
//
|
||||
// Note: we need this in examples like
|
||||
// ```
|
||||
// trait Foo {
|
||||
|
|
@ -262,7 +272,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
// }
|
||||
// impl Foo for () {
|
||||
// type Bar = ();
|
||||
// fn foo(&self) ->&() {}
|
||||
// fn foo(&self) -> &() {}
|
||||
// }
|
||||
// ```
|
||||
// Both &Self::Bar and &() are WF
|
||||
|
|
@ -277,6 +287,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
}
|
||||
|
||||
// Add implied bounds from impl header.
|
||||
//
|
||||
// We don't use `assumed_wf_types` to source the entire set of implied bounds for
|
||||
// a few reasons:
|
||||
// - `DefiningTy` for closure has the `&'env Self` type while `assumed_wf_types` doesn't
|
||||
// - We compute implied bounds from the unnormalized types in the `DefiningTy` but do not
|
||||
// do so for types in impl headers
|
||||
// - We must compute the normalized signature and then compute implied bounds from that
|
||||
// in order to connect any unconstrained region vars created during normalization to
|
||||
// the types of the locals corresponding to the inputs and outputs of the item. (#136547)
|
||||
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
|
||||
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
|
||||
let result: Result<_, ErrorGuaranteed> = param_env
|
||||
|
|
@ -352,10 +371,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
known_type_outlives_obligations.push(outlives);
|
||||
}
|
||||
|
||||
/// Update the type of a single local, which should represent
|
||||
/// either the return type of the MIR or one of its arguments. At
|
||||
/// the same time, compute and add any implied bounds that come
|
||||
/// from this local.
|
||||
/// Compute and add any implied bounds that come from a given type.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn add_implied_bounds(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@
|
|||
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
|
||||
//! contain revealed `impl Trait` values).
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use itertools::Itertools;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
|
||||
use rustc_middle::mir::*;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use rustc_infer::infer::{
|
|||
BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin,
|
||||
};
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
|
|
@ -28,7 +29,6 @@ use rustc_middle::ty::{
|
|||
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
|
||||
GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
|
|
@ -387,18 +387,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
#[instrument(skip(self), level = "debug")]
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
debug!(?self.user_type_annotations);
|
||||
let tcx = self.tcx();
|
||||
for user_annotation in self.user_type_annotations {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let annotation = self.instantiate_canonical(span, user_ty);
|
||||
if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind
|
||||
&& let DefKind::InlineConst = tcx.def_kind(def)
|
||||
{
|
||||
assert!(annotation.bounds.is_empty());
|
||||
self.check_inline_const(inferred_ty, def.expect_local(), args, span);
|
||||
} else {
|
||||
self.ascribe_user_type(inferred_ty, annotation, span);
|
||||
}
|
||||
self.ascribe_user_type(inferred_ty, annotation, span);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -560,36 +552,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.constraints.liveness_constraints.add_location(region, location);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_inline_const(
|
||||
&mut self,
|
||||
inferred_ty: Ty<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
args: UserArgs<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
assert!(args.user_self_ty.is_none());
|
||||
let tcx = self.tcx();
|
||||
let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
|
||||
if let Err(terr) =
|
||||
self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
|
||||
{
|
||||
span_bug!(
|
||||
span,
|
||||
"bad inline const pattern: ({:?} = {:?}) {:?}",
|
||||
const_ty,
|
||||
inferred_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
let args = self.infcx.resolve_vars_if_possible(args.args);
|
||||
let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
|
||||
self.normalize_and_prove_instantiated_predicates(
|
||||
def_id.to_def_id(),
|
||||
predicates,
|
||||
Locations::All(span),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
|
|
@ -1581,12 +1543,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
.unwrap();
|
||||
}
|
||||
(None, None) => {
|
||||
// `struct_tail` returns regions which haven't been mapped
|
||||
// to nll vars yet so we do it here as `outlives_constraints`
|
||||
// expects nll vars.
|
||||
let src_lt = self.universal_regions.to_region_vid(src_lt);
|
||||
let dst_lt = self.universal_regions.to_region_vid(dst_lt);
|
||||
|
||||
// The principalless (no non-auto traits) case:
|
||||
// You can only cast `dyn Send + 'long` to `dyn Send + 'short`.
|
||||
self.constraints.outlives_constraints.push(
|
||||
OutlivesConstraint {
|
||||
sup: src_lt.as_var(),
|
||||
sub: dst_lt.as_var(),
|
||||
sup: src_lt,
|
||||
sub: dst_lt,
|
||||
locations: location.to_locations(),
|
||||
span: location.to_locations().span(self.body),
|
||||
category: ConstraintCategory::Cast {
|
||||
|
|
@ -1725,12 +1693,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
let def_id = uv.def;
|
||||
if tcx.def_kind(def_id) == DefKind::InlineConst {
|
||||
let def_id = def_id.expect_local();
|
||||
let predicates = self.prove_closure_bounds(
|
||||
tcx,
|
||||
def_id,
|
||||
uv.args,
|
||||
location.to_locations(),
|
||||
);
|
||||
let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
|
||||
self.normalize_and_prove_instantiated_predicates(
|
||||
def_id.to_def_id(),
|
||||
predicates,
|
||||
|
|
@ -2513,15 +2476,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// clauses on the struct.
|
||||
AggregateKind::Closure(def_id, args)
|
||||
| AggregateKind::CoroutineClosure(def_id, args)
|
||||
| AggregateKind::Coroutine(def_id, args) => (
|
||||
def_id,
|
||||
self.prove_closure_bounds(
|
||||
tcx,
|
||||
def_id.expect_local(),
|
||||
args,
|
||||
location.to_locations(),
|
||||
),
|
||||
),
|
||||
| AggregateKind::Coroutine(def_id, args) => {
|
||||
(def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
|
||||
}
|
||||
|
||||
AggregateKind::Array(_) | AggregateKind::Tuple | AggregateKind::RawPtr(..) => {
|
||||
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
|
||||
|
|
@ -2540,12 +2497,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
locations: Locations,
|
||||
location: Location,
|
||||
) -> ty::InstantiatedPredicates<'tcx> {
|
||||
let root_def_id = self.root_cx.root_def_id();
|
||||
// We will have to handle propagated closure requirements for this closure,
|
||||
// but need to defer this until the nested body has been fully borrow checked.
|
||||
self.deferred_closure_requirements.push((def_id, args, locations));
|
||||
self.deferred_closure_requirements.push((def_id, args, location.to_locations()));
|
||||
|
||||
// Equate closure args to regions inherited from `root_def_id`. Fixes #98589.
|
||||
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id);
|
||||
|
|
@ -2569,7 +2526,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
if let Err(_) = self.eq_args(
|
||||
typeck_root_args,
|
||||
parent_args,
|
||||
locations,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
span_mirbug!(
|
||||
|
|
|
|||
|
|
@ -11,9 +11,6 @@
|
|||
//! The code in this file doesn't *do anything* with those results; it
|
||||
//! just returns them for other code to use.
|
||||
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::iter;
|
||||
|
||||
|
|
@ -207,10 +204,10 @@ struct UniversalRegionIndices<'tcx> {
|
|||
/// `ty::Region` to the internal `RegionVid` we are using. This is
|
||||
/// used because trait matching and type-checking will feed us
|
||||
/// region constraints that reference those regions and we need to
|
||||
/// be able to map them to our internal `RegionVid`. This is
|
||||
/// basically equivalent to an `GenericArgs`, except that it also
|
||||
/// contains an entry for `ReStatic` -- it might be nice to just
|
||||
/// use an args, and then handle `ReStatic` another way.
|
||||
/// be able to map them to our internal `RegionVid`.
|
||||
///
|
||||
/// This is similar to just using `GenericArgs`, except that it contains
|
||||
/// an entry for `'static`, and also late bound parameters in scope.
|
||||
indices: FxIndexMap<ty::Region<'tcx>, RegionVid>,
|
||||
|
||||
/// The vid assigned to `'static`. Used only for diagnostics.
|
||||
|
|
@ -543,38 +540,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
&indices,
|
||||
);
|
||||
|
||||
let (unnormalized_output_ty, mut unnormalized_input_tys) =
|
||||
let (unnormalized_output_ty, unnormalized_input_tys) =
|
||||
inputs_and_output.split_last().unwrap();
|
||||
|
||||
// C-variadic fns also have a `VaList` input that's not listed in the signature
|
||||
// (as it's created inside the body itself, not passed in from outside).
|
||||
if let DefiningTy::FnDef(def_id, _) = defining_ty {
|
||||
if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
|
||||
let va_list_did = self
|
||||
.infcx
|
||||
.tcx
|
||||
.require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def));
|
||||
|
||||
let reg_vid = self
|
||||
.infcx
|
||||
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
|
||||
RegionCtxt::Free(sym::c_dash_variadic)
|
||||
})
|
||||
.as_var();
|
||||
|
||||
let region = ty::Region::new_var(self.infcx.tcx, reg_vid);
|
||||
let va_list_ty = self
|
||||
.infcx
|
||||
.tcx
|
||||
.type_of(va_list_did)
|
||||
.instantiate(self.infcx.tcx, &[region.into()]);
|
||||
|
||||
unnormalized_input_tys = self.infcx.tcx.mk_type_list_from_iter(
|
||||
unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let fr_fn_body = self
|
||||
.infcx
|
||||
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
|
||||
|
|
@ -816,7 +784,40 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
DefiningTy::FnDef(def_id, _) => {
|
||||
let sig = tcx.fn_sig(def_id).instantiate_identity();
|
||||
let sig = indices.fold_to_region_vids(tcx, sig);
|
||||
sig.inputs_and_output()
|
||||
let inputs_and_output = sig.inputs_and_output();
|
||||
|
||||
// C-variadic fns also have a `VaList` input that's not listed in the signature
|
||||
// (as it's created inside the body itself, not passed in from outside).
|
||||
if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
|
||||
let va_list_did = self
|
||||
.infcx
|
||||
.tcx
|
||||
.require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def));
|
||||
|
||||
let reg_vid = self
|
||||
.infcx
|
||||
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
|
||||
RegionCtxt::Free(sym::c_dash_variadic)
|
||||
})
|
||||
.as_var();
|
||||
|
||||
let region = ty::Region::new_var(self.infcx.tcx, reg_vid);
|
||||
let va_list_ty = self
|
||||
.infcx
|
||||
.tcx
|
||||
.type_of(va_list_did)
|
||||
.instantiate(self.infcx.tcx, &[region.into()]);
|
||||
|
||||
// The signature needs to follow the order [input_tys, va_list_ty, output_ty]
|
||||
return inputs_and_output.map_bound(|tys| {
|
||||
let (output_ty, input_tys) = tys.split_last().unwrap();
|
||||
tcx.mk_type_list_from_iter(
|
||||
input_tys.iter().copied().chain([va_list_ty, *output_ty]),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
inputs_and_output
|
||||
}
|
||||
|
||||
DefiningTy::Const(def_id, _) => {
|
||||
|
|
|
|||
|
|
@ -151,9 +151,9 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept
|
|||
|
||||
builtin_macros_duplicate_macro_attribute = duplicated attribute
|
||||
|
||||
builtin_macros_eii_extern_target_expected_list = `#[eii_extern_target(...)]` expects a list of one or two elements
|
||||
builtin_macros_eii_extern_target_expected_macro = `#[eii_extern_target(...)]` is only valid on macros
|
||||
builtin_macros_eii_extern_target_expected_unsafe = expected this argument to be "unsafe"
|
||||
builtin_macros_eii_declaration_expected_list = `#[eii_declaration(...)]` expects a list of one or two elements
|
||||
builtin_macros_eii_declaration_expected_macro = `#[eii_declaration(...)]` is only valid on macros
|
||||
builtin_macros_eii_declaration_expected_unsafe = expected this argument to be "unsafe"
|
||||
.note = the second argument is optional
|
||||
|
||||
builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
|
||||
|
|
@ -161,6 +161,8 @@ builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
|
|||
|
||||
builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions
|
||||
builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]`
|
||||
builtin_macros_eii_shared_macro_in_statement_position = `#[{$name}]` can only be used on functions inside a module
|
||||
.label = `#[{$name}]` is used on this item, which is part of another item's local scope
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
|
||||
|
|
@ -182,6 +184,8 @@ builtin_macros_expected_other = expected operand, {$is_inline_asm ->
|
|||
|
||||
builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently
|
||||
|
||||
builtin_macros_format_add_missing_colon = add a colon before the format specifier
|
||||
|
||||
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
|
||||
.label1 = previously here
|
||||
.label2 = duplicate argument
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ mod llvm_enzyme {
|
|||
let inline_item = ast::AttrItem {
|
||||
unsafety: ast::Safety::Default,
|
||||
path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)),
|
||||
args: ast::AttrArgs::Delimited(never_arg),
|
||||
args: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)),
|
||||
tokens: None,
|
||||
};
|
||||
let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None });
|
||||
|
|
@ -421,11 +421,13 @@ mod llvm_enzyme {
|
|||
}
|
||||
};
|
||||
// Now update for d_fn
|
||||
rustc_ad_attr.item.args = rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs {
|
||||
dspan: DelimSpan::dummy(),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: ts,
|
||||
});
|
||||
rustc_ad_attr.item.args = rustc_ast::ast::AttrItemKind::Unparsed(
|
||||
rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs {
|
||||
dspan: DelimSpan::dummy(),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: ts,
|
||||
}),
|
||||
);
|
||||
|
||||
let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
|
||||
let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ use rustc_attr_parsing::{
|
|||
AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
|
||||
};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_hir::{AttrPath, Target};
|
||||
use rustc_parse::exp;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span};
|
||||
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||
|
||||
use crate::errors;
|
||||
|
||||
|
|
@ -40,20 +40,25 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
|
|||
return Err(cx.dcx().emit_err(errors::RequiresCfgPattern { span }));
|
||||
}
|
||||
|
||||
let meta = MetaItemOrLitParser::parse_single(&mut parser, ShouldEmit::ErrorsAndLints)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
&mut parser,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
cx.sess,
|
||||
span,
|
||||
span,
|
||||
AttrStyle::Inner,
|
||||
AttrPath { segments: vec![Ident::from_str("cfg")].into_boxed_slice(), span },
|
||||
AttrPath { segments: vec![sym::cfg].into_boxed_slice(), span },
|
||||
None,
|
||||
ParsedDescription::Macro,
|
||||
span,
|
||||
cx.current_expansion.lint_node_id,
|
||||
// Doesn't matter what the target actually is here.
|
||||
Target::Crate,
|
||||
Some(cx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&CFG_TEMPLATE,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
|
|||
use rustc_expand::config::StripUnconfigured;
|
||||
use rustc_expand::configure;
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{Span, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -47,10 +47,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
|||
impl<'ast> visit::Visitor<'ast> for CfgFinder {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> {
|
||||
if attr
|
||||
.ident()
|
||||
.is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
|
||||
{
|
||||
if attr.name().is_some_and(|name| name == sym::cfg || name == sym::cfg_attr) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
|
|
@ -113,7 +110,8 @@ impl CfgEval<'_> {
|
|||
let res: PResult<'_, Annotatable> = try {
|
||||
match annotatable {
|
||||
Annotatable::Item(_) => {
|
||||
let item = parser.parse_item(ForceCollect::Yes)?.unwrap();
|
||||
let item =
|
||||
parser.parse_item(ForceCollect::Yes, AllowConstBlockItems::Yes)?.unwrap();
|
||||
Annotatable::Item(self.flat_map_item(item).pop().unwrap())
|
||||
}
|
||||
Annotatable::AssocItem(_, ctxt) => {
|
||||
|
|
|
|||
|
|
@ -19,9 +19,8 @@ pub(crate) fn expand_compile_error<'cx>(
|
|||
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
|
||||
};
|
||||
|
||||
#[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")]
|
||||
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
|
||||
let guar = cx.dcx().span_err(sp, var.to_string());
|
||||
cx.resolver.mark_scope_with_compile_error(cx.current_expansion.lint_node_id);
|
||||
|
||||
ExpandResult::Ready(DummyResult::any(sp, guar))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -807,24 +807,29 @@ impl<'a> TraitDef<'a> {
|
|||
rustc_ast::AttrItem {
|
||||
unsafety: Safety::Default,
|
||||
path: rustc_const_unstable,
|
||||
args: AttrArgs::Delimited(DelimArgs {
|
||||
dspan: DelimSpan::from_single(self.span),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: [
|
||||
TokenKind::Ident(sym::feature, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const, None),
|
||||
TokenKind::Comma,
|
||||
TokenKind::Ident(sym::issue, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|kind| {
|
||||
TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone)
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
args: rustc_ast::ast::AttrItemKind::Unparsed(AttrArgs::Delimited(
|
||||
DelimArgs {
|
||||
dspan: DelimSpan::from_single(self.span),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: [
|
||||
TokenKind::Ident(sym::feature, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const, None),
|
||||
TokenKind::Comma,
|
||||
TokenKind::Ident(sym::issue, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|kind| {
|
||||
TokenTree::Token(
|
||||
Token { kind, span: self.span },
|
||||
Spacing::Alone,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
)),
|
||||
tokens: None,
|
||||
},
|
||||
self.span,
|
||||
|
|
@ -981,16 +986,6 @@ impl<'a> MethodDef<'a> {
|
|||
f(cx, span, &substructure)
|
||||
}
|
||||
|
||||
fn get_ret_ty(
|
||||
&self,
|
||||
cx: &ExtCtxt<'_>,
|
||||
trait_: &TraitDef<'_>,
|
||||
generics: &Generics,
|
||||
type_ident: Ident,
|
||||
) -> Box<ast::Ty> {
|
||||
self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
|
||||
}
|
||||
|
||||
fn is_static(&self) -> bool {
|
||||
!self.explicit_self
|
||||
}
|
||||
|
|
@ -1063,10 +1058,14 @@ impl<'a> MethodDef<'a> {
|
|||
self_arg.into_iter().chain(nonself_args).collect()
|
||||
};
|
||||
|
||||
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
|
||||
let ret_type = if let Ty::Unit = &self.ret_ty {
|
||||
ast::FnRetTy::Default(span)
|
||||
} else {
|
||||
ast::FnRetTy::Ty(self.ret_ty.to_ty(cx, span, type_ident, generics))
|
||||
};
|
||||
|
||||
let method_ident = Ident::new(self.name, span);
|
||||
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
||||
let fn_decl = cx.fn_decl(args, ret_type);
|
||||
let body_block = body.into_block(cx, span);
|
||||
|
||||
let trait_lo_sp = span.shrink_to_lo();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use rustc_ast::token::{Delimiter, TokenKind};
|
||||
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::{
|
||||
Attribute, DUMMY_NODE_ID, EiiExternTarget, EiiImpl, ItemKind, MetaItem, Path, Stmt, StmtKind,
|
||||
Visibility, ast,
|
||||
Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast,
|
||||
};
|
||||
use rustc_ast_pretty::pprust::path_to_string;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
|
|
@ -12,6 +11,7 @@ use thin_vec::{ThinVec, thin_vec};
|
|||
use crate::errors::{
|
||||
EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
|
||||
EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction,
|
||||
EiiSharedMacroInStatementPosition,
|
||||
};
|
||||
|
||||
/// ```rust
|
||||
|
|
@ -30,7 +30,7 @@ use crate::errors::{
|
|||
/// }
|
||||
///
|
||||
/// #[rustc_builtin_macro(eii_shared_macro)]
|
||||
/// #[eii_extern_target(panic_handler)]
|
||||
/// #[eii_declaration(panic_handler)]
|
||||
/// macro panic_handler() {}
|
||||
/// ```
|
||||
pub(crate) fn eii(
|
||||
|
|
@ -55,29 +55,29 @@ fn eii_(
|
|||
ecx: &mut ExtCtxt<'_>,
|
||||
eii_attr_span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
item: Annotatable,
|
||||
orig_item: Annotatable,
|
||||
impl_unsafe: bool,
|
||||
) -> Vec<Annotatable> {
|
||||
let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span);
|
||||
|
||||
let (item, wrap_item): (_, &dyn Fn(_) -> _) = if let Annotatable::Item(item) = item {
|
||||
(item, &Annotatable::Item)
|
||||
} else if let Annotatable::Stmt(ref stmt) = item
|
||||
let item = if let Annotatable::Item(item) = orig_item {
|
||||
item
|
||||
} else if let Annotatable::Stmt(ref stmt) = orig_item
|
||||
&& let StmtKind::Item(ref item) = stmt.kind
|
||||
&& let ItemKind::Fn(ref f) = item.kind
|
||||
{
|
||||
(item.clone(), &|item| {
|
||||
Annotatable::Stmt(Box::new(Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: StmtKind::Item(item),
|
||||
span: eii_attr_span,
|
||||
}))
|
||||
})
|
||||
ecx.dcx().emit_err(EiiSharedMacroInStatementPosition {
|
||||
span: eii_attr_span.to(item.span),
|
||||
name: path_to_string(&meta_item.path),
|
||||
item_span: f.ident.span,
|
||||
});
|
||||
return vec![orig_item];
|
||||
} else {
|
||||
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
|
||||
span: eii_attr_span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![item];
|
||||
return vec![orig_item];
|
||||
};
|
||||
|
||||
let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } =
|
||||
|
|
@ -87,7 +87,7 @@ fn eii_(
|
|||
span: eii_attr_span,
|
||||
name: path_to_string(&meta_item.path),
|
||||
});
|
||||
return vec![wrap_item(item)];
|
||||
return vec![Annotatable::Item(item)];
|
||||
};
|
||||
// only clone what we need
|
||||
let attrs = attrs.clone();
|
||||
|
|
@ -98,45 +98,49 @@ fn eii_(
|
|||
filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
|
||||
|
||||
let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else {
|
||||
return vec![wrap_item(item)];
|
||||
// we don't need to wrap in Annotatable::Stmt conditionally since
|
||||
// EII can't be used on items in statement position
|
||||
return vec![Annotatable::Item(item)];
|
||||
};
|
||||
|
||||
// span of the declaring item without attributes
|
||||
let item_span = func.sig.span;
|
||||
// span of the eii attribute and the item below it, i.e. the full declaration
|
||||
let decl_span = eii_attr_span.to(item_span);
|
||||
let foreign_item_name = func.ident;
|
||||
|
||||
let mut return_items = Vec::new();
|
||||
let mut module_items = Vec::new();
|
||||
|
||||
if func.body.is_some() {
|
||||
return_items.push(Box::new(generate_default_impl(
|
||||
module_items.push(generate_default_impl(
|
||||
ecx,
|
||||
&func,
|
||||
impl_unsafe,
|
||||
macro_name,
|
||||
eii_attr_span,
|
||||
item_span,
|
||||
)))
|
||||
foreign_item_name,
|
||||
))
|
||||
}
|
||||
|
||||
return_items.push(Box::new(generate_foreign_item(
|
||||
module_items.push(generate_foreign_item(
|
||||
ecx,
|
||||
eii_attr_span,
|
||||
item_span,
|
||||
func,
|
||||
vis,
|
||||
&attrs_from_decl,
|
||||
)));
|
||||
return_items.push(Box::new(generate_attribute_macro_to_implement(
|
||||
));
|
||||
module_items.push(generate_attribute_macro_to_implement(
|
||||
ecx,
|
||||
eii_attr_span,
|
||||
macro_name,
|
||||
foreign_item_name,
|
||||
impl_unsafe,
|
||||
decl_span,
|
||||
)));
|
||||
&attrs_from_decl,
|
||||
));
|
||||
|
||||
return_items.into_iter().map(wrap_item).collect()
|
||||
// we don't need to wrap in Annotatable::Stmt conditionally since
|
||||
// EII can't be used on items in statement position
|
||||
module_items.into_iter().map(Annotatable::Item).collect()
|
||||
}
|
||||
|
||||
/// Decide on the name of the macro that can be used to implement the EII.
|
||||
|
|
@ -187,12 +191,14 @@ fn filter_attrs_for_multiple_eii_attr(
|
|||
}
|
||||
|
||||
fn generate_default_impl(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
func: &ast::Fn,
|
||||
impl_unsafe: bool,
|
||||
macro_name: Ident,
|
||||
eii_attr_span: Span,
|
||||
item_span: Span,
|
||||
) -> ast::Item {
|
||||
foreign_item_name: Ident,
|
||||
) -> Box<ast::Item> {
|
||||
// FIXME: re-add some original attrs
|
||||
let attrs = ThinVec::new();
|
||||
|
||||
|
|
@ -208,62 +214,38 @@ fn generate_default_impl(
|
|||
},
|
||||
span: eii_attr_span,
|
||||
is_default: true,
|
||||
known_eii_macro_resolution: Some(ast::EiiDecl {
|
||||
foreign_item: ecx.path(
|
||||
foreign_item_name.span,
|
||||
// prefix self to explicitly escape the const block generated below
|
||||
// NOTE: this is why EIIs can't be used on statements
|
||||
vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name],
|
||||
),
|
||||
impl_unsafe,
|
||||
}),
|
||||
});
|
||||
|
||||
ast::Item {
|
||||
attrs: ThinVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: eii_attr_span,
|
||||
vis: ast::Visibility {
|
||||
span: eii_attr_span,
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None,
|
||||
},
|
||||
kind: ast::ItemKind::Const(Box::new(ast::ConstItem {
|
||||
ident: Ident { name: kw::Underscore, span: eii_attr_span },
|
||||
defaultness: ast::Defaultness::Final,
|
||||
generics: ast::Generics::default(),
|
||||
ty: Box::new(ast::Ty {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ast::TyKind::Tup(ThinVec::new()),
|
||||
span: eii_attr_span,
|
||||
tokens: None,
|
||||
}),
|
||||
rhs: Some(ast::ConstItemRhs::Body(Box::new(ast::Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::Block(
|
||||
Box::new(ast::Block {
|
||||
stmts: thin_vec![ast::Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ast::StmtKind::Item(Box::new(ast::Item {
|
||||
attrs,
|
||||
id: DUMMY_NODE_ID,
|
||||
span: item_span,
|
||||
vis: ast::Visibility {
|
||||
span: eii_attr_span,
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None
|
||||
},
|
||||
kind: ItemKind::Fn(Box::new(default_func)),
|
||||
tokens: None,
|
||||
})),
|
||||
span: eii_attr_span
|
||||
}],
|
||||
id: DUMMY_NODE_ID,
|
||||
rules: ast::BlockCheckMode::Default,
|
||||
span: eii_attr_span,
|
||||
tokens: None,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
span: eii_attr_span,
|
||||
attrs: ThinVec::new(),
|
||||
tokens: None,
|
||||
}))),
|
||||
define_opaque: None,
|
||||
})),
|
||||
tokens: None,
|
||||
}
|
||||
let anon_mod = |span: Span, stmts: ThinVec<ast::Stmt>| {
|
||||
let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new()));
|
||||
let underscore = Ident::new(kw::Underscore, item_span);
|
||||
ecx.item_const(
|
||||
span,
|
||||
underscore,
|
||||
unit,
|
||||
ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))),
|
||||
)
|
||||
};
|
||||
|
||||
// const _: () = {
|
||||
// <orig fn>
|
||||
// }
|
||||
anon_mod(
|
||||
item_span,
|
||||
thin_vec![ecx.stmt_item(
|
||||
item_span,
|
||||
ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func)))
|
||||
),],
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a foreign item, like
|
||||
|
|
@ -278,13 +260,13 @@ fn generate_foreign_item(
|
|||
mut func: ast::Fn,
|
||||
vis: Visibility,
|
||||
attrs_from_decl: &[Attribute],
|
||||
) -> ast::Item {
|
||||
) -> Box<ast::Item> {
|
||||
let mut foreign_item_attrs = ThinVec::new();
|
||||
foreign_item_attrs.extend_from_slice(attrs_from_decl);
|
||||
|
||||
// Add the rustc_eii_extern_item on the foreign item. Usually, foreign items are mangled.
|
||||
// Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled.
|
||||
// This attribute makes sure that we later know that this foreign item's symbol should not be.
|
||||
foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_extern_item, eii_attr_span));
|
||||
foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span));
|
||||
|
||||
let abi = match func.sig.header.ext {
|
||||
// extern "X" fn => extern "X" {}
|
||||
|
|
@ -310,16 +292,10 @@ fn generate_foreign_item(
|
|||
func.sig.header.safety = ast::Safety::Safe(func.sig.span);
|
||||
}
|
||||
|
||||
ast::Item {
|
||||
attrs: ast::AttrVec::default(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: eii_attr_span,
|
||||
vis: ast::Visibility {
|
||||
span: eii_attr_span,
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None,
|
||||
},
|
||||
kind: ast::ItemKind::ForeignMod(ast::ForeignMod {
|
||||
ecx.item(
|
||||
eii_attr_span,
|
||||
ThinVec::new(),
|
||||
ast::ItemKind::ForeignMod(ast::ForeignMod {
|
||||
extern_span: eii_attr_span,
|
||||
safety: ast::Safety::Unsafe(eii_attr_span),
|
||||
abi,
|
||||
|
|
@ -332,8 +308,7 @@ fn generate_foreign_item(
|
|||
tokens: None,
|
||||
})]),
|
||||
}),
|
||||
tokens: None,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate a stub macro (a bit like in core) that will roughly look like:
|
||||
|
|
@ -343,7 +318,7 @@ fn generate_foreign_item(
|
|||
/// // This attribute tells the compiler that
|
||||
/// #[builtin_macro(eii_shared_macro)]
|
||||
/// // the metadata to link this macro to the generated foreign item.
|
||||
/// #[eii_extern_target(<related_reign_item>)]
|
||||
/// #[eii_declaration(<related_foreign_item>)]
|
||||
/// macro macro_name { () => {} }
|
||||
/// ```
|
||||
fn generate_attribute_macro_to_implement(
|
||||
|
|
@ -352,14 +327,22 @@ fn generate_attribute_macro_to_implement(
|
|||
macro_name: Ident,
|
||||
foreign_item_name: Ident,
|
||||
impl_unsafe: bool,
|
||||
decl_span: Span,
|
||||
) -> ast::Item {
|
||||
attrs_from_decl: &[Attribute],
|
||||
) -> Box<ast::Item> {
|
||||
let mut macro_attrs = ThinVec::new();
|
||||
|
||||
// To avoid e.g. `error: attribute macro has missing stability attribute`
|
||||
// errors for eii's in std.
|
||||
macro_attrs.extend_from_slice(attrs_from_decl);
|
||||
|
||||
// Avoid "missing stability attribute" errors for eiis in std. See #146993.
|
||||
macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span));
|
||||
|
||||
// #[builtin_macro(eii_shared_macro)]
|
||||
macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span));
|
||||
|
||||
ast::Item {
|
||||
// cant use ecx methods here to construct item since we need it to be public
|
||||
Box::new(ast::Item {
|
||||
attrs: macro_attrs,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
|
|
@ -390,19 +373,18 @@ fn generate_attribute_macro_to_implement(
|
|||
]),
|
||||
}),
|
||||
macro_rules: false,
|
||||
// #[eii_extern_target(foreign_item_ident)]
|
||||
eii_extern_target: Some(ast::EiiExternTarget {
|
||||
extern_item_path: ast::Path::from_ident(foreign_item_name),
|
||||
// #[eii_declaration(foreign_item_ident)]
|
||||
eii_declaration: Some(ast::EiiDecl {
|
||||
foreign_item: ast::Path::from_ident(foreign_item_name),
|
||||
impl_unsafe,
|
||||
span: decl_span,
|
||||
}),
|
||||
},
|
||||
),
|
||||
tokens: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn eii_extern_target(
|
||||
pub(crate) fn eii_declaration(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
|
|
@ -451,7 +433,7 @@ pub(crate) fn eii_extern_target(
|
|||
false
|
||||
};
|
||||
|
||||
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span });
|
||||
d.eii_declaration = Some(EiiDecl { foreign_item: extern_item_path, impl_unsafe });
|
||||
|
||||
// Return the original item and the new methods.
|
||||
vec![item]
|
||||
|
|
@ -508,6 +490,7 @@ pub(crate) fn eii_shared_macro(
|
|||
impl_safety: meta_item.unsafety,
|
||||
span,
|
||||
is_default,
|
||||
known_eii_macro_resolution: None,
|
||||
});
|
||||
|
||||
vec![item]
|
||||
|
|
|
|||
|
|
@ -503,10 +503,6 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
|
|||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage {
|
||||
#[track_caller]
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
#[expect(
|
||||
rustc::untranslatable_diagnostic,
|
||||
reason = "cannot translate user-provided messages"
|
||||
)]
|
||||
let mut diag = Diag::new(dcx, level, self.msg_from_user.to_string());
|
||||
diag.span(self.span);
|
||||
diag
|
||||
|
|
@ -643,6 +639,15 @@ pub(crate) enum InvalidFormatStringSuggestion {
|
|||
span: Span,
|
||||
replacement: String,
|
||||
},
|
||||
#[suggestion(
|
||||
builtin_macros_format_add_missing_colon,
|
||||
code = ":?",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
AddMissingColon {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -1001,21 +1006,21 @@ pub(crate) struct CfgSelectUnreachable {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_extern_target_expected_macro)]
|
||||
#[diag(builtin_macros_eii_declaration_expected_macro)]
|
||||
pub(crate) struct EiiExternTargetExpectedMacro {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_extern_target_expected_list)]
|
||||
#[diag(builtin_macros_eii_declaration_expected_list)]
|
||||
pub(crate) struct EiiExternTargetExpectedList {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_extern_target_expected_unsafe)]
|
||||
#[diag(builtin_macros_eii_declaration_expected_unsafe)]
|
||||
pub(crate) struct EiiExternTargetExpectedUnsafe {
|
||||
#[primary_span]
|
||||
#[note]
|
||||
|
|
@ -1030,6 +1035,16 @@ pub(crate) struct EiiSharedMacroExpectedFunction {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_shared_macro_in_statement_position)]
|
||||
pub(crate) struct EiiSharedMacroInStatementPosition {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: String,
|
||||
#[label]
|
||||
pub item_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_eii_only_once)]
|
||||
pub(crate) struct EiiOnlyOnce {
|
||||
|
|
|
|||
|
|
@ -329,6 +329,10 @@ fn make_format_args(
|
|||
replacement,
|
||||
});
|
||||
}
|
||||
parse::Suggestion::AddMissingColon(span) => {
|
||||
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
|
||||
}
|
||||
}
|
||||
let guar = ecx.dcx().emit_err(e);
|
||||
return ExpandResult::Ready(Err(guar));
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(decl_macro)]
|
||||
|
|
@ -119,7 +117,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
|||
derive: derive::Expander { is_const: false },
|
||||
derive_const: derive::Expander { is_const: true },
|
||||
eii: eii::eii,
|
||||
eii_extern_target: eii::eii_extern_target,
|
||||
eii_declaration: eii::eii_declaration,
|
||||
eii_shared_macro: eii::eii_shared_macro,
|
||||
global_allocator: global_allocator::expand,
|
||||
test: test::expand_test,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_expand::base::{
|
|||
};
|
||||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect};
|
||||
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_session::parse::ParseSess;
|
||||
|
|
@ -168,7 +168,7 @@ pub(crate) fn expand_include<'cx>(
|
|||
));
|
||||
let mut ret = SmallVec::new();
|
||||
loop {
|
||||
match p.parse_item(ForceCollect::No) {
|
||||
match p.parse_item(ForceCollect::No, AllowConstBlockItems::Yes) {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub fn inject(
|
|||
|
||||
let item = cx.item(
|
||||
span,
|
||||
thin_vec![cx.attr_word(sym::macro_use, span)],
|
||||
ast::AttrVec::new(),
|
||||
ast::ItemKind::ExternCrate(None, Ident::new(name, ident_span)),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
//! The expansion from a test function to the appropriate test struct for libtest
|
||||
//! Ideally, this code would be in libtest but for efficiency and error messages it lives here.
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::iter;
|
||||
|
||||
use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_errors::{Applicability, Diag, Level};
|
||||
use rustc_expand::base::*;
|
||||
use rustc_hir::Attribute;
|
||||
|
|
|
|||
|
|
@ -78,8 +78,6 @@ type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), Err
|
|||
/// The returned bool indicates whether an applicable suggestion has already been
|
||||
/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))`
|
||||
/// indicates that an ast error was encountered.
|
||||
// FIXME(Nilstrieb) Make this function setup translatable
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub(crate) fn expr_to_spanned_string<'a>(
|
||||
cx: &'a mut ExtCtxt<'_>,
|
||||
expr: Box<ast::Expr>,
|
||||
|
|
|
|||
|
|
@ -744,43 +744,43 @@ unsafe extern "C" {
|
|||
pub struct VaList<'a>(&'a mut VaListImpl);
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro stringify($($t:tt)*) {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro file() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro line() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro cfg() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro asm() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro global_asm() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro naked_asm() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,10 @@ diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs
|
|||
index 1e336bf..35e6f54 100644
|
||||
--- a/coretests/tests/lib.rs
|
||||
+++ b/coretests/tests/lib.rs
|
||||
@@ -2,5 +2,4 @@
|
||||
@@ -2,4 +2,3 @@
|
||||
// tidy-alphabetical-start
|
||||
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
||||
#![cfg_attr(test, feature(cfg_select))]
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(array_ptr_get)]
|
||||
diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs
|
||||
index b735957..ea728b6 100644
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ pub(crate) fn conv_to_call_conv(
|
|||
CanonAbi::Rust | CanonAbi::C => default_call_conv,
|
||||
CanonAbi::RustCold => CallConv::Cold,
|
||||
|
||||
// Cranelift doesn't currently have anything for this.
|
||||
CanonAbi::RustPreserveNone => default_call_conv,
|
||||
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
|
|
|
|||
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