Compare commits
31 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e10913d41 | ||
|
|
9cc698e8d6 | ||
|
|
a096799b4a | ||
|
|
bcfdf1bf97 | ||
|
|
1087b41a83 | ||
|
|
8ac1f9d27d | ||
|
|
25c0e0569c | ||
|
|
4dbbfa3087 | ||
|
|
01268919a5 | ||
|
|
e1dd1bb6cb | ||
|
|
8011d42521 | ||
|
|
622cdb3575 | ||
|
|
90e99bdd32 | ||
|
|
f5ccb92483 | ||
|
|
dbfbf2df54 | ||
|
|
322be0cdee | ||
|
|
34f6f4827d | ||
|
|
d8ac42edd1 | ||
|
|
9126c7a0b7 | ||
|
|
dcea3c7ea3 | ||
|
|
4afad17828 | ||
|
|
b5e2de23c2 | ||
|
|
610c87797c | ||
|
|
e9a79f3f76 | ||
|
|
c226970869 | ||
|
|
b90149755a | ||
|
|
23a44d3c70 | ||
|
|
8065524b58 | ||
|
|
9b1f8ff42d | ||
|
|
9118d50436 | ||
|
|
5d1cb2526b |
4318 changed files with 79059 additions and 110755 deletions
1
.github/ISSUE_TEMPLATE/ice.md
vendored
1
.github/ISSUE_TEMPLATE/ice.md
vendored
|
|
@ -2,7 +2,6 @@
|
||||||
name: Internal Compiler Error
|
name: Internal Compiler Error
|
||||||
about: Create a report for an internal compiler error in rustc.
|
about: Create a report for an internal compiler error in rustc.
|
||||||
labels: C-bug, I-ICE, T-compiler
|
labels: C-bug, I-ICE, T-compiler
|
||||||
title: "[ICE]: "
|
|
||||||
---
|
---
|
||||||
<!--
|
<!--
|
||||||
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
||||||
|
|
|
||||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
|
@ -165,6 +165,9 @@ jobs:
|
||||||
- name: install sccache
|
- name: install sccache
|
||||||
run: src/ci/scripts/install-sccache.sh
|
run: src/ci/scripts/install-sccache.sh
|
||||||
|
|
||||||
|
- name: select Xcode
|
||||||
|
run: src/ci/scripts/select-xcode.sh
|
||||||
|
|
||||||
- name: install clang
|
- name: install clang
|
||||||
run: src/ci/scripts/install-clang.sh
|
run: src/ci/scripts/install-clang.sh
|
||||||
|
|
||||||
|
|
|
||||||
16
.github/workflows/dependencies.yml
vendored
16
.github/workflows/dependencies.yml
vendored
|
|
@ -62,9 +62,19 @@ jobs:
|
||||||
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
|
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
|
||||||
rustup default $TOOLCHAIN
|
rustup default $TOOLCHAIN
|
||||||
|
|
||||||
- name: cargo update
|
- name: cargo update compiler & tools
|
||||||
run: ./src/tools/update-lockfile.sh
|
# Remove first line that always just says "Updating crates.io index"
|
||||||
|
run: |
|
||||||
|
echo -e "\ncompiler & tools dependencies:" >> cargo_update.log
|
||||||
|
cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||||
|
- name: cargo update library
|
||||||
|
run: |
|
||||||
|
echo -e "\nlibrary dependencies:" >> cargo_update.log
|
||||||
|
cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||||
|
- name: cargo update rustbook
|
||||||
|
run: |
|
||||||
|
echo -e "\nrustbook dependencies:" >> cargo_update.log
|
||||||
|
cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||||
- name: upload Cargo.lock artifact for use in PR
|
- name: upload Cargo.lock artifact for use in PR
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -25,7 +25,7 @@
|
||||||
[submodule "src/llvm-project"]
|
[submodule "src/llvm-project"]
|
||||||
path = src/llvm-project
|
path = src/llvm-project
|
||||||
url = https://github.com/rust-lang/llvm-project.git
|
url = https://github.com/rust-lang/llvm-project.git
|
||||||
branch = rustc/22.1-2026-01-27
|
branch = rustc/21.1-2025-08-01
|
||||||
shallow = true
|
shallow = true
|
||||||
[submodule "src/doc/embedded-book"]
|
[submodule "src/doc/embedded-book"]
|
||||||
path = src/doc/embedded-book
|
path = src/doc/embedded-book
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ the Zulip stream is the best place to *ask* for help.
|
||||||
|
|
||||||
Documentation for contributing to the compiler or tooling is located in the [Guide to Rustc
|
Documentation for contributing to the compiler or tooling is located in the [Guide to Rustc
|
||||||
Development][rustc-dev-guide], commonly known as the [rustc-dev-guide]. Documentation for the
|
Development][rustc-dev-guide], commonly known as the [rustc-dev-guide]. Documentation for the
|
||||||
standard library is in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
|
standard library in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
|
||||||
|
|
||||||
## Making changes to subtrees and submodules
|
## Making changes to subtrees and submodules
|
||||||
|
|
||||||
|
|
|
||||||
254
Cargo.lock
254
Cargo.lock
|
|
@ -184,9 +184,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "askama"
|
name = "askama"
|
||||||
version = "0.15.4"
|
version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08e1676b346cadfec169374f949d7490fd80a24193d37d2afce0c047cf695e57"
|
checksum = "bb7125972258312e79827b60c9eb93938334100245081cf701a2dee981b17427"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama_macros",
|
"askama_macros",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
|
@ -197,9 +197,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "askama_derive"
|
name = "askama_derive"
|
||||||
version = "0.15.4"
|
version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7661ff56517787343f376f75db037426facd7c8d3049cef8911f1e75016f3a37"
|
checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama_parser",
|
"askama_parser",
|
||||||
"basic-toml",
|
"basic-toml",
|
||||||
|
|
@ -214,18 +214,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "askama_macros"
|
name = "askama_macros"
|
||||||
version = "0.15.4"
|
version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "713ee4dbfd1eb719c2dab859465b01fa1d21cb566684614a713a6b7a99a4e47b"
|
checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama_derive",
|
"askama_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "askama_parser"
|
name = "askama_parser"
|
||||||
version = "0.15.4"
|
version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d62d674238a526418b30c0def480d5beadb9d8964e7f38d635b03bf639c704c"
|
checksum = "f3c63392767bb2df6aa65a6e1e3b80fd89bb7af6d58359b924c0695620f1512e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -580,9 +580,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.54"
|
version = "4.5.51"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
|
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
|
@ -600,9 +600,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.54"
|
version = "4.5.51"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
|
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
|
@ -630,7 +630,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy"
|
name = "clippy"
|
||||||
version = "0.1.95"
|
version = "0.1.94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"askama",
|
"askama",
|
||||||
|
|
@ -657,7 +657,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy_config"
|
name = "clippy_config"
|
||||||
version = "0.1.95"
|
version = "0.1.94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clippy_utils",
|
"clippy_utils",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
|
@ -681,7 +681,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy_lints"
|
name = "clippy_lints"
|
||||||
version = "0.1.95"
|
version = "0.1.94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"cargo_metadata 0.18.1",
|
"cargo_metadata 0.18.1",
|
||||||
|
|
@ -713,7 +713,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy_utils"
|
name = "clippy_utils"
|
||||||
version = "0.1.95"
|
version = "0.1.94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
|
@ -857,7 +857,7 @@ dependencies = [
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"unified-diff",
|
"unified-diff",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"windows 0.61.3",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1117,7 +1117,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "declare_clippy_lint"
|
name = "declare_clippy_lint"
|
||||||
version = "0.1.95"
|
version = "0.1.94"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive-where"
|
name = "derive-where"
|
||||||
|
|
@ -1298,9 +1298,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ena"
|
name = "ena"
|
||||||
version = "0.14.4"
|
version = "0.14.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1"
|
checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
@ -1670,12 +1670,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.16.1"
|
version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||||
dependencies = [
|
|
||||||
"foldhash 0.2.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
|
@ -1953,12 +1950,12 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.13.0"
|
version = "2.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
@ -2038,7 +2035,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"uuid",
|
"uuid",
|
||||||
"windows 0.61.3",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2652,9 +2649,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-core-foundation"
|
name = "objc2-core-foundation"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
@ -2667,9 +2664,9 @@ checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-io-kit"
|
name = "objc2-io-kit"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
|
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
|
|
@ -3337,7 +3334,6 @@ dependencies = [
|
||||||
"rustdoc-json-types",
|
"rustdoc-json-types",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"similar",
|
"similar",
|
||||||
"tempfile",
|
|
||||||
"wasmparser 0.236.1",
|
"wasmparser 0.236.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -3356,9 +3352,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.27"
|
version = "0.1.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
|
|
@ -3490,6 +3486,7 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
@ -3514,6 +3511,7 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
|
@ -3539,9 +3537,9 @@ dependencies = [
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_ast_pretty",
|
"rustc_ast_pretty",
|
||||||
"rustc_data_structures",
|
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_lexer",
|
"rustc_lexer",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
@ -3572,6 +3570,7 @@ dependencies = [
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_graphviz",
|
"rustc_graphviz",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
|
|
@ -3599,6 +3598,7 @@ dependencies = [
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_lexer",
|
"rustc_lexer",
|
||||||
|
|
@ -3632,6 +3632,7 @@ dependencies = [
|
||||||
"rustc_codegen_ssa",
|
"rustc_codegen_ssa",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_fs_util",
|
"rustc_fs_util",
|
||||||
"rustc_hashes",
|
"rustc_hashes",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
|
|
@ -3640,6 +3641,7 @@ dependencies = [
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_metadata",
|
"rustc_metadata",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
|
"rustc_query_system",
|
||||||
"rustc_sanitizers",
|
"rustc_sanitizers",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
|
@ -3668,6 +3670,7 @@ dependencies = [
|
||||||
"rustc_attr_parsing",
|
"rustc_attr_parsing",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_fs_util",
|
"rustc_fs_util",
|
||||||
"rustc_hashes",
|
"rustc_hashes",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
|
|
@ -3677,6 +3680,7 @@ dependencies = [
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_metadata",
|
"rustc_metadata",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
|
"rustc_query_system",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
|
@ -3686,10 +3690,11 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"thin-vec",
|
||||||
"thorin-dwp",
|
"thorin-dwp",
|
||||||
"tracing",
|
"tracing",
|
||||||
"wasm-encoder 0.219.2",
|
"wasm-encoder 0.219.2",
|
||||||
"windows 0.61.3",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3702,6 +3707,7 @@ dependencies = [
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
|
|
@ -3724,7 +3730,7 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"elsa",
|
"elsa",
|
||||||
"ena",
|
"ena",
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.15.5",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -3746,7 +3752,7 @@ dependencies = [
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thin-vec",
|
"thin-vec",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows 0.61.3",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3761,41 +3767,56 @@ dependencies = [
|
||||||
name = "rustc_driver_impl"
|
name = "rustc_driver_impl"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"jiff",
|
"jiff",
|
||||||
"libc",
|
"libc",
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
|
"rustc_ast_lowering",
|
||||||
|
"rustc_ast_passes",
|
||||||
"rustc_ast_pretty",
|
"rustc_ast_pretty",
|
||||||
|
"rustc_attr_parsing",
|
||||||
|
"rustc_borrowck",
|
||||||
|
"rustc_builtin_macros",
|
||||||
"rustc_codegen_ssa",
|
"rustc_codegen_ssa",
|
||||||
"rustc_const_eval",
|
"rustc_const_eval",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir_analysis",
|
"rustc_hir_analysis",
|
||||||
"rustc_hir_pretty",
|
"rustc_hir_pretty",
|
||||||
|
"rustc_hir_typeck",
|
||||||
|
"rustc_incremental",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
|
"rustc_infer",
|
||||||
"rustc_interface",
|
"rustc_interface",
|
||||||
"rustc_lexer",
|
|
||||||
"rustc_lint",
|
"rustc_lint",
|
||||||
"rustc_log",
|
"rustc_log",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_metadata",
|
"rustc_metadata",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_mir_build",
|
"rustc_mir_build",
|
||||||
|
"rustc_mir_dataflow",
|
||||||
"rustc_mir_transform",
|
"rustc_mir_transform",
|
||||||
|
"rustc_monomorphize",
|
||||||
"rustc_parse",
|
"rustc_parse",
|
||||||
|
"rustc_passes",
|
||||||
|
"rustc_pattern_analysis",
|
||||||
|
"rustc_privacy",
|
||||||
"rustc_public",
|
"rustc_public",
|
||||||
|
"rustc_query_system",
|
||||||
"rustc_resolve",
|
"rustc_resolve",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"rustc_target",
|
"rustc_target",
|
||||||
|
"rustc_trait_selection",
|
||||||
|
"rustc_ty_utils",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shlex",
|
"shlex",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows 0.61.3",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3835,8 +3856,10 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_error_codes",
|
"rustc_error_codes",
|
||||||
"rustc_error_messages",
|
"rustc_error_messages",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hashes",
|
"rustc_hashes",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
|
"rustc_lexer",
|
||||||
"rustc_lint_defs",
|
"rustc_lint_defs",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
|
|
@ -3845,7 +3868,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"termize",
|
"termize",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows 0.61.3",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3859,6 +3882,7 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_lexer",
|
"rustc_lexer",
|
||||||
"rustc_lint_defs",
|
"rustc_lint_defs",
|
||||||
|
|
@ -3886,6 +3910,19 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_fluent_macro"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"annotate-snippets 0.11.5",
|
||||||
|
"fluent-bundle",
|
||||||
|
"fluent-syntax",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.110",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_fs_util"
|
name = "rustc_fs_util"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
@ -3940,6 +3977,7 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
|
|
@ -3986,6 +4024,7 @@ dependencies = [
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_hir_analysis",
|
"rustc_hir_analysis",
|
||||||
"rustc_hir_pretty",
|
"rustc_hir_pretty",
|
||||||
|
|
@ -4007,8 +4046,10 @@ name = "rustc_incremental"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.9.2",
|
"rand 0.9.2",
|
||||||
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_fs_util",
|
"rustc_fs_util",
|
||||||
"rustc_graphviz",
|
"rustc_graphviz",
|
||||||
"rustc_hashes",
|
"rustc_hashes",
|
||||||
|
|
@ -4018,6 +4059,7 @@ dependencies = [
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
"thin-vec",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -4046,6 +4088,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
@ -4076,6 +4119,7 @@ dependencies = [
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_fs_util",
|
"rustc_fs_util",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_hir_analysis",
|
"rustc_hir_analysis",
|
||||||
|
|
@ -4092,6 +4136,7 @@ dependencies = [
|
||||||
"rustc_passes",
|
"rustc_passes",
|
||||||
"rustc_privacy",
|
"rustc_privacy",
|
||||||
"rustc_query_impl",
|
"rustc_query_impl",
|
||||||
|
"rustc_query_system",
|
||||||
"rustc_resolve",
|
"rustc_resolve",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
|
@ -4120,13 +4165,13 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_apfloat",
|
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_ast_pretty",
|
"rustc_ast_pretty",
|
||||||
"rustc_attr_parsing",
|
"rustc_attr_parsing",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
|
|
@ -4178,8 +4223,6 @@ dependencies = [
|
||||||
name = "rustc_macros"
|
name = "rustc_macros"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fluent-bundle",
|
|
||||||
"fluent-syntax",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.110",
|
"syn 2.0.110",
|
||||||
|
|
@ -4201,6 +4244,7 @@ dependencies = [
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_fs_util",
|
"rustc_fs_util",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_hir_pretty",
|
"rustc_hir_pretty",
|
||||||
|
|
@ -4224,7 +4268,6 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"either",
|
"either",
|
||||||
"gsgdt",
|
"gsgdt",
|
||||||
"parking_lot",
|
|
||||||
"polonius-engine",
|
"polonius-engine",
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_apfloat",
|
"rustc_apfloat",
|
||||||
|
|
@ -4235,6 +4278,7 @@ dependencies = [
|
||||||
"rustc_error_messages",
|
"rustc_error_messages",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_graphviz",
|
"rustc_graphviz",
|
||||||
"rustc_hashes",
|
"rustc_hashes",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
|
|
@ -4242,6 +4286,7 @@ dependencies = [
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_lint_defs",
|
"rustc_lint_defs",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
"rustc_query_system",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
|
@ -4264,6 +4309,7 @@ dependencies = [
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
|
|
@ -4284,10 +4330,11 @@ dependencies = [
|
||||||
"polonius-engine",
|
"polonius-engine",
|
||||||
"regex",
|
"regex",
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_graphviz",
|
"rustc_graphviz",
|
||||||
"rustc_hir",
|
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
|
|
@ -4301,6 +4348,7 @@ name = "rustc_mir_transform"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
|
"hashbrown 0.15.5",
|
||||||
"itertools",
|
"itertools",
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_arena",
|
"rustc_arena",
|
||||||
|
|
@ -4308,6 +4356,7 @@ dependencies = [
|
||||||
"rustc_const_eval",
|
"rustc_const_eval",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
|
|
@ -4329,6 +4378,7 @@ dependencies = [
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
@ -4365,6 +4415,7 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_lexer",
|
"rustc_lexer",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
@ -4397,6 +4448,7 @@ dependencies = [
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
@ -4419,6 +4471,7 @@ dependencies = [
|
||||||
"rustc_arena",
|
"rustc_arena",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
@ -4438,6 +4491,7 @@ dependencies = [
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
|
|
@ -4490,18 +4544,38 @@ name = "rustc_query_impl"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"measureme",
|
"measureme",
|
||||||
|
"rustc_data_structures",
|
||||||
|
"rustc_hashes",
|
||||||
|
"rustc_hir",
|
||||||
|
"rustc_index",
|
||||||
|
"rustc_middle",
|
||||||
|
"rustc_query_system",
|
||||||
|
"rustc_serialize",
|
||||||
|
"rustc_span",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_query_system"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.15.5",
|
||||||
|
"parking_lot",
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hashes",
|
"rustc_hashes",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_middle",
|
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"rustc_thread_pool",
|
"rustc_thread_pool",
|
||||||
|
"smallvec",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -4520,11 +4594,13 @@ dependencies = [
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_metadata",
|
"rustc_metadata",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
|
"rustc_query_system",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
|
@ -4572,6 +4648,7 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_fs_util",
|
"rustc_fs_util",
|
||||||
"rustc_hashes",
|
"rustc_hashes",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
|
|
@ -4582,7 +4659,7 @@ dependencies = [
|
||||||
"rustc_target",
|
"rustc_target",
|
||||||
"termize",
|
"termize",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows 0.61.3",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4678,6 +4755,7 @@ dependencies = [
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
@ -4726,6 +4804,7 @@ dependencies = [
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hashes",
|
"rustc_hashes",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
|
|
@ -5354,14 +5433,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.38.2"
|
version = "0.37.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1efc19935b4b66baa6f654ac7924c192f55b175c00a7ab72410fc24284dacda8"
|
checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-io-kit",
|
"objc2-io-kit",
|
||||||
"windows 0.62.2",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -5538,7 +5617,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"build_helper",
|
"build_helper",
|
||||||
"cargo_metadata 0.21.0",
|
"cargo_metadata 0.21.0",
|
||||||
"clap",
|
"fluent-syntax",
|
||||||
"globset",
|
"globset",
|
||||||
"ignore",
|
"ignore",
|
||||||
"miropt-test-tools",
|
"miropt-test-tools",
|
||||||
|
|
@ -6314,34 +6393,22 @@ version = "0.61.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-collections 0.2.0",
|
"windows-collections",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
"windows-future 0.2.1",
|
"windows-future",
|
||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
"windows-numerics 0.2.0",
|
"windows-numerics",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows"
|
|
||||||
version = "0.62.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
|
|
||||||
dependencies = [
|
|
||||||
"windows-collections 0.3.2",
|
|
||||||
"windows-core 0.62.2",
|
|
||||||
"windows-future 0.3.2",
|
|
||||||
"windows-numerics 0.3.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-bindgen"
|
name = "windows-bindgen"
|
||||||
version = "0.66.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "81b7ec123a4eadd44d1f44f76804316b477b2537abed9a2ab950b3c54afa1fcf"
|
checksum = "9b4e97b01190d32f268a2dfbd3f006f77840633746707fbe40bcee588108a231"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"windows-threading 0.2.1",
|
"windows-threading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -6353,15 +6420,6 @@ dependencies = [
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-collections"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core 0.62.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.61.2"
|
version = "0.61.2"
|
||||||
|
|
@ -6396,18 +6454,7 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
"windows-threading 0.1.0",
|
"windows-threading",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-future"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core 0.62.2",
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
"windows-threading 0.2.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -6454,16 +6501,6 @@ dependencies = [
|
||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-numerics"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core 0.62.2",
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
|
|
@ -6569,15 +6606,6 @@ dependencies = [
|
||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-threading"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ itself back on after some time).
|
||||||
|
|
||||||
### MSVC
|
### MSVC
|
||||||
|
|
||||||
MSVC builds of Rust additionally require an installation of:
|
MSVC builds of Rust additionally requires an installation of:
|
||||||
|
|
||||||
- Visual Studio 2022 (or later) build tools so `rustc` can use its linker. Older
|
- Visual Studio 2022 (or later) build tools so `rustc` can use its linker. Older
|
||||||
Visual Studio versions such as 2019 *may* work but aren't actively tested.
|
Visual Studio versions such as 2019 *may* work but aren't actively tested.
|
||||||
|
|
|
||||||
128
RELEASES.md
128
RELEASES.md
|
|
@ -1,123 +1,3 @@
|
||||||
Version 1.93.1 (2026-02-12)
|
|
||||||
===========================
|
|
||||||
|
|
||||||
<a id="1.93.1"></a>
|
|
||||||
|
|
||||||
- [Don't try to recover keyword as non-keyword identifier](https://github.com/rust-lang/rust/pull/150590), fixing an ICE that especially [affected rustfmt](https://github.com/rust-lang/rustfmt/issues/6739).
|
|
||||||
- [Fix `clippy::panicking_unwrap` false-positive on field access with implicit deref](https://github.com/rust-lang/rust-clippy/pull/16196).
|
|
||||||
- [Revert "Update wasm-related dependencies in CI"](https://github.com/rust-lang/rust/pull/152259), fixing file descriptor leaks on the `wasm32-wasip2` target.
|
|
||||||
|
|
||||||
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)
|
Version 1.92.0 (2025-12-11)
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
|
@ -1555,7 +1435,7 @@ Compatibility Notes
|
||||||
- [Check well-formedness of the source type's signature in fn pointer casts.](https://github.com/rust-lang/rust/pull/129021) This partly closes a soundness hole that comes when casting a function item to function pointer
|
- [Check well-formedness of the source type's signature in fn pointer casts.](https://github.com/rust-lang/rust/pull/129021) This partly closes a soundness hole that comes when casting a function item to function pointer
|
||||||
- [Use equality instead of subtyping when resolving type dependent paths.](https://github.com/rust-lang/rust/pull/129073)
|
- [Use equality instead of subtyping when resolving type dependent paths.](https://github.com/rust-lang/rust/pull/129073)
|
||||||
- Linking on macOS now correctly includes Rust's default deployment target. Due to a linker bug, you might have to pass `MACOSX_DEPLOYMENT_TARGET` or fix your `#[link]` attributes to point to the correct frameworks. See <https://github.com/rust-lang/rust/pull/129369>.
|
- Linking on macOS now correctly includes Rust's default deployment target. Due to a linker bug, you might have to pass `MACOSX_DEPLOYMENT_TARGET` or fix your `#[link]` attributes to point to the correct frameworks. See <https://github.com/rust-lang/rust/pull/129369>.
|
||||||
- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previously did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
|
- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previous did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
|
||||||
- The future incompatibility lint `deprecated_cfg_attr_crate_type_name` [has been made into a hard error](https://github.com/rust-lang/rust/pull/129670). It was used to deny usage of `#![crate_type]` and `#![crate_name]` attributes in `#![cfg_attr]`, which required a hack in the compiler to be able to change the used crate type and crate name after cfg expansion.
|
- The future incompatibility lint `deprecated_cfg_attr_crate_type_name` [has been made into a hard error](https://github.com/rust-lang/rust/pull/129670). It was used to deny usage of `#![crate_type]` and `#![crate_name]` attributes in `#![cfg_attr]`, which required a hack in the compiler to be able to change the used crate type and crate name after cfg expansion.
|
||||||
Users can use `--crate-type` instead of `#![cfg_attr(..., crate_type = "...")]` and `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]` when running `rustc`/`cargo rustc` on the command line.
|
Users can use `--crate-type` instead of `#![cfg_attr(..., crate_type = "...")]` and `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]` when running `rustc`/`cargo rustc` on the command line.
|
||||||
Use of those two attributes outside of `#![cfg_attr]` continue to be fully supported.
|
Use of those two attributes outside of `#![cfg_attr]` continue to be fully supported.
|
||||||
|
|
@ -1731,7 +1611,7 @@ Cargo
|
||||||
Compatibility Notes
|
Compatibility Notes
|
||||||
-------------------
|
-------------------
|
||||||
- We now [disallow setting some built-in cfgs via the command-line](https://github.com/rust-lang/rust/pull/126158) with the newly added [`explicit_builtin_cfgs_in_flags`](https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html#explicit-builtin-cfgs-in-flags) lint in order to prevent incoherent state, eg. `windows` cfg active but target is Linux based. The appropriate [`rustc` flag](https://doc.rust-lang.org/rustc/command-line-arguments.html) should be used instead.
|
- We now [disallow setting some built-in cfgs via the command-line](https://github.com/rust-lang/rust/pull/126158) with the newly added [`explicit_builtin_cfgs_in_flags`](https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html#explicit-builtin-cfgs-in-flags) lint in order to prevent incoherent state, eg. `windows` cfg active but target is Linux based. The appropriate [`rustc` flag](https://doc.rust-lang.org/rustc/command-line-arguments.html) should be used instead.
|
||||||
- The standard library has a new implementation of `binary_search` which significantly improves performance ([#128254](https://github.com/rust-lang/rust/pull/128254)). However when a sorted slice has multiple values which compare equal, the new implementation may select a different value among the equal ones than the old implementation.
|
- The standard library has a new implementation of `binary_search` which is significantly improves performance ([#128254](https://github.com/rust-lang/rust/pull/128254)). However when a sorted slice has multiple values which compare equal, the new implementation may select a different value among the equal ones than the old implementation.
|
||||||
- [illumos/Solaris now sets `MSG_NOSIGNAL` when writing to sockets](https://github.com/rust-lang/rust/pull/128259). This avoids killing the process with SIGPIPE when writing to a closed socket, which matches the existing behavior on other UNIX targets.
|
- [illumos/Solaris now sets `MSG_NOSIGNAL` when writing to sockets](https://github.com/rust-lang/rust/pull/128259). This avoids killing the process with SIGPIPE when writing to a closed socket, which matches the existing behavior on other UNIX targets.
|
||||||
- [Removes a problematic hack that always passed the --whole-archive linker flag for tests, which may cause linker errors for code accidentally relying on it.](https://github.com/rust-lang/rust/pull/128400)
|
- [Removes a problematic hack that always passed the --whole-archive linker flag for tests, which may cause linker errors for code accidentally relying on it.](https://github.com/rust-lang/rust/pull/128400)
|
||||||
- The WebAssembly target features `multivalue` and `reference-types` are now
|
- The WebAssembly target features `multivalue` and `reference-types` are now
|
||||||
|
|
@ -1881,7 +1761,7 @@ These changes do not affect any public interfaces of Rust, but they represent
|
||||||
significant improvements to the performance or internals of rustc and related
|
significant improvements to the performance or internals of rustc and related
|
||||||
tools.
|
tools.
|
||||||
|
|
||||||
- [Add a Rust-for-Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
|
- [Add a Rust-for Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
|
||||||
|
|
||||||
Version 1.80.1 (2024-08-08)
|
Version 1.80.1 (2024-08-08)
|
||||||
===========================
|
===========================
|
||||||
|
|
@ -4519,7 +4399,7 @@ Compatibility Notes
|
||||||
saturating to `0` instead][89926]. In the real world the panic happened mostly
|
saturating to `0` instead][89926]. In the real world the panic happened mostly
|
||||||
on platforms with buggy monotonic clock implementations rather than catching
|
on platforms with buggy monotonic clock implementations rather than catching
|
||||||
programming errors like reversing the start and end times. Such programming
|
programming errors like reversing the start and end times. Such programming
|
||||||
errors will now result in `0` rather than a panic.
|
errors will now results in `0` rather than a panic.
|
||||||
- In a future release we're planning to increase the baseline requirements for
|
- In a future release we're planning to increase the baseline requirements for
|
||||||
the Linux kernel to version 3.2, and for glibc to version 2.17. We'd love
|
the Linux kernel to version 3.2, and for glibc to version 2.17. We'd love
|
||||||
your feedback in [PR #95026][95026].
|
your feedback in [PR #95026][95026].
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ path = [
|
||||||
]
|
]
|
||||||
precedence = "override"
|
precedence = "override"
|
||||||
SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)"
|
SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)"
|
||||||
SPDX-License-Identifier = "MIT OR Apache-2.0"
|
SPDX-License-Identifier = "MIT or Apache-2.0"
|
||||||
|
|
||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = "compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp"
|
path = "compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp"
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
// Several crates are depended upon but unused so that they are present in the sysroot
|
// Several crates are depended upon but unused so that they are present in the sysroot
|
||||||
#![expect(unused_crate_dependencies)]
|
#![expect(unused_crate_dependencies)]
|
||||||
|
|
||||||
use std::process::ExitCode;
|
|
||||||
|
|
||||||
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
||||||
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
||||||
// mechanism. However, for complicated reasons (see
|
// mechanism. However, for complicated reasons (see
|
||||||
|
|
@ -40,6 +38,6 @@ use std::process::ExitCode;
|
||||||
#[cfg(feature = "jemalloc")]
|
#[cfg(feature = "jemalloc")]
|
||||||
use tikv_jemalloc_sys as _;
|
use tikv_jemalloc_sys as _;
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() {
|
||||||
rustc_driver::main()
|
rustc_driver::main()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ impl Reg {
|
||||||
|
|
||||||
reg_ctor!(f32, Float, 32);
|
reg_ctor!(f32, Float, 32);
|
||||||
reg_ctor!(f64, Float, 64);
|
reg_ctor!(f64, Float, 64);
|
||||||
reg_ctor!(f128, Float, 128);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reg {
|
impl Reg {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ pub enum CanonAbi {
|
||||||
C,
|
C,
|
||||||
Rust,
|
Rust,
|
||||||
RustCold,
|
RustCold,
|
||||||
RustPreserveNone,
|
|
||||||
|
|
||||||
/// An ABI that rustc does not know how to call or define.
|
/// An ABI that rustc does not know how to call or define.
|
||||||
Custom,
|
Custom,
|
||||||
|
|
@ -55,7 +54,7 @@ pub enum CanonAbi {
|
||||||
impl CanonAbi {
|
impl CanonAbi {
|
||||||
pub fn is_rustic_abi(self) -> bool {
|
pub fn is_rustic_abi(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
|
CanonAbi::Rust | CanonAbi::RustCold => true,
|
||||||
CanonAbi::C
|
CanonAbi::C
|
||||||
| CanonAbi::Custom
|
| CanonAbi::Custom
|
||||||
| CanonAbi::Arm(_)
|
| CanonAbi::Arm(_)
|
||||||
|
|
@ -75,7 +74,6 @@ impl fmt::Display for CanonAbi {
|
||||||
CanonAbi::C => ExternAbi::C { unwind: false },
|
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||||
CanonAbi::Rust => ExternAbi::Rust,
|
CanonAbi::Rust => ExternAbi::Rust,
|
||||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||||
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
|
|
||||||
CanonAbi::Custom => ExternAbi::Custom,
|
CanonAbi::Custom => ExternAbi::Custom,
|
||||||
CanonAbi::Arm(arm_call) => match arm_call {
|
CanonAbi::Arm(arm_call) => match arm_call {
|
||||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,6 @@ pub enum ExternAbi {
|
||||||
/// in a platform-agnostic way.
|
/// in a platform-agnostic way.
|
||||||
RustInvalid,
|
RustInvalid,
|
||||||
|
|
||||||
/// Preserves no registers.
|
|
||||||
///
|
|
||||||
/// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
|
|
||||||
/// and may fall-back to a more conservative calling convention if the backend does not support
|
|
||||||
/// forcing callers to save all registers.
|
|
||||||
RustPreserveNone,
|
|
||||||
|
|
||||||
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
|
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
|
||||||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||||
Unadjusted,
|
Unadjusted,
|
||||||
|
|
@ -170,7 +163,6 @@ abi_impls! {
|
||||||
RustCall =><= "rust-call",
|
RustCall =><= "rust-call",
|
||||||
RustCold =><= "rust-cold",
|
RustCold =><= "rust-cold",
|
||||||
RustInvalid =><= "rust-invalid",
|
RustInvalid =><= "rust-invalid",
|
||||||
RustPreserveNone =><= "rust-preserve-none",
|
|
||||||
Stdcall { unwind: false } =><= "stdcall",
|
Stdcall { unwind: false } =><= "stdcall",
|
||||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||||
System { unwind: false } =><= "system",
|
System { unwind: false } =><= "system",
|
||||||
|
|
@ -251,7 +243,7 @@ impl ExternAbi {
|
||||||
/// - are subject to change between compiler versions
|
/// - are subject to change between compiler versions
|
||||||
pub fn is_rustic_abi(self) -> bool {
|
pub fn is_rustic_abi(self) -> bool {
|
||||||
use ExternAbi::*;
|
use ExternAbi::*;
|
||||||
matches!(self, Rust | RustCall | RustCold | RustPreserveNone)
|
matches!(self, Rust | RustCall | RustCold)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
|
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
|
||||||
|
|
@ -323,8 +315,7 @@ impl ExternAbi {
|
||||||
| Self::Thiscall { .. }
|
| Self::Thiscall { .. }
|
||||||
| Self::Vectorcall { .. }
|
| Self::Vectorcall { .. }
|
||||||
| Self::SysV64 { .. }
|
| Self::SysV64 { .. }
|
||||||
| Self::Win64 { .. }
|
| Self::Win64 { .. } => true,
|
||||||
| Self::RustPreserveNone => true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
|
use std::assert_matches::assert_matches;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use rustc_data_structures::assert_matches;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
|
||||||
|
|
@ -290,19 +290,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
/// function call isn't allowed (a.k.a. `va_list`).
|
/// function call isn't allowed (a.k.a. `va_list`).
|
||||||
///
|
///
|
||||||
/// This function handles transparent types automatically.
|
/// This function handles transparent types automatically.
|
||||||
pub fn pass_indirectly_in_non_rustic_abis<C>(self, cx: &C) -> bool
|
pub fn pass_indirectly_in_non_rustic_abis<C>(mut self, cx: &C) -> bool
|
||||||
where
|
|
||||||
Ty: TyAbiInterface<'a, C> + Copy,
|
|
||||||
{
|
|
||||||
let base = self.peel_transparent_wrappers(cx);
|
|
||||||
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Recursively peel away transparent wrappers, returning the inner value.
|
|
||||||
///
|
|
||||||
/// The return value is not `repr(transparent)` and/or does
|
|
||||||
/// not have a non-1zst field.
|
|
||||||
pub fn peel_transparent_wrappers<C>(mut self, cx: &C) -> Self
|
|
||||||
where
|
where
|
||||||
Ty: TyAbiInterface<'a, C> + Copy,
|
Ty: TyAbiInterface<'a, C> + Copy,
|
||||||
{
|
{
|
||||||
|
|
@ -312,7 +300,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
self = field;
|
self = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the one field that is not a 1-ZST.
|
/// Finds the one field that is not a 1-ZST.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![cfg_attr(all(feature = "nightly", bootstrap, test), feature(assert_matches))]
|
|
||||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||||
|
#![cfg_attr(feature = "nightly", feature(assert_matches))]
|
||||||
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
||||||
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#![cfg_attr(test, feature(test))]
|
#![cfg_attr(test, feature(test))]
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
#![doc(test(no_crate_inject, attr(deny(warnings), allow(internal_features))))]
|
#![doc(test(no_crate_inject, attr(deny(warnings), allow(internal_features))))]
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(dropck_eyepatch)]
|
#![feature(dropck_eyepatch)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
|
@ -25,7 +26,7 @@ use std::cell::{Cell, RefCell};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem::{self, MaybeUninit};
|
use std::mem::{self, MaybeUninit};
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
use std::{cmp, hint, slice};
|
use std::{cmp, intrinsics, slice};
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
|
@ -171,22 +172,8 @@ impl<T> TypedArena<T> {
|
||||||
available_bytes >= additional_bytes
|
available_bytes >= additional_bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates storage for `len >= 1` values in this arena, and returns a
|
|
||||||
/// raw pointer to the first value's storage.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Caller must initialize each of the `len` slots to a droppable value
|
|
||||||
/// before the arena is dropped.
|
|
||||||
///
|
|
||||||
/// In practice, this typically means that the caller must be able to
|
|
||||||
/// raw-copy `len` already-initialized values into the slice without any
|
|
||||||
/// possibility of panicking.
|
|
||||||
///
|
|
||||||
/// FIXME(Zalathar): This is *very* fragile; perhaps we need a different
|
|
||||||
/// approach to arena-allocating slices of droppable values.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T {
|
fn alloc_raw_slice(&self, len: usize) -> *mut T {
|
||||||
assert!(size_of::<T>() != 0);
|
assert!(size_of::<T>() != 0);
|
||||||
assert!(len != 0);
|
assert!(len != 0);
|
||||||
|
|
||||||
|
|
@ -221,7 +208,7 @@ impl<T> TypedArena<T> {
|
||||||
&self,
|
&self,
|
||||||
iter: impl IntoIterator<Item = Result<T, E>>,
|
iter: impl IntoIterator<Item = Result<T, E>>,
|
||||||
) -> Result<&mut [T], E> {
|
) -> Result<&mut [T], E> {
|
||||||
// Despite the similarity with `DroplessArena`, we cannot reuse their fast case. The reason
|
// Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason
|
||||||
// is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a
|
// is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a
|
||||||
// reference to `self` and adding elements to the arena during iteration.
|
// reference to `self` and adding elements to the arena during iteration.
|
||||||
//
|
//
|
||||||
|
|
@ -242,15 +229,9 @@ impl<T> TypedArena<T> {
|
||||||
}
|
}
|
||||||
// Move the content to the arena by copying and then forgetting it.
|
// Move the content to the arena by copying and then forgetting it.
|
||||||
let len = vec.len();
|
let len = vec.len();
|
||||||
|
|
||||||
// SAFETY: After allocating raw storage for exactly `len` values, we
|
|
||||||
// must fully initialize the storage without panicking, and we must
|
|
||||||
// also prevent the stale values in the vec from being dropped.
|
|
||||||
Ok(unsafe {
|
|
||||||
let start_ptr = self.alloc_raw_slice(len);
|
let start_ptr = self.alloc_raw_slice(len);
|
||||||
// Initialize the newly-allocated storage without panicking.
|
Ok(unsafe {
|
||||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||||
// Prevent the stale values in the vec from being dropped.
|
|
||||||
vec.set_len(0);
|
vec.set_len(0);
|
||||||
slice::from_raw_parts_mut(start_ptr, len)
|
slice::from_raw_parts_mut(start_ptr, len)
|
||||||
})
|
})
|
||||||
|
|
@ -451,7 +432,7 @@ impl DroplessArena {
|
||||||
let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT);
|
let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT);
|
||||||
|
|
||||||
// Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT.
|
// Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT.
|
||||||
unsafe { hint::assert_unchecked(end == align_down(end, DROPLESS_ALIGNMENT)) };
|
unsafe { intrinsics::assume(end == align_down(end, DROPLESS_ALIGNMENT)) };
|
||||||
|
|
||||||
if let Some(sub) = end.checked_sub(bytes) {
|
if let Some(sub) = end.checked_sub(bytes) {
|
||||||
let new_end = align_down(sub, layout.align());
|
let new_end = align_down(sub, layout.align());
|
||||||
|
|
@ -509,6 +490,19 @@ impl DroplessArena {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used by `Lift` to check whether this slice is allocated
|
||||||
|
/// in this arena.
|
||||||
|
#[inline]
|
||||||
|
pub fn contains_slice<T>(&self, slice: &[T]) -> bool {
|
||||||
|
for chunk in self.chunks.borrow_mut().iter_mut() {
|
||||||
|
let ptr = slice.as_ptr().cast::<u8>().cast_mut();
|
||||||
|
if chunk.start() <= ptr && chunk.end() >= ptr {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Allocates a string slice that is copied into the `DroplessArena`, returning a
|
/// Allocates a string slice that is copied into the `DroplessArena`, returning a
|
||||||
/// reference to it. Will panic if passed an empty string.
|
/// reference to it. Will panic if passed an empty string.
|
||||||
///
|
///
|
||||||
|
|
@ -590,7 +584,7 @@ impl DroplessArena {
|
||||||
&self,
|
&self,
|
||||||
iter: impl IntoIterator<Item = Result<T, E>>,
|
iter: impl IntoIterator<Item = Result<T, E>>,
|
||||||
) -> Result<&mut [T], E> {
|
) -> Result<&mut [T], E> {
|
||||||
// Despite the similarity with `alloc_from_iter`, we cannot reuse their fast case, as we
|
// Despite the similarlty with `alloc_from_iter`, we cannot reuse their fast case, as we
|
||||||
// cannot know the minimum length of the iterator in this case.
|
// cannot know the minimum length of the iterator in this case.
|
||||||
assert!(size_of::<T>() != 0);
|
assert!(size_of::<T>() != 0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -656,7 +656,11 @@ impl Pat {
|
||||||
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
|
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
|
||||||
// assuming `T0` to `Tn` are all syntactically valid as types.
|
// assuming `T0` to `Tn` are all syntactically valid as types.
|
||||||
PatKind::Tuple(pats) => {
|
PatKind::Tuple(pats) => {
|
||||||
let tys = pats.iter().map(|pat| pat.to_ty()).collect::<Option<ThinVec<_>>>()?;
|
let mut tys = ThinVec::with_capacity(pats.len());
|
||||||
|
// FIXME(#48994) - could just be collected into an Option<Vec>
|
||||||
|
for pat in pats {
|
||||||
|
tys.push(pat.to_ty()?);
|
||||||
|
}
|
||||||
TyKind::Tup(tys)
|
TyKind::Tup(tys)
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
|
@ -3131,16 +3135,8 @@ pub enum Const {
|
||||||
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
||||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
||||||
pub enum Defaultness {
|
pub enum Defaultness {
|
||||||
/// Item is unmarked. Implicitly determined based off of position.
|
|
||||||
/// For impls, this is `final`; for traits, this is `default`.
|
|
||||||
///
|
|
||||||
/// If you're expanding an item in a built-in macro or parsing an item
|
|
||||||
/// by hand, you probably want to use this.
|
|
||||||
Implicit,
|
|
||||||
/// `default`
|
|
||||||
Default(Span),
|
Default(Span),
|
||||||
/// `final`; per RFC 3678, only trait items may be *explicitly* marked final.
|
Final,
|
||||||
Final(Span),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||||
|
|
@ -3630,7 +3626,6 @@ impl Item {
|
||||||
pub fn opt_generics(&self) -> Option<&Generics> {
|
pub fn opt_generics(&self) -> Option<&Generics> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
ItemKind::ExternCrate(..)
|
ItemKind::ExternCrate(..)
|
||||||
| ItemKind::ConstBlock(_)
|
|
||||||
| ItemKind::Use(_)
|
| ItemKind::Use(_)
|
||||||
| ItemKind::Mod(..)
|
| ItemKind::Mod(..)
|
||||||
| ItemKind::ForeignMod(_)
|
| ItemKind::ForeignMod(_)
|
||||||
|
|
@ -3877,55 +3872,27 @@ pub struct ConstItem {
|
||||||
pub ident: Ident,
|
pub ident: Ident,
|
||||||
pub generics: Generics,
|
pub generics: Generics,
|
||||||
pub ty: Box<Ty>,
|
pub ty: Box<Ty>,
|
||||||
pub rhs_kind: ConstItemRhsKind,
|
pub rhs: Option<ConstItemRhs>,
|
||||||
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||||
pub enum ConstItemRhsKind {
|
pub enum ConstItemRhs {
|
||||||
Body { rhs: Option<Box<Expr>> },
|
TypeConst(AnonConst),
|
||||||
TypeConst { rhs: Option<AnonConst> },
|
Body(Box<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstItemRhsKind {
|
impl ConstItemRhs {
|
||||||
pub fn new_body(rhs: Box<Expr>) -> Self {
|
pub fn span(&self) -> Span {
|
||||||
Self::Body { rhs: Some(rhs) }
|
self.expr().span
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn span(&self) -> Option<Span> {
|
pub fn expr(&self) -> &Expr {
|
||||||
Some(self.expr()?.span)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expr(&self) -> Option<&Expr> {
|
|
||||||
match self {
|
match self {
|
||||||
Self::Body { rhs: Some(body) } => Some(&body),
|
ConstItemRhs::TypeConst(anon_const) => &anon_const.value,
|
||||||
Self::TypeConst { rhs: Some(anon) } => Some(&anon.value),
|
ConstItemRhs::Body(expr) => expr,
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_expr(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Body { rhs: Some(_) } => true,
|
|
||||||
Self::TypeConst { rhs: Some(_) } => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_type_const(&self) -> bool {
|
|
||||||
matches!(self, &Self::TypeConst { .. })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
|
||||||
pub struct ConstBlockItem {
|
|
||||||
pub id: NodeId,
|
|
||||||
pub span: Span,
|
|
||||||
pub block: Box<Block>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConstBlockItem {
|
|
||||||
pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
||||||
|
|
@ -3947,11 +3914,6 @@ pub enum ItemKind {
|
||||||
///
|
///
|
||||||
/// E.g., `const FOO: i32 = 42;`.
|
/// E.g., `const FOO: i32 = 42;`.
|
||||||
Const(Box<ConstItem>),
|
Const(Box<ConstItem>),
|
||||||
/// A module-level const block.
|
|
||||||
/// Equivalent to `const _: () = const { ... };`.
|
|
||||||
///
|
|
||||||
/// E.g., `const { assert!(true) }`.
|
|
||||||
ConstBlock(ConstBlockItem),
|
|
||||||
/// A function declaration (`fn`).
|
/// A function declaration (`fn`).
|
||||||
///
|
///
|
||||||
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
|
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
|
||||||
|
|
@ -4028,8 +3990,6 @@ impl ItemKind {
|
||||||
| ItemKind::MacroDef(ident, _)
|
| ItemKind::MacroDef(ident, _)
|
||||||
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
|
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
|
||||||
|
|
||||||
ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT),
|
|
||||||
|
|
||||||
ItemKind::Use(_)
|
ItemKind::Use(_)
|
||||||
| ItemKind::ForeignMod(_)
|
| ItemKind::ForeignMod(_)
|
||||||
| ItemKind::GlobalAsm(_)
|
| ItemKind::GlobalAsm(_)
|
||||||
|
|
@ -4043,9 +4003,9 @@ impl ItemKind {
|
||||||
pub fn article(&self) -> &'static str {
|
pub fn article(&self) -> &'static str {
|
||||||
use ItemKind::*;
|
use ItemKind::*;
|
||||||
match self {
|
match self {
|
||||||
Use(..) | Static(..) | Const(..) | ConstBlock(..) | Fn(..) | Mod(..)
|
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
||||||
| GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..)
|
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
||||||
| MacroDef(..) | Delegation(..) | DelegationMac(..) => "a",
|
| Delegation(..) | DelegationMac(..) => "a",
|
||||||
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4056,7 +4016,6 @@ impl ItemKind {
|
||||||
ItemKind::Use(..) => "`use` import",
|
ItemKind::Use(..) => "`use` import",
|
||||||
ItemKind::Static(..) => "static item",
|
ItemKind::Static(..) => "static item",
|
||||||
ItemKind::Const(..) => "constant item",
|
ItemKind::Const(..) => "constant item",
|
||||||
ItemKind::ConstBlock(..) => "const block",
|
|
||||||
ItemKind::Fn(..) => "function",
|
ItemKind::Fn(..) => "function",
|
||||||
ItemKind::Mod(..) => "module",
|
ItemKind::Mod(..) => "module",
|
||||||
ItemKind::ForeignMod(..) => "extern block",
|
ItemKind::ForeignMod(..) => "extern block",
|
||||||
|
|
@ -4086,18 +4045,7 @@ impl ItemKind {
|
||||||
| Self::Trait(box Trait { generics, .. })
|
| Self::Trait(box Trait { generics, .. })
|
||||||
| Self::TraitAlias(box TraitAlias { generics, .. })
|
| Self::TraitAlias(box TraitAlias { generics, .. })
|
||||||
| Self::Impl(Impl { generics, .. }) => Some(generics),
|
| Self::Impl(Impl { generics, .. }) => Some(generics),
|
||||||
|
_ => None,
|
||||||
Self::ExternCrate(..)
|
|
||||||
| Self::Use(..)
|
|
||||||
| Self::Static(..)
|
|
||||||
| Self::ConstBlock(..)
|
|
||||||
| Self::Mod(..)
|
|
||||||
| Self::ForeignMod(..)
|
|
||||||
| Self::GlobalAsm(..)
|
|
||||||
| Self::MacCall(..)
|
|
||||||
| Self::MacroDef(..)
|
|
||||||
| Self::Delegation(..)
|
|
||||||
| Self::DelegationMac(..) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4148,7 +4096,7 @@ impl AssocItemKind {
|
||||||
| Self::Fn(box Fn { defaultness, .. })
|
| Self::Fn(box Fn { defaultness, .. })
|
||||||
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
||||||
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
||||||
Defaultness::Implicit
|
Defaultness::Final
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
//! This API is completely unstable and subject to change.
|
//! This API is completely unstable and subject to change.
|
||||||
|
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
|
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||||
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
||||||
#![feature(associated_type_defaults)]
|
#![feature(associated_type_defaults)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
|
|
||||||
|
|
@ -625,12 +625,12 @@ impl TokenKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
pub const fn new(kind: TokenKind, span: Span) -> Self {
|
pub fn new(kind: TokenKind, span: Span) -> Self {
|
||||||
Token { kind, span }
|
Token { kind, span }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Some token that will be thrown away later.
|
/// Some token that will be thrown away later.
|
||||||
pub const fn dummy() -> Self {
|
pub fn dummy() -> Self {
|
||||||
Token::new(TokenKind::Question, DUMMY_SP)
|
Token::new(TokenKind::Question, DUMMY_SP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -354,13 +354,7 @@ fn make_attr_token_stream(
|
||||||
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
|
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
|
||||||
));
|
));
|
||||||
} else if let Some(delim) = kind.close_delim() {
|
} else if let Some(delim) = kind.close_delim() {
|
||||||
// If there's no matching opening delimiter, the token stream is malformed,
|
let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
|
||||||
// likely due to a improper delimiter positions in the source code.
|
|
||||||
// It's not delimiter mismatch, and lexer can not detect it, so we just ignore it here.
|
|
||||||
let Some(frame) = stack_rest.pop() else {
|
|
||||||
return AttrTokenStream::new(stack_top.inner);
|
|
||||||
};
|
|
||||||
let frame_data = mem::replace(&mut stack_top, frame);
|
|
||||||
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
|
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
open_delim.eq_ignoring_invisible_origin(&delim),
|
open_delim.eq_ignoring_invisible_origin(&delim),
|
||||||
|
|
|
||||||
|
|
@ -425,9 +425,8 @@ macro_rules! common_visitor_and_walkers {
|
||||||
ByRef,
|
ByRef,
|
||||||
Closure,
|
Closure,
|
||||||
Const,
|
Const,
|
||||||
ConstBlockItem,
|
|
||||||
ConstItem,
|
ConstItem,
|
||||||
ConstItemRhsKind,
|
ConstItemRhs,
|
||||||
Defaultness,
|
Defaultness,
|
||||||
Delegation,
|
Delegation,
|
||||||
DelegationMac,
|
DelegationMac,
|
||||||
|
|
@ -826,8 +825,6 @@ macro_rules! common_visitor_and_walkers {
|
||||||
visit_visitable!($($mut)? vis, use_tree),
|
visit_visitable!($($mut)? vis, use_tree),
|
||||||
ItemKind::Static(item) =>
|
ItemKind::Static(item) =>
|
||||||
visit_visitable!($($mut)? vis, item),
|
visit_visitable!($($mut)? vis, item),
|
||||||
ItemKind::ConstBlock(item) =>
|
|
||||||
visit_visitable!($($mut)? vis, item),
|
|
||||||
ItemKind::Const(item) =>
|
ItemKind::Const(item) =>
|
||||||
visit_visitable!($($mut)? vis, item),
|
visit_visitable!($($mut)? vis, item),
|
||||||
ItemKind::Mod(safety, ident, mod_kind) =>
|
ItemKind::Mod(safety, ident, mod_kind) =>
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
|
|
|
||||||
191
compiler/rustc_ast_lowering/messages.ftl
Normal file
191
compiler/rustc_ast_lowering/messages.ftl
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
ast_lowering_abi_specified_multiple_times =
|
||||||
|
`{$prev_name}` ABI specified multiple times
|
||||||
|
.label = previously specified here
|
||||||
|
.note = these ABIs are equivalent on the current target
|
||||||
|
|
||||||
|
ast_lowering_arbitrary_expression_in_pattern =
|
||||||
|
arbitrary expressions aren't allowed in patterns
|
||||||
|
.pattern_from_macro_note = the `expr` fragment specifier forces the metavariable's content to be an expression
|
||||||
|
.const_block_in_pattern_help = use a named `const`-item or an `if`-guard (`x if x == const {"{ ... }"}`) instead
|
||||||
|
|
||||||
|
ast_lowering_argument = argument
|
||||||
|
|
||||||
|
ast_lowering_assoc_ty_binding_in_dyn =
|
||||||
|
associated type bounds are not allowed in `dyn` types
|
||||||
|
.suggestion = use `impl Trait` to introduce a type instead
|
||||||
|
|
||||||
|
ast_lowering_assoc_ty_parentheses =
|
||||||
|
parenthesized generic arguments cannot be used in associated type constraints
|
||||||
|
|
||||||
|
ast_lowering_async_bound_not_on_trait =
|
||||||
|
`async` bound modifier only allowed on trait, not `{$descr}`
|
||||||
|
|
||||||
|
ast_lowering_async_bound_only_for_fn_traits =
|
||||||
|
`async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits
|
||||||
|
|
||||||
|
ast_lowering_async_coroutines_not_supported =
|
||||||
|
`async` coroutines are not yet supported
|
||||||
|
|
||||||
|
ast_lowering_att_syntax_only_x86 =
|
||||||
|
the `att_syntax` option is only supported on x86
|
||||||
|
|
||||||
|
ast_lowering_await_only_in_async_fn_and_blocks =
|
||||||
|
`await` is only allowed inside `async` functions and blocks
|
||||||
|
.label = only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
|
ast_lowering_bad_return_type_notation_inputs =
|
||||||
|
argument types not allowed with return type notation
|
||||||
|
.suggestion = remove the input types
|
||||||
|
|
||||||
|
ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..`
|
||||||
|
.suggestion = use the correct syntax by adding `..` to the arguments
|
||||||
|
|
||||||
|
ast_lowering_bad_return_type_notation_output =
|
||||||
|
return type not allowed with return type notation
|
||||||
|
ast_lowering_bad_return_type_notation_output_suggestion = use the right argument notation and remove the return type
|
||||||
|
|
||||||
|
ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet
|
||||||
|
|
||||||
|
ast_lowering_clobber_abi_not_supported =
|
||||||
|
`clobber_abi` is not supported on this target
|
||||||
|
|
||||||
|
ast_lowering_closure_cannot_be_static = closures cannot be static
|
||||||
|
|
||||||
|
ast_lowering_coroutine_too_many_parameters =
|
||||||
|
too many parameters for a coroutine (expected 0 or 1 parameters)
|
||||||
|
|
||||||
|
ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs
|
||||||
|
.label = default fields are only supported on structs
|
||||||
|
|
||||||
|
ast_lowering_delegation_cycle_in_signature_resolution = encountered a cycle during delegation signature resolution
|
||||||
|
ast_lowering_delegation_unresolved_callee = failed to resolve delegation callee
|
||||||
|
ast_lowering_does_not_support_modifiers =
|
||||||
|
the `{$class_name}` register class does not support template modifiers
|
||||||
|
|
||||||
|
ast_lowering_extra_double_dot =
|
||||||
|
`..` can only be used once per {$ctx} pattern
|
||||||
|
.label = can only be used once per {$ctx} pattern
|
||||||
|
|
||||||
|
ast_lowering_functional_record_update_destructuring_assignment =
|
||||||
|
functional record updates are not allowed in destructuring assignments
|
||||||
|
.suggestion = consider removing the trailing pattern
|
||||||
|
|
||||||
|
ast_lowering_generic_param_default_in_binder =
|
||||||
|
defaults for generic parameters are not allowed in `for<...>` binders
|
||||||
|
|
||||||
|
ast_lowering_generic_type_with_parentheses =
|
||||||
|
parenthesized type parameters may only be used with a `Fn` trait
|
||||||
|
.label = only `Fn` traits may use parentheses
|
||||||
|
|
||||||
|
ast_lowering_inclusive_range_with_no_end = inclusive range with no end
|
||||||
|
|
||||||
|
ast_lowering_inline_asm_unsupported_target =
|
||||||
|
inline assembly is unsupported on this target
|
||||||
|
|
||||||
|
ast_lowering_invalid_abi =
|
||||||
|
invalid ABI: found `{$abi}`
|
||||||
|
.label = invalid ABI
|
||||||
|
.note = invoke `{$command}` for a full list of supported calling conventions
|
||||||
|
|
||||||
|
ast_lowering_invalid_abi_clobber_abi =
|
||||||
|
invalid ABI for `clobber_abi`
|
||||||
|
.note = the following ABIs are supported on this target: {$supported_abis}
|
||||||
|
|
||||||
|
ast_lowering_invalid_abi_suggestion = there's a similarly named valid ABI `{$suggestion}`
|
||||||
|
|
||||||
|
ast_lowering_invalid_asm_template_modifier_const =
|
||||||
|
asm template modifiers are not allowed for `const` arguments
|
||||||
|
|
||||||
|
ast_lowering_invalid_asm_template_modifier_label =
|
||||||
|
asm template modifiers are not allowed for `label` arguments
|
||||||
|
|
||||||
|
ast_lowering_invalid_asm_template_modifier_reg_class =
|
||||||
|
invalid asm template modifier for this register class
|
||||||
|
|
||||||
|
ast_lowering_invalid_asm_template_modifier_sym =
|
||||||
|
asm template modifiers are not allowed for `sym` arguments
|
||||||
|
|
||||||
|
ast_lowering_invalid_legacy_const_generic_arg =
|
||||||
|
invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
|
||||||
|
|
||||||
|
ast_lowering_invalid_legacy_const_generic_arg_suggestion =
|
||||||
|
try using a const generic argument instead
|
||||||
|
|
||||||
|
ast_lowering_invalid_register =
|
||||||
|
invalid register `{$reg}`: {$error}
|
||||||
|
|
||||||
|
ast_lowering_invalid_register_class =
|
||||||
|
invalid register class `{$reg_class}`: unknown register class
|
||||||
|
.note = the following register classes are supported on this target: {$supported_register_classes}
|
||||||
|
|
||||||
|
ast_lowering_match_arm_with_no_body =
|
||||||
|
`match` arm with no body
|
||||||
|
.suggestion = add a body after the pattern
|
||||||
|
|
||||||
|
ast_lowering_misplaced_double_dot =
|
||||||
|
`..` patterns are not allowed here
|
||||||
|
.note = only allowed in tuple, tuple struct, and slice patterns
|
||||||
|
|
||||||
|
ast_lowering_misplaced_impl_trait =
|
||||||
|
`impl Trait` is not allowed in {$position}
|
||||||
|
.note = `impl Trait` is only allowed in arguments and return types of functions and methods
|
||||||
|
|
||||||
|
ast_lowering_never_pattern_with_body =
|
||||||
|
a never pattern is always unreachable
|
||||||
|
.label = this will never be executed
|
||||||
|
.suggestion = remove this expression
|
||||||
|
|
||||||
|
ast_lowering_never_pattern_with_guard =
|
||||||
|
a guard on a never pattern will never be run
|
||||||
|
.suggestion = remove this guard
|
||||||
|
|
||||||
|
ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
|
||||||
|
|
||||||
|
ast_lowering_previously_used_here = previously used here
|
||||||
|
|
||||||
|
ast_lowering_register1 = register `{$reg1_name}`
|
||||||
|
|
||||||
|
ast_lowering_register2 = register `{$reg2_name}`
|
||||||
|
|
||||||
|
ast_lowering_register_class_only_clobber =
|
||||||
|
register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
|
||||||
|
ast_lowering_register_class_only_clobber_stable =
|
||||||
|
register class `{$reg_class_name}` can only be used as a clobber in stable
|
||||||
|
|
||||||
|
ast_lowering_register_conflict =
|
||||||
|
register `{$reg1_name}` conflicts with register `{$reg2_name}`
|
||||||
|
.help = use `lateout` instead of `out` to avoid conflict
|
||||||
|
|
||||||
|
ast_lowering_remove_parentheses = remove these parentheses
|
||||||
|
|
||||||
|
ast_lowering_sub_tuple_binding =
|
||||||
|
`{$ident_name} @` is not allowed in a {$ctx}
|
||||||
|
.label = this is only allowed in slice patterns
|
||||||
|
.help = remove this and bind each tuple field independently
|
||||||
|
|
||||||
|
ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields
|
||||||
|
|
||||||
|
ast_lowering_support_modifiers =
|
||||||
|
the `{$class_name}` register class supports the following template modifiers: {$modifiers}
|
||||||
|
|
||||||
|
ast_lowering_template_modifier = template modifier
|
||||||
|
|
||||||
|
ast_lowering_this_not_async = this is not `async`
|
||||||
|
|
||||||
|
ast_lowering_underscore_expr_lhs_assign =
|
||||||
|
in expressions, `_` can only be used on the left-hand side of an assignment
|
||||||
|
.label = `_` not allowed here
|
||||||
|
|
||||||
|
ast_lowering_union_default_field_values = unions cannot have default field values
|
||||||
|
|
||||||
|
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
|
||||||
|
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
|
||||||
|
using both label and output operands for inline assembly is unstable
|
||||||
|
ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable
|
||||||
|
|
||||||
|
ast_lowering_use_angle_brackets = use angle brackets instead
|
||||||
|
|
||||||
|
ast_lowering_yield = yield syntax is experimental
|
||||||
|
ast_lowering_yield_in_closure =
|
||||||
|
`yield` can only be used in `#[coroutine]` closures, or `gen` blocks
|
||||||
|
.suggestion = use `#[coroutine]` to make this closure a coroutine
|
||||||
|
|
@ -3,7 +3,6 @@ use std::fmt::Write;
|
||||||
|
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||||
use rustc_errors::msg;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
|
|
@ -20,7 +19,8 @@ use super::errors::{
|
||||||
RegisterConflict,
|
RegisterConflict,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt,
|
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
|
||||||
|
ResolverAstLoweringExt, fluent_generated as fluent,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
@ -51,8 +51,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
| asm::InlineAsmArch::LoongArch32
|
| asm::InlineAsmArch::LoongArch32
|
||||||
| asm::InlineAsmArch::LoongArch64
|
| asm::InlineAsmArch::LoongArch64
|
||||||
| asm::InlineAsmArch::S390x
|
| asm::InlineAsmArch::S390x
|
||||||
| asm::InlineAsmArch::PowerPC
|
|
||||||
| asm::InlineAsmArch::PowerPC64
|
|
||||||
);
|
);
|
||||||
if !is_stable
|
if !is_stable
|
||||||
&& !self.tcx.features().asm_experimental_arch()
|
&& !self.tcx.features().asm_experimental_arch()
|
||||||
|
|
@ -67,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
&self.tcx.sess,
|
&self.tcx.sess,
|
||||||
sym::asm_experimental_arch,
|
sym::asm_experimental_arch,
|
||||||
sp,
|
sp,
|
||||||
msg!("inline assembly is not stable yet on this architecture"),
|
fluent::ast_lowering_unstable_inline_assembly,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +82,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
&self.tcx.sess,
|
&self.tcx.sess,
|
||||||
sym::asm_unwind,
|
sym::asm_unwind,
|
||||||
sp,
|
sp,
|
||||||
msg!("the `may_unwind` option is unstable"),
|
fluent::ast_lowering_unstable_may_unwind,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -499,7 +497,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
sess,
|
sess,
|
||||||
sym::asm_goto_with_outputs,
|
sym::asm_goto_with_outputs,
|
||||||
*op_sp,
|
*op_sp,
|
||||||
msg!("using both label and output operands for inline assembly is unstable"),
|
fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,21 +152,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
) -> DelegationResults<'hir> {
|
) -> DelegationResults<'hir> {
|
||||||
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
||||||
|
|
||||||
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
|
let ids = self.get_delegation_ids(
|
||||||
let ids = if let Some(delegation_info) =
|
self.resolver.delegation_infos[&self.local_def_id(item_id)].resolution_node,
|
||||||
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,
|
span,
|
||||||
format!("LoweringContext: the delegation {:?} is unresolved", item_id),
|
|
||||||
),
|
|
||||||
span,
|
|
||||||
delegation,
|
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
match ids {
|
match ids {
|
||||||
Ok(ids) => {
|
Ok(ids) => {
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_span::{Ident, Span, Symbol};
|
use rustc_span::{Ident, Span, Symbol};
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("parenthesized type parameters may only be used with a `Fn` trait", code = E0214)]
|
#[diag(ast_lowering_generic_type_with_parentheses, code = E0214)]
|
||||||
pub(crate) struct GenericTypeWithParentheses {
|
pub(crate) struct GenericTypeWithParentheses {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("only `Fn` traits may use parentheses")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub sub: Option<UseAngleBrackets>,
|
pub sub: Option<UseAngleBrackets>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion("use angle brackets instead", applicability = "maybe-incorrect")]
|
#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")]
|
||||||
pub(crate) struct UseAngleBrackets {
|
pub(crate) struct UseAngleBrackets {
|
||||||
#[suggestion_part(code = "<")]
|
#[suggestion_part(code = "<")]
|
||||||
pub open_param: Span,
|
pub open_param: Span,
|
||||||
|
|
@ -23,11 +23,11 @@ pub(crate) struct UseAngleBrackets {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid ABI: found `{$abi}`", code = E0703)]
|
#[diag(ast_lowering_invalid_abi, code = E0703)]
|
||||||
#[note("invoke `{$command}` for a full list of supported calling conventions")]
|
#[note]
|
||||||
pub(crate) struct InvalidAbi {
|
pub(crate) struct InvalidAbi {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("invalid ABI")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub abi: Symbol,
|
pub abi: Symbol,
|
||||||
pub command: String,
|
pub command: String,
|
||||||
|
|
@ -36,16 +36,16 @@ pub(crate) struct InvalidAbi {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("default fields are not supported in tuple structs")]
|
#[diag(ast_lowering_default_field_in_tuple)]
|
||||||
pub(crate) struct TupleStructWithDefault {
|
pub(crate) struct TupleStructWithDefault {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("default fields are only supported on structs")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
"there's a similarly named valid ABI `{$suggestion}`",
|
ast_lowering_invalid_abi_suggestion,
|
||||||
code = "\"{suggestion}\"",
|
code = "\"{suggestion}\"",
|
||||||
applicability = "maybe-incorrect",
|
applicability = "maybe-incorrect",
|
||||||
style = "verbose"
|
style = "verbose"
|
||||||
|
|
@ -57,7 +57,7 @@ pub(crate) struct InvalidAbiSuggestion {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("parenthesized generic arguments cannot be used in associated type constraints")]
|
#[diag(ast_lowering_assoc_ty_parentheses)]
|
||||||
pub(crate) struct AssocTyParentheses {
|
pub(crate) struct AssocTyParentheses {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -67,12 +67,12 @@ pub(crate) struct AssocTyParentheses {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum AssocTyParenthesesSub {
|
pub(crate) enum AssocTyParenthesesSub {
|
||||||
#[multipart_suggestion("remove these parentheses")]
|
#[multipart_suggestion(ast_lowering_remove_parentheses)]
|
||||||
Empty {
|
Empty {
|
||||||
#[suggestion_part(code = "")]
|
#[suggestion_part(code = "")]
|
||||||
parentheses_span: Span,
|
parentheses_span: Span,
|
||||||
},
|
},
|
||||||
#[multipart_suggestion("use angle brackets instead")]
|
#[multipart_suggestion(ast_lowering_use_angle_brackets)]
|
||||||
NotEmpty {
|
NotEmpty {
|
||||||
#[suggestion_part(code = "<")]
|
#[suggestion_part(code = "<")]
|
||||||
open_param: Span,
|
open_param: Span,
|
||||||
|
|
@ -82,8 +82,8 @@ pub(crate) enum AssocTyParenthesesSub {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`impl Trait` is not allowed in {$position}", code = E0562)]
|
#[diag(ast_lowering_misplaced_impl_trait, code = E0562)]
|
||||||
#[note("`impl Trait` is only allowed in arguments and return types of functions and methods")]
|
#[note]
|
||||||
pub(crate) struct MisplacedImplTrait<'a> {
|
pub(crate) struct MisplacedImplTrait<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -91,106 +91,97 @@ pub(crate) struct MisplacedImplTrait<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("associated type bounds are not allowed in `dyn` types")]
|
#[diag(ast_lowering_assoc_ty_binding_in_dyn)]
|
||||||
pub(crate) struct MisplacedAssocTyBinding {
|
pub(crate) struct MisplacedAssocTyBinding {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[suggestion(
|
#[suggestion(code = " = impl", applicability = "maybe-incorrect", style = "verbose")]
|
||||||
"use `impl Trait` to introduce a type instead",
|
|
||||||
code = " = impl",
|
|
||||||
applicability = "maybe-incorrect",
|
|
||||||
style = "verbose"
|
|
||||||
)]
|
|
||||||
pub suggestion: Option<Span>,
|
pub suggestion: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("in expressions, `_` can only be used on the left-hand side of an assignment")]
|
#[diag(ast_lowering_underscore_expr_lhs_assign)]
|
||||||
pub(crate) struct UnderscoreExprLhsAssign {
|
pub(crate) struct UnderscoreExprLhsAssign {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("`_` not allowed here")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`await` is only allowed inside `async` functions and blocks", code = E0728)]
|
#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)]
|
||||||
pub(crate) struct AwaitOnlyInAsyncFnAndBlocks {
|
pub(crate) struct AwaitOnlyInAsyncFnAndBlocks {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("only allowed inside `async` functions and blocks")]
|
#[label]
|
||||||
pub await_kw_span: Span,
|
pub await_kw_span: Span,
|
||||||
#[label("this is not `async`")]
|
#[label(ast_lowering_this_not_async)]
|
||||||
pub item_span: Option<Span>,
|
pub item_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("too many parameters for a coroutine (expected 0 or 1 parameters)", code = E0628)]
|
#[diag(ast_lowering_coroutine_too_many_parameters, code = E0628)]
|
||||||
pub(crate) struct CoroutineTooManyParameters {
|
pub(crate) struct CoroutineTooManyParameters {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub fn_decl_span: Span,
|
pub fn_decl_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("closures cannot be static", code = E0697)]
|
#[diag(ast_lowering_closure_cannot_be_static, code = E0697)]
|
||||||
pub(crate) struct ClosureCannotBeStatic {
|
pub(crate) struct ClosureCannotBeStatic {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub fn_decl_span: Span,
|
pub fn_decl_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("functional record updates are not allowed in destructuring assignments")]
|
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||||
pub(crate) struct FunctionalRecordUpdateDestructuringAssignment {
|
pub(crate) struct FunctionalRecordUpdateDestructuringAssignment {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion(
|
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||||
"consider removing the trailing pattern",
|
|
||||||
code = "",
|
|
||||||
applicability = "machine-applicable"
|
|
||||||
)]
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`async` coroutines are not yet supported", code = E0727)]
|
#[diag(ast_lowering_async_coroutines_not_supported, code = E0727)]
|
||||||
pub(crate) struct AsyncCoroutinesNotSupported {
|
pub(crate) struct AsyncCoroutinesNotSupported {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("inline assembly is unsupported on this target", code = E0472)]
|
#[diag(ast_lowering_inline_asm_unsupported_target, code = E0472)]
|
||||||
pub(crate) struct InlineAsmUnsupportedTarget {
|
pub(crate) struct InlineAsmUnsupportedTarget {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("the `att_syntax` option is only supported on x86")]
|
#[diag(ast_lowering_att_syntax_only_x86)]
|
||||||
pub(crate) struct AttSyntaxOnlyX86 {
|
pub(crate) struct AttSyntaxOnlyX86 {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`{$prev_name}` ABI specified multiple times")]
|
#[diag(ast_lowering_abi_specified_multiple_times)]
|
||||||
pub(crate) struct AbiSpecifiedMultipleTimes {
|
pub(crate) struct AbiSpecifiedMultipleTimes {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub abi_span: Span,
|
pub abi_span: Span,
|
||||||
pub prev_name: Symbol,
|
pub prev_name: Symbol,
|
||||||
#[label("previously specified here")]
|
#[label]
|
||||||
pub prev_span: Span,
|
pub prev_span: Span,
|
||||||
#[note("these ABIs are equivalent on the current target")]
|
#[note]
|
||||||
pub equivalent: bool,
|
pub equivalent: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`clobber_abi` is not supported on this target")]
|
#[diag(ast_lowering_clobber_abi_not_supported)]
|
||||||
pub(crate) struct ClobberAbiNotSupported {
|
pub(crate) struct ClobberAbiNotSupported {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub abi_span: Span,
|
pub abi_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[note("the following ABIs are supported on this target: {$supported_abis}")]
|
#[note]
|
||||||
#[diag("invalid ABI for `clobber_abi`")]
|
#[diag(ast_lowering_invalid_abi_clobber_abi)]
|
||||||
pub(crate) struct InvalidAbiClobberAbi {
|
pub(crate) struct InvalidAbiClobberAbi {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub abi_span: Span,
|
pub abi_span: Span,
|
||||||
|
|
@ -198,7 +189,7 @@ pub(crate) struct InvalidAbiClobberAbi {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid register `{$reg}`: {$error}")]
|
#[diag(ast_lowering_invalid_register)]
|
||||||
pub(crate) struct InvalidRegister<'a> {
|
pub(crate) struct InvalidRegister<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
|
|
@ -207,10 +198,8 @@ pub(crate) struct InvalidRegister<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[note(
|
#[note]
|
||||||
"the following register classes are supported on this target: {$supported_register_classes}"
|
#[diag(ast_lowering_invalid_register_class)]
|
||||||
)]
|
|
||||||
#[diag("invalid register class `{$reg_class}`: unknown register class")]
|
|
||||||
pub(crate) struct InvalidRegisterClass {
|
pub(crate) struct InvalidRegisterClass {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
|
|
@ -219,12 +208,12 @@ pub(crate) struct InvalidRegisterClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid asm template modifier for this register class")]
|
#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)]
|
||||||
pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("template modifier")]
|
#[label(ast_lowering_template_modifier)]
|
||||||
pub placeholder_span: Span,
|
pub placeholder_span: Span,
|
||||||
#[label("argument")]
|
#[label(ast_lowering_argument)]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub sub: InvalidAsmTemplateModifierRegClassSub,
|
pub sub: InvalidAsmTemplateModifierRegClassSub,
|
||||||
|
|
@ -232,48 +221,44 @@ pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum InvalidAsmTemplateModifierRegClassSub {
|
pub(crate) enum InvalidAsmTemplateModifierRegClassSub {
|
||||||
#[note(
|
#[note(ast_lowering_support_modifiers)]
|
||||||
"the `{$class_name}` register class supports the following template modifiers: {$modifiers}"
|
|
||||||
)]
|
|
||||||
SupportModifier { class_name: Symbol, modifiers: String },
|
SupportModifier { class_name: Symbol, modifiers: String },
|
||||||
#[note("the `{$class_name}` register class does not support template modifiers")]
|
#[note(ast_lowering_does_not_support_modifiers)]
|
||||||
DoesNotSupportModifier { class_name: Symbol },
|
DoesNotSupportModifier { class_name: Symbol },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("asm template modifiers are not allowed for `const` arguments")]
|
#[diag(ast_lowering_invalid_asm_template_modifier_const)]
|
||||||
pub(crate) struct InvalidAsmTemplateModifierConst {
|
pub(crate) struct InvalidAsmTemplateModifierConst {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("template modifier")]
|
#[label(ast_lowering_template_modifier)]
|
||||||
pub placeholder_span: Span,
|
pub placeholder_span: Span,
|
||||||
#[label("argument")]
|
#[label(ast_lowering_argument)]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("asm template modifiers are not allowed for `sym` arguments")]
|
#[diag(ast_lowering_invalid_asm_template_modifier_sym)]
|
||||||
pub(crate) struct InvalidAsmTemplateModifierSym {
|
pub(crate) struct InvalidAsmTemplateModifierSym {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("template modifier")]
|
#[label(ast_lowering_template_modifier)]
|
||||||
pub placeholder_span: Span,
|
pub placeholder_span: Span,
|
||||||
#[label("argument")]
|
#[label(ast_lowering_argument)]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("asm template modifiers are not allowed for `label` arguments")]
|
#[diag(ast_lowering_invalid_asm_template_modifier_label)]
|
||||||
pub(crate) struct InvalidAsmTemplateModifierLabel {
|
pub(crate) struct InvalidAsmTemplateModifierLabel {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("template modifier")]
|
#[label(ast_lowering_template_modifier)]
|
||||||
pub placeholder_span: Span,
|
pub placeholder_span: Span,
|
||||||
#[label("argument")]
|
#[label(ast_lowering_argument)]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(
|
#[diag(ast_lowering_register_class_only_clobber)]
|
||||||
"register class `{$reg_class_name}` can only be used as a clobber, not as an input or output"
|
|
||||||
)]
|
|
||||||
pub(crate) struct RegisterClassOnlyClobber {
|
pub(crate) struct RegisterClassOnlyClobber {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
|
|
@ -281,7 +266,7 @@ pub(crate) struct RegisterClassOnlyClobber {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("register class `{$reg_class_name}` can only be used as a clobber in stable")]
|
#[diag(ast_lowering_register_class_only_clobber_stable)]
|
||||||
pub(crate) struct RegisterClassOnlyClobberStable {
|
pub(crate) struct RegisterClassOnlyClobberStable {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
|
|
@ -289,27 +274,27 @@ pub(crate) struct RegisterClassOnlyClobberStable {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("register `{$reg1_name}` conflicts with register `{$reg2_name}`")]
|
#[diag(ast_lowering_register_conflict)]
|
||||||
pub(crate) struct RegisterConflict<'a> {
|
pub(crate) struct RegisterConflict<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("register `{$reg1_name}`")]
|
#[label(ast_lowering_register1)]
|
||||||
pub op_span1: Span,
|
pub op_span1: Span,
|
||||||
#[label("register `{$reg2_name}`")]
|
#[label(ast_lowering_register2)]
|
||||||
pub op_span2: Span,
|
pub op_span2: Span,
|
||||||
pub reg1_name: &'a str,
|
pub reg1_name: &'a str,
|
||||||
pub reg2_name: &'a str,
|
pub reg2_name: &'a str,
|
||||||
#[help("use `lateout` instead of `out` to avoid conflict")]
|
#[help]
|
||||||
pub in_out: Option<Span>,
|
pub in_out: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[help("remove this and bind each tuple field independently")]
|
#[help]
|
||||||
#[diag("`{$ident_name} @` is not allowed in a {$ctx}")]
|
#[diag(ast_lowering_sub_tuple_binding)]
|
||||||
pub(crate) struct SubTupleBinding<'a> {
|
pub(crate) struct SubTupleBinding<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("this is only allowed in slice patterns")]
|
#[label]
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
"if you don't need to use the contents of {$ident}, discard the tuple's remaining fields",
|
ast_lowering_sub_tuple_binding_suggestion,
|
||||||
style = "verbose",
|
style = "verbose",
|
||||||
code = "..",
|
code = "..",
|
||||||
applicability = "maybe-incorrect"
|
applicability = "maybe-incorrect"
|
||||||
|
|
@ -321,67 +306,63 @@ pub(crate) struct SubTupleBinding<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`..` can only be used once per {$ctx} pattern")]
|
#[diag(ast_lowering_extra_double_dot)]
|
||||||
pub(crate) struct ExtraDoubleDot<'a> {
|
pub(crate) struct ExtraDoubleDot<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("can only be used once per {$ctx} pattern")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[label("previously used here")]
|
#[label(ast_lowering_previously_used_here)]
|
||||||
pub prev_span: Span,
|
pub prev_span: Span,
|
||||||
pub ctx: &'a str,
|
pub ctx: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[note("only allowed in tuple, tuple struct, and slice patterns")]
|
#[note]
|
||||||
#[diag("`..` patterns are not allowed here")]
|
#[diag(ast_lowering_misplaced_double_dot)]
|
||||||
pub(crate) struct MisplacedDoubleDot {
|
pub(crate) struct MisplacedDoubleDot {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`match` arm with no body")]
|
#[diag(ast_lowering_match_arm_with_no_body)]
|
||||||
pub(crate) struct MatchArmWithNoBody {
|
pub(crate) struct MatchArmWithNoBody {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[suggestion(
|
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
|
||||||
"add a body after the pattern",
|
|
||||||
code = " => todo!(),",
|
|
||||||
applicability = "has-placeholders"
|
|
||||||
)]
|
|
||||||
pub suggestion: Span,
|
pub suggestion: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("a never pattern is always unreachable")]
|
#[diag(ast_lowering_never_pattern_with_body)]
|
||||||
pub(crate) struct NeverPatternWithBody {
|
pub(crate) struct NeverPatternWithBody {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("this will never be executed")]
|
#[label]
|
||||||
#[suggestion("remove this expression", code = "", applicability = "maybe-incorrect")]
|
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("a guard on a never pattern will never be run")]
|
#[diag(ast_lowering_never_pattern_with_guard)]
|
||||||
pub(crate) struct NeverPatternWithGuard {
|
pub(crate) struct NeverPatternWithGuard {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion("remove this guard", code = "", applicability = "maybe-incorrect")]
|
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("arbitrary expressions aren't allowed in patterns")]
|
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
|
||||||
pub(crate) struct ArbitraryExpressionInPattern {
|
pub(crate) struct ArbitraryExpressionInPattern {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[note("the `expr` fragment specifier forces the metavariable's content to be an expression")]
|
#[note(ast_lowering_pattern_from_macro_note)]
|
||||||
pub pattern_from_macro_note: bool,
|
pub pattern_from_macro_note: bool,
|
||||||
#[help("use a named `const`-item or an `if`-guard (`x if x == const {\"{ ... }\"}`) instead")]
|
#[help(ast_lowering_const_block_in_pattern_help)]
|
||||||
pub const_block_in_pattern_help: bool,
|
pub const_block_in_pattern_help: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("inclusive range with no end")]
|
#[diag(ast_lowering_inclusive_range_with_no_end)]
|
||||||
pub(crate) struct InclusiveRangeWithNoEnd {
|
pub(crate) struct InclusiveRangeWithNoEnd {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -389,7 +370,7 @@ pub(crate) struct InclusiveRangeWithNoEnd {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(
|
||||||
"use the right argument notation and remove the return type",
|
ast_lowering_bad_return_type_notation_output_suggestion,
|
||||||
applicability = "machine-applicable",
|
applicability = "machine-applicable",
|
||||||
style = "verbose"
|
style = "verbose"
|
||||||
)]
|
)]
|
||||||
|
|
@ -403,36 +384,26 @@ pub(crate) struct RTNSuggestion {
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
pub(crate) enum BadReturnTypeNotation {
|
pub(crate) enum BadReturnTypeNotation {
|
||||||
#[diag("argument types not allowed with return type notation")]
|
#[diag(ast_lowering_bad_return_type_notation_inputs)]
|
||||||
Inputs {
|
Inputs {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion(
|
#[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
|
||||||
"remove the input types",
|
|
||||||
code = "(..)",
|
|
||||||
applicability = "machine-applicable",
|
|
||||||
style = "verbose"
|
|
||||||
)]
|
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[diag("return type not allowed with return type notation")]
|
#[diag(ast_lowering_bad_return_type_notation_output)]
|
||||||
Output {
|
Output {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
suggestion: RTNSuggestion,
|
suggestion: RTNSuggestion,
|
||||||
},
|
},
|
||||||
#[diag("return type notation arguments must be elided with `..`")]
|
#[diag(ast_lowering_bad_return_type_notation_needs_dots)]
|
||||||
NeedsDots {
|
NeedsDots {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion(
|
#[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
|
||||||
"use the correct syntax by adding `..` to the arguments",
|
|
||||||
code = "(..)",
|
|
||||||
applicability = "machine-applicable",
|
|
||||||
style = "verbose"
|
|
||||||
)]
|
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[diag("return type notation not allowed in this position yet")]
|
#[diag(ast_lowering_bad_return_type_notation_position)]
|
||||||
Position {
|
Position {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -440,14 +411,14 @@ pub(crate) enum BadReturnTypeNotation {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("defaults for generic parameters are not allowed in `for<...>` binders")]
|
#[diag(ast_lowering_generic_param_default_in_binder)]
|
||||||
pub(crate) struct GenericParamDefaultInBinder {
|
pub(crate) struct GenericParamDefaultInBinder {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`async` bound modifier only allowed on trait, not `{$descr}`")]
|
#[diag(ast_lowering_async_bound_not_on_trait)]
|
||||||
pub(crate) struct AsyncBoundNotOnTrait {
|
pub(crate) struct AsyncBoundNotOnTrait {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -455,37 +426,30 @@ pub(crate) struct AsyncBoundNotOnTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits")]
|
#[diag(ast_lowering_async_bound_only_for_fn_traits)]
|
||||||
pub(crate) struct AsyncBoundOnlyForFnTraits {
|
pub(crate) struct AsyncBoundOnlyForFnTraits {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`use<...>` precise capturing syntax not allowed in argument-position `impl Trait`")]
|
#[diag(ast_lowering_no_precise_captures_on_apit)]
|
||||||
pub(crate) struct NoPreciseCapturesOnApit {
|
pub(crate) struct NoPreciseCapturesOnApit {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`yield` can only be used in `#[coroutine]` closures, or `gen` blocks")]
|
#[diag(ast_lowering_yield_in_closure)]
|
||||||
pub(crate) struct YieldInClosure {
|
pub(crate) struct YieldInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[suggestion(
|
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
|
||||||
"use `#[coroutine]` to make this closure a coroutine",
|
|
||||||
code = "#[coroutine] ",
|
|
||||||
applicability = "maybe-incorrect",
|
|
||||||
style = "verbose"
|
|
||||||
)]
|
|
||||||
pub suggestion: Option<Span>,
|
pub suggestion: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(
|
#[diag(ast_lowering_invalid_legacy_const_generic_arg)]
|
||||||
"invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items"
|
|
||||||
)]
|
|
||||||
pub(crate) struct InvalidLegacyConstGenericArg {
|
pub(crate) struct InvalidLegacyConstGenericArg {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -495,7 +459,7 @@ pub(crate) struct InvalidLegacyConstGenericArg {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(
|
||||||
"try using a const generic argument instead",
|
ast_lowering_invalid_legacy_const_generic_arg_suggestion,
|
||||||
applicability = "maybe-incorrect"
|
applicability = "maybe-incorrect"
|
||||||
)]
|
)]
|
||||||
pub(crate) struct UseConstGenericArg {
|
pub(crate) struct UseConstGenericArg {
|
||||||
|
|
@ -508,21 +472,21 @@ pub(crate) struct UseConstGenericArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("unions cannot have default field values")]
|
#[diag(ast_lowering_union_default_field_values)]
|
||||||
pub(crate) struct UnionWithDefault {
|
pub(crate) struct UnionWithDefault {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("failed to resolve delegation callee")]
|
#[diag(ast_lowering_delegation_unresolved_callee)]
|
||||||
pub(crate) struct UnresolvedDelegationCallee {
|
pub(crate) struct UnresolvedDelegationCallee {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("encountered a cycle during delegation signature resolution")]
|
#[diag(ast_lowering_delegation_cycle_in_signature_resolution)]
|
||||||
pub(crate) struct CycleInDelegationSignatureResolution {
|
pub(crate) struct CycleInDelegationSignatureResolution {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ use std::sync::Arc;
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_ast_pretty::pprust::expr_to_string;
|
use rustc_ast_pretty::pprust::expr_to_string;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::msg;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::attrs::AttributeKind;
|
use rustc_hir::attrs::AttributeKind;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
|
@ -29,7 +28,9 @@ use super::{
|
||||||
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||||
};
|
};
|
||||||
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
||||||
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope};
|
use crate::{
|
||||||
|
AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope, fluent_generated,
|
||||||
|
};
|
||||||
|
|
||||||
struct WillCreateDefIdsVisitor {}
|
struct WillCreateDefIdsVisitor {}
|
||||||
|
|
||||||
|
|
@ -966,14 +967,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
||||||
this.arena.alloc(this.expr(gen_future_span, expr_break))
|
this.arena.alloc(this.expr(gen_future_span, expr_break))
|
||||||
});
|
});
|
||||||
self.arm(ready_pat, break_x, span)
|
self.arm(ready_pat, break_x)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `::std::task::Poll::Pending => {}`
|
// `::std::task::Poll::Pending => {}`
|
||||||
let pending_arm = {
|
let pending_arm = {
|
||||||
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
|
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
|
||||||
let empty_block = self.expr_block_empty(span);
|
let empty_block = self.expr_block_empty(span);
|
||||||
self.arm(pending_pat, empty_block, span)
|
self.arm(pending_pat, empty_block)
|
||||||
};
|
};
|
||||||
|
|
||||||
let inner_match_stmt = {
|
let inner_match_stmt = {
|
||||||
|
|
@ -1027,7 +1028,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// mut __awaitee => loop { ... }
|
// mut __awaitee => loop { ... }
|
||||||
let awaitee_arm = self.arm(awaitee_pat, loop_expr, span);
|
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
|
||||||
|
|
||||||
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
|
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
|
||||||
let into_future_expr = match await_kind {
|
let into_future_expr = match await_kind {
|
||||||
|
|
@ -1702,7 +1703,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&self.tcx.sess,
|
&self.tcx.sess,
|
||||||
sym::yield_expr,
|
sym::yield_expr,
|
||||||
span,
|
span,
|
||||||
msg!("yield syntax is experimental"),
|
fluent_generated::ast_lowering_yield,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -1817,7 +1818,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let break_expr =
|
let break_expr =
|
||||||
self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
|
self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
|
||||||
let pat = self.pat_none(for_span);
|
let pat = self.pat_none(for_span);
|
||||||
self.arm(pat, break_expr, for_span)
|
self.arm(pat, break_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Some(<pat>) => <body>,
|
// Some(<pat>) => <body>,
|
||||||
|
|
@ -1826,7 +1827,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let body_block =
|
let body_block =
|
||||||
self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
|
self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
|
||||||
let body_expr = self.arena.alloc(self.expr_block(body_block));
|
let body_expr = self.arena.alloc(self.expr_block(body_block));
|
||||||
self.arm(some_pat, body_expr, for_span)
|
self.arm(some_pat, body_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `mut iter`
|
// `mut iter`
|
||||||
|
|
@ -1885,7 +1886,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });
|
let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });
|
||||||
|
|
||||||
// `mut iter => { ... }`
|
// `mut iter => { ... }`
|
||||||
let iter_arm = self.arm(iter_pat, loop_expr, for_span);
|
let iter_arm = self.arm(iter_pat, loop_expr);
|
||||||
|
|
||||||
let match_expr = match loop_kind {
|
let match_expr = match loop_kind {
|
||||||
ForLoopKind::For => {
|
ForLoopKind::For => {
|
||||||
|
|
@ -1930,7 +1931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir::LangItem::IntoAsyncIterIntoIter,
|
hir::LangItem::IntoAsyncIterIntoIter,
|
||||||
arena_vec![self; head],
|
arena_vec![self; head],
|
||||||
);
|
);
|
||||||
let iter_arm = self.arm(async_iter_pat, inner_match_expr, for_span);
|
let iter_arm = self.arm(async_iter_pat, inner_match_expr);
|
||||||
self.arena.alloc(self.expr_match(
|
self.arena.alloc(self.expr_match(
|
||||||
for_span,
|
for_span,
|
||||||
iter,
|
iter,
|
||||||
|
|
@ -1997,7 +1998,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
|
let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
|
||||||
self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);
|
self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);
|
||||||
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
|
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
|
||||||
self.arm(continue_pat, val_expr, try_span)
|
self.arm(continue_pat, val_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `ControlFlow::Break(residual) =>
|
// `ControlFlow::Break(residual) =>
|
||||||
|
|
@ -2040,7 +2041,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression);
|
self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression);
|
||||||
|
|
||||||
let break_pat = self.pat_cf_break(try_span, residual_local);
|
let break_pat = self.pat_cf_break(try_span, residual_local);
|
||||||
self.arm(break_pat, ret_expr, try_span)
|
self.arm(break_pat, ret_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
hir::ExprKind::Match(
|
hir::ExprKind::Match(
|
||||||
|
|
@ -2368,13 +2369,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&mut self,
|
&mut self,
|
||||||
pat: &'hir hir::Pat<'hir>,
|
pat: &'hir hir::Pat<'hir>,
|
||||||
expr: &'hir hir::Expr<'hir>,
|
expr: &'hir hir::Expr<'hir>,
|
||||||
span: Span,
|
|
||||||
) -> hir::Arm<'hir> {
|
) -> hir::Arm<'hir> {
|
||||||
hir::Arm {
|
hir::Arm {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
pat,
|
pat,
|
||||||
guard: None,
|
guard: None,
|
||||||
span: self.lower_span(span),
|
span: self.lower_span(expr.span),
|
||||||
body: expr,
|
body: expr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
| ItemKind::Use(..)
|
| ItemKind::Use(..)
|
||||||
| ItemKind::Static(..)
|
| ItemKind::Static(..)
|
||||||
| ItemKind::Const(..)
|
| ItemKind::Const(..)
|
||||||
| ItemKind::ConstBlock(..)
|
|
||||||
| ItemKind::Mod(..)
|
| ItemKind::Mod(..)
|
||||||
| ItemKind::ForeignMod(..)
|
| ItemKind::ForeignMod(..)
|
||||||
| ItemKind::GlobalAsm(..)
|
| ItemKind::GlobalAsm(..)
|
||||||
|
|
@ -283,13 +282,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.lower_define_opaque(hir_id, define_opaque);
|
self.lower_define_opaque(hir_id, define_opaque);
|
||||||
hir::ItemKind::Static(*m, ident, ty, body_id)
|
hir::ItemKind::Static(*m, ident, ty, body_id)
|
||||||
}
|
}
|
||||||
ItemKind::Const(box ConstItem {
|
ItemKind::Const(box ast::ConstItem {
|
||||||
defaultness: _,
|
ident, generics, ty, rhs, define_opaque, ..
|
||||||
ident,
|
|
||||||
generics,
|
|
||||||
ty,
|
|
||||||
rhs_kind,
|
|
||||||
define_opaque,
|
|
||||||
}) => {
|
}) => {
|
||||||
let ident = self.lower_ident(*ident);
|
let ident = self.lower_ident(*ident);
|
||||||
let (generics, (ty, rhs)) = self.lower_generics(
|
let (generics, (ty, rhs)) = self.lower_generics(
|
||||||
|
|
@ -301,26 +295,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ty,
|
ty,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||||
);
|
);
|
||||||
let rhs = this.lower_const_item_rhs(rhs_kind, span);
|
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
|
||||||
(ty, rhs)
|
(ty, rhs)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.lower_define_opaque(hir_id, &define_opaque);
|
self.lower_define_opaque(hir_id, &define_opaque);
|
||||||
hir::ItemKind::Const(ident, generics, ty, rhs)
|
hir::ItemKind::Const(ident, generics, ty, rhs)
|
||||||
}
|
}
|
||||||
ItemKind::ConstBlock(ConstBlockItem { span, id, block }) => hir::ItemKind::Const(
|
|
||||||
self.lower_ident(ConstBlockItem::IDENT),
|
|
||||||
hir::Generics::empty(),
|
|
||||||
self.arena.alloc(self.ty_tup(DUMMY_SP, &[])),
|
|
||||||
hir::ConstItemRhs::Body({
|
|
||||||
let body = hir::Expr {
|
|
||||||
hir_id: self.lower_node_id(*id),
|
|
||||||
kind: hir::ExprKind::Block(self.lower_block(block, false), None),
|
|
||||||
span: self.lower_span(*span),
|
|
||||||
};
|
|
||||||
self.record_body(&[], body)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
ItemKind::Fn(box Fn {
|
ItemKind::Fn(box Fn {
|
||||||
sig: FnSig { decl, header, span: fn_sig_span },
|
sig: FnSig { decl, header, span: fn_sig_span },
|
||||||
ident,
|
ident,
|
||||||
|
|
@ -827,10 +808,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir_id,
|
hir_id,
|
||||||
def_id: self.local_def_id(v.id),
|
def_id: self.local_def_id(v.id),
|
||||||
data: self.lower_variant_data(hir_id, item_kind, &v.data),
|
data: self.lower_variant_data(hir_id, item_kind, &v.data),
|
||||||
disr_expr: v
|
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
|
||||||
.disr_expr
|
|
||||||
.as_ref()
|
|
||||||
.map(|e| self.lower_anon_const_to_anon_const(e, e.value.span)),
|
|
||||||
ident: self.lower_ident(v.ident),
|
ident: self.lower_ident(v.ident),
|
||||||
span: self.lower_span(v.span),
|
span: self.lower_span(v.span),
|
||||||
}
|
}
|
||||||
|
|
@ -920,10 +898,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
|
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
|
||||||
},
|
},
|
||||||
vis_span: self.lower_span(f.vis.span),
|
vis_span: self.lower_span(f.vis.span),
|
||||||
default: f
|
default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)),
|
||||||
.default
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| self.lower_anon_const_to_anon_const(v, v.value.span)),
|
|
||||||
ty,
|
ty,
|
||||||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||||
}
|
}
|
||||||
|
|
@ -939,14 +914,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
let trait_item_def_id = hir_id.expect_owner();
|
let trait_item_def_id = hir_id.expect_owner();
|
||||||
|
|
||||||
let (ident, generics, kind, has_value) = match &i.kind {
|
let (ident, generics, kind, has_default) = match &i.kind {
|
||||||
AssocItemKind::Const(box ConstItem {
|
AssocItemKind::Const(box ConstItem {
|
||||||
ident,
|
ident, generics, ty, rhs, define_opaque, ..
|
||||||
generics,
|
|
||||||
ty,
|
|
||||||
rhs_kind,
|
|
||||||
define_opaque,
|
|
||||||
..
|
|
||||||
}) => {
|
}) => {
|
||||||
let (generics, kind) = self.lower_generics(
|
let (generics, kind) = self.lower_generics(
|
||||||
generics,
|
generics,
|
||||||
|
|
@ -957,18 +927,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ty,
|
ty,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||||
);
|
);
|
||||||
// Trait associated consts don't need an expression/body.
|
let rhs = rhs
|
||||||
let rhs = if rhs_kind.has_expr() {
|
.as_ref()
|
||||||
Some(this.lower_const_item_rhs(rhs_kind, i.span))
|
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
|
||||||
} else {
|
hir::TraitItemKind::Const(ty, rhs)
|
||||||
None
|
|
||||||
};
|
|
||||||
hir::TraitItemKind::Const(ty, rhs, rhs_kind.is_type_const().into())
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if define_opaque.is_some() {
|
if define_opaque.is_some() {
|
||||||
if rhs_kind.has_expr() {
|
if rhs.is_some() {
|
||||||
self.lower_define_opaque(hir_id, &define_opaque);
|
self.lower_define_opaque(hir_id, &define_opaque);
|
||||||
} else {
|
} else {
|
||||||
self.dcx().span_err(
|
self.dcx().span_err(
|
||||||
|
|
@ -978,7 +945,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(*ident, generics, kind, rhs_kind.has_expr())
|
(*ident, generics, kind, rhs.is_some())
|
||||||
}
|
}
|
||||||
AssocItemKind::Fn(box Fn {
|
AssocItemKind::Fn(box Fn {
|
||||||
sig, ident, generics, body: None, define_opaque, ..
|
sig, ident, generics, body: None, define_opaque, ..
|
||||||
|
|
@ -1088,17 +1055,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value, || {
|
|
||||||
hir::Defaultness::Default { has_value }
|
|
||||||
});
|
|
||||||
|
|
||||||
let item = hir::TraitItem {
|
let item = hir::TraitItem {
|
||||||
owner_id: trait_item_def_id,
|
owner_id: trait_item_def_id,
|
||||||
ident: self.lower_ident(ident),
|
ident: self.lower_ident(ident),
|
||||||
generics,
|
generics,
|
||||||
kind,
|
kind,
|
||||||
span: self.lower_span(i.span),
|
span: self.lower_span(i.span),
|
||||||
defaultness,
|
defaultness: hir::Defaultness::Default { has_value: has_default },
|
||||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||||
};
|
};
|
||||||
self.arena.alloc(item)
|
self.arena.alloc(item)
|
||||||
|
|
@ -1126,8 +1089,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
||||||
// to not cause an assertion failure inside the `lower_defaultness` function.
|
// to not cause an assertion failure inside the `lower_defaultness` function.
|
||||||
let has_val = true;
|
let has_val = true;
|
||||||
let (defaultness, defaultness_span) =
|
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
|
||||||
self.lower_defaultness(defaultness, has_val, || hir::Defaultness::Final);
|
|
||||||
let modifiers = TraitBoundModifiers {
|
let modifiers = TraitBoundModifiers {
|
||||||
constness: BoundConstness::Never,
|
constness: BoundConstness::Never,
|
||||||
asyncness: BoundAsyncness::Normal,
|
asyncness: BoundAsyncness::Normal,
|
||||||
|
|
@ -1156,8 +1118,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
) -> &'hir hir::ImplItem<'hir> {
|
) -> &'hir hir::ImplItem<'hir> {
|
||||||
// Since `default impl` is not yet implemented, this is always true in impls.
|
// Since `default impl` is not yet implemented, this is always true in impls.
|
||||||
let has_value = true;
|
let has_value = true;
|
||||||
let (defaultness, _) =
|
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
||||||
self.lower_defaultness(i.kind.defaultness(), has_value, || hir::Defaultness::Final);
|
|
||||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||||
let attrs = self.lower_attrs(
|
let attrs = self.lower_attrs(
|
||||||
hir_id,
|
hir_id,
|
||||||
|
|
@ -1168,12 +1129,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
let (ident, (generics, kind)) = match &i.kind {
|
let (ident, (generics, kind)) = match &i.kind {
|
||||||
AssocItemKind::Const(box ConstItem {
|
AssocItemKind::Const(box ConstItem {
|
||||||
ident,
|
ident, generics, ty, rhs, define_opaque, ..
|
||||||
generics,
|
|
||||||
ty,
|
|
||||||
rhs_kind,
|
|
||||||
define_opaque,
|
|
||||||
..
|
|
||||||
}) => (
|
}) => (
|
||||||
*ident,
|
*ident,
|
||||||
self.lower_generics(
|
self.lower_generics(
|
||||||
|
|
@ -1186,7 +1142,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||||
);
|
);
|
||||||
this.lower_define_opaque(hir_id, &define_opaque);
|
this.lower_define_opaque(hir_id, &define_opaque);
|
||||||
let rhs = this.lower_const_item_rhs(rhs_kind, i.span);
|
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
|
||||||
hir::ImplItemKind::Const(ty, rhs)
|
hir::ImplItemKind::Const(ty, rhs)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -1310,14 +1266,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&self,
|
&self,
|
||||||
d: Defaultness,
|
d: Defaultness,
|
||||||
has_value: bool,
|
has_value: bool,
|
||||||
implicit: impl FnOnce() -> hir::Defaultness,
|
|
||||||
) -> (hir::Defaultness, Option<Span>) {
|
) -> (hir::Defaultness, Option<Span>) {
|
||||||
match d {
|
match d {
|
||||||
Defaultness::Implicit => (implicit(), None),
|
|
||||||
Defaultness::Default(sp) => {
|
Defaultness::Default(sp) => {
|
||||||
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
|
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
|
||||||
}
|
}
|
||||||
Defaultness::Final(sp) => (hir::Defaultness::Final, Some(self.lower_span(sp))),
|
Defaultness::Final => {
|
||||||
|
assert!(has_value);
|
||||||
|
(hir::Defaultness::Final, None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1415,7 +1372,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||||
// this as a special case.
|
// this as a special case.
|
||||||
return self.lower_fn_body(decl, contract, |this| {
|
return self.lower_fn_body(decl, contract, |this| {
|
||||||
if find_attr!(attrs, AttributeKind::RustcIntrinsic)
|
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
|
||||||
|| this.tcx.is_sdylib_interface_build()
|
|| this.tcx.is_sdylib_interface_build()
|
||||||
{
|
{
|
||||||
let span = this.lower_span(span);
|
let span = this.lower_span(span);
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,8 @@ mod pat;
|
||||||
mod path;
|
mod path;
|
||||||
pub mod stability;
|
pub mod stability;
|
||||||
|
|
||||||
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
||||||
struct LoweringContext<'a, 'hir> {
|
struct LoweringContext<'a, 'hir> {
|
||||||
tcx: TyCtxt<'hir>,
|
tcx: TyCtxt<'hir>,
|
||||||
resolver: &'a mut ResolverAstLowering,
|
resolver: &'a mut ResolverAstLowering,
|
||||||
|
|
@ -878,7 +880,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
|
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
|
||||||
}
|
}
|
||||||
LifetimeRes::Static { .. } | LifetimeRes::Error(..) => return None,
|
LifetimeRes::Static { .. } | LifetimeRes::Error => return None,
|
||||||
res => panic!(
|
res => panic!(
|
||||||
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
||||||
res, ident, ident.span
|
res, ident, ident.span
|
||||||
|
|
@ -1931,8 +1933,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
source: LifetimeSource,
|
source: LifetimeSource,
|
||||||
syntax: LifetimeSyntax,
|
syntax: LifetimeSyntax,
|
||||||
) -> &'hir hir::Lifetime {
|
) -> &'hir hir::Lifetime {
|
||||||
let res = if let Some(res) = self.resolver.get_lifetime_res(id) {
|
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
|
||||||
match res {
|
let res = match res {
|
||||||
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
||||||
LifetimeRes::Fresh { param, .. } => {
|
LifetimeRes::Fresh { param, .. } => {
|
||||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||||
|
|
@ -1947,13 +1949,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||||
hir::LifetimeKind::Static
|
hir::LifetimeKind::Static
|
||||||
}
|
}
|
||||||
LifetimeRes::Error(guar) => hir::LifetimeKind::Error(guar),
|
LifetimeRes::Error => hir::LifetimeKind::Error,
|
||||||
LifetimeRes::ElidedAnchor { .. } => {
|
LifetimeRes::ElidedAnchor { .. } => {
|
||||||
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hir::LifetimeKind::Error(self.dcx().span_delayed_bug(ident.span, "unresolved lifetime"))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(?res);
|
debug!(?res);
|
||||||
|
|
@ -2017,9 +2016,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// AST resolution emitted an error on those parameters, so we lower them using
|
// AST resolution emitted an error on those parameters, so we lower them using
|
||||||
// `ParamName::Error`.
|
// `ParamName::Error`.
|
||||||
let ident = self.lower_ident(param.ident);
|
let ident = self.lower_ident(param.ident);
|
||||||
let param_name = if let Some(LifetimeRes::Error(..)) =
|
let param_name =
|
||||||
self.resolver.get_lifetime_res(param.id)
|
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
|
||||||
{
|
|
||||||
ParamName::Error(ident)
|
ParamName::Error(ident)
|
||||||
} else {
|
} else {
|
||||||
ParamName::Plain(ident)
|
ParamName::Plain(ident)
|
||||||
|
|
@ -2378,20 +2376,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
fn lower_const_item_rhs(
|
fn lower_const_item_rhs(
|
||||||
&mut self,
|
&mut self,
|
||||||
rhs_kind: &ConstItemRhsKind,
|
attrs: &[hir::Attribute],
|
||||||
|
rhs: Option<&ConstItemRhs>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> hir::ConstItemRhs<'hir> {
|
) -> hir::ConstItemRhs<'hir> {
|
||||||
match rhs_kind {
|
match rhs {
|
||||||
ConstItemRhsKind::Body { rhs: Some(body) } => {
|
Some(ConstItemRhs::TypeConst(anon)) => {
|
||||||
hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body)))
|
|
||||||
}
|
|
||||||
ConstItemRhsKind::Body { rhs: None } => {
|
|
||||||
hir::ConstItemRhs::Body(self.lower_const_body(span, None))
|
|
||||||
}
|
|
||||||
ConstItemRhsKind::TypeConst { rhs: Some(anon) } => {
|
|
||||||
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
|
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
|
||||||
}
|
}
|
||||||
ConstItemRhsKind::TypeConst { rhs: None } => {
|
None if attr::contains_name(attrs, sym::type_const) => {
|
||||||
let const_arg = ConstArg {
|
let const_arg = ConstArg {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
kind: hir::ConstArgKind::Error(
|
kind: hir::ConstArgKind::Error(
|
||||||
|
|
@ -2401,6 +2394,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
};
|
};
|
||||||
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
|
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
|
||||||
}
|
}
|
||||||
|
Some(ConstItemRhs::Body(body)) => {
|
||||||
|
hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body)))
|
||||||
|
}
|
||||||
|
None => hir::ConstItemRhs::Body(self.lower_const_body(span, None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2430,7 +2427,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
|
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
|
||||||
let const_arg = self.lower_expr_to_const_arg_direct(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)
|
&*self.arena.alloc(const_arg)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -2442,7 +2447,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
ExprKind::Tup(exprs) => {
|
ExprKind::Tup(exprs) => {
|
||||||
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
|
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
|
||||||
let expr = self.lower_expr_to_const_arg_direct(&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)
|
&*self.arena.alloc(expr)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -2482,7 +2496,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// then go unused as the `Target::ExprField` is not actually
|
// then go unused as the `Target::ExprField` is not actually
|
||||||
// corresponding to `Node::ExprField`.
|
// corresponding to `Node::ExprField`.
|
||||||
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
|
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
|
||||||
let expr = self.lower_expr_to_const_arg_direct(&f.expr);
|
|
||||||
|
let expr = if let ExprKind::ConstBlock(anon_const) = &f.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(&f.expr)
|
||||||
|
};
|
||||||
|
|
||||||
&*self.arena.alloc(hir::ConstArgExprField {
|
&*self.arena.alloc(hir::ConstArgExprField {
|
||||||
hir_id,
|
hir_id,
|
||||||
|
|
@ -2500,7 +2523,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
ExprKind::Array(elements) => {
|
ExprKind::Array(elements) => {
|
||||||
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
|
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
|
||||||
let const_arg = self.lower_expr_to_const_arg_direct(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)
|
&*self.arena.alloc(const_arg)
|
||||||
}));
|
}));
|
||||||
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
|
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
|
||||||
|
|
@ -2530,7 +2559,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
| ExprKind::Call(..)
|
| ExprKind::Call(..)
|
||||||
| ExprKind::Tup(..)
|
| ExprKind::Tup(..)
|
||||||
| ExprKind::Array(..)
|
| ExprKind::Array(..)
|
||||||
| ExprKind::ConstBlock(..)
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return self.lower_expr_to_const_arg_direct(expr);
|
return self.lower_expr_to_const_arg_direct(expr);
|
||||||
|
|
@ -2544,27 +2572,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
ConstArg {
|
ConstArg {
|
||||||
hir_id: self.lower_node_id(expr.id),
|
hir_id: self.lower_node_id(expr.id),
|
||||||
kind: hir::ConstArgKind::Literal { lit: literal.node, negated: false },
|
kind: hir::ConstArgKind::Literal(literal.node),
|
||||||
span,
|
span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Unary(UnOp::Neg, inner_expr)
|
|
||||||
if let ExprKind::Lit(literal) = &inner_expr.kind =>
|
|
||||||
{
|
|
||||||
let span = expr.span;
|
|
||||||
let literal = self.lower_lit(literal, span);
|
|
||||||
|
|
||||||
ConstArg {
|
|
||||||
hir_id: self.lower_node_id(expr.id),
|
|
||||||
kind: hir::ConstArgKind::Literal { lit: literal.node, negated: true },
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::ConstBlock(anon_const) => {
|
|
||||||
let def_id = self.local_def_id(anon_const.id);
|
|
||||||
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
|
|
||||||
self.lower_anon_const_to_const_arg(anon_const, span)
|
|
||||||
}
|
|
||||||
_ => overly_complex_const(self),
|
_ => overly_complex_const(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2575,15 +2586,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
&mut self,
|
&mut self,
|
||||||
anon: &AnonConst,
|
anon: &AnonConst,
|
||||||
) -> &'hir hir::ConstArg<'hir> {
|
) -> &'hir hir::ConstArg<'hir> {
|
||||||
self.arena.alloc(self.lower_anon_const_to_const_arg(anon, anon.value.span))
|
self.arena.alloc(self.lower_anon_const_to_const_arg(anon))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn lower_anon_const_to_const_arg(
|
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||||
&mut self,
|
|
||||||
anon: &AnonConst,
|
|
||||||
span: Span,
|
|
||||||
) -> hir::ConstArg<'hir> {
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
// We cannot change parsing depending on feature gates available,
|
// We cannot change parsing depending on feature gates available,
|
||||||
|
|
@ -2594,7 +2601,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
if tcx.features().min_generic_const_args() {
|
if tcx.features().min_generic_const_args() {
|
||||||
return match anon.mgca_disambiguation {
|
return match anon.mgca_disambiguation {
|
||||||
MgcaDisambiguation::AnonConst => {
|
MgcaDisambiguation::AnonConst => {
|
||||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon, span);
|
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||||
ConstArg {
|
ConstArg {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
kind: hir::ConstArgKind::Anon(lowered_anon),
|
||||||
|
|
@ -2640,7 +2647,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon, anon.value.span);
|
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||||
ConstArg {
|
ConstArg {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
kind: hir::ConstArgKind::Anon(lowered_anon),
|
||||||
|
|
@ -2650,11 +2657,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
/// See [`hir::ConstArg`] for when to use this function vs
|
/// See [`hir::ConstArg`] for when to use this function vs
|
||||||
/// [`Self::lower_anon_const_to_const_arg`].
|
/// [`Self::lower_anon_const_to_const_arg`].
|
||||||
fn lower_anon_const_to_anon_const(
|
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
|
||||||
&mut self,
|
|
||||||
c: &AnonConst,
|
|
||||||
span: Span,
|
|
||||||
) -> &'hir hir::AnonConst {
|
|
||||||
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
|
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
|
||||||
let def_id = this.local_def_id(c.id);
|
let def_id = this.local_def_id(c.id);
|
||||||
let hir_id = this.lower_node_id(c.id);
|
let hir_id = this.lower_node_id(c.id);
|
||||||
|
|
@ -2662,7 +2665,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
def_id,
|
def_id,
|
||||||
hir_id,
|
hir_id,
|
||||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||||
span: this.lower_span(span),
|
span: this.lower_span(c.value.span),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ pub(crate) fn extern_abi_enabled(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
|
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
|
||||||
match extern_abi_enabled(features, span, abi) {
|
match extern_abi_enabled(features, span, abi) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
|
|
@ -95,11 +96,6 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
||||||
ExternAbi::RustCold => {
|
ExternAbi::RustCold => {
|
||||||
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
|
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
|
||||||
}
|
}
|
||||||
ExternAbi::RustPreserveNone => Err(UnstableAbi {
|
|
||||||
abi,
|
|
||||||
feature: sym::rust_preserve_none_cc,
|
|
||||||
explain: GateReason::Experimental,
|
|
||||||
}),
|
|
||||||
ExternAbi::RustInvalid => {
|
ExternAbi::RustInvalid => {
|
||||||
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_session = { path = "../rustc_session" }
|
rustc_session = { path = "../rustc_session" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
|
|
|
||||||
342
compiler/rustc_ast_passes/messages.ftl
Normal file
342
compiler/rustc_ast_passes/messages.ftl
Normal file
|
|
@ -0,0 +1,342 @@
|
||||||
|
ast_passes_abi_cannot_be_coroutine =
|
||||||
|
functions with the {$abi} ABI cannot be `{$coroutine_kind_str}`
|
||||||
|
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definition
|
||||||
|
|
||||||
|
ast_passes_abi_custom_safe_foreign_function =
|
||||||
|
foreign functions with the "custom" ABI cannot be safe
|
||||||
|
.suggestion = remove the `safe` keyword from this definition
|
||||||
|
|
||||||
|
ast_passes_abi_custom_safe_function =
|
||||||
|
functions with the "custom" ABI must be unsafe
|
||||||
|
.suggestion = add the `unsafe` keyword to this definition
|
||||||
|
|
||||||
|
ast_passes_abi_must_not_have_parameters_or_return_type=
|
||||||
|
invalid signature for `extern {$abi}` function
|
||||||
|
.note = functions with the {$abi} ABI cannot have any parameters or return type
|
||||||
|
.suggestion = remove the parameters and return type
|
||||||
|
|
||||||
|
ast_passes_abi_must_not_have_return_type=
|
||||||
|
invalid signature for `extern {$abi}` function
|
||||||
|
.note = functions with the {$abi} ABI cannot have a return type
|
||||||
|
.help = remove the return type
|
||||||
|
|
||||||
|
ast_passes_abi_x86_interrupt =
|
||||||
|
invalid signature for `extern "x86-interrupt"` function
|
||||||
|
.note = functions with the "x86-interrupt" ABI must be have either 1 or 2 parameters (but found {$param_count})
|
||||||
|
|
||||||
|
ast_passes_assoc_const_without_body =
|
||||||
|
associated constant in `impl` without body
|
||||||
|
.suggestion = provide a definition for the constant
|
||||||
|
|
||||||
|
ast_passes_assoc_fn_without_body =
|
||||||
|
associated function in `impl` without body
|
||||||
|
.suggestion = provide a definition for the function
|
||||||
|
|
||||||
|
ast_passes_assoc_type_without_body =
|
||||||
|
associated type in `impl` without body
|
||||||
|
.suggestion = provide a definition for the type
|
||||||
|
|
||||||
|
ast_passes_async_fn_in_const_trait_or_trait_impl =
|
||||||
|
async functions are not allowed in `const` {$context ->
|
||||||
|
[trait_impl] trait impls
|
||||||
|
[impl] impls
|
||||||
|
*[trait] traits
|
||||||
|
}
|
||||||
|
.label = associated functions of `const` cannot be declared `async`
|
||||||
|
|
||||||
|
ast_passes_at_least_one_trait = at least one trait must be specified
|
||||||
|
|
||||||
|
ast_passes_auto_generic = auto traits cannot have generic parameters
|
||||||
|
.label = auto trait cannot have generic parameters
|
||||||
|
.suggestion = remove the parameters
|
||||||
|
|
||||||
|
ast_passes_auto_items = auto traits cannot have associated items
|
||||||
|
.label = {ast_passes_auto_items}
|
||||||
|
.suggestion = remove the associated items
|
||||||
|
|
||||||
|
ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
|
||||||
|
.label = {ast_passes_auto_super_lifetime}
|
||||||
|
.suggestion = remove the super traits or lifetime bounds
|
||||||
|
|
||||||
|
ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
|
||||||
|
.cannot_have = cannot have a body
|
||||||
|
.invalid = the invalid body
|
||||||
|
.existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body
|
||||||
|
|
||||||
|
ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
|
||||||
|
|
||||||
|
ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions
|
||||||
|
.label = `extern "{$abi}"` because of this
|
||||||
|
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||||
|
|
||||||
|
ast_passes_c_variadic_bad_naked_extern = `...` is not supported for `extern "{$abi}"` naked functions
|
||||||
|
.label = `extern "{$abi}"` because of this
|
||||||
|
.help = C-variadic function must have a compatible calling convention
|
||||||
|
|
||||||
|
ast_passes_c_variadic_must_be_unsafe =
|
||||||
|
functions with a C variable argument list must be unsafe
|
||||||
|
.suggestion = add the `unsafe` keyword to this definition
|
||||||
|
|
||||||
|
ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions
|
||||||
|
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||||
|
|
||||||
|
ast_passes_c_variadic_not_supported = the `{$target}` target does not support c-variadic functions
|
||||||
|
|
||||||
|
ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic
|
||||||
|
.const = `const` because of this
|
||||||
|
.variadic = C-variadic because of this
|
||||||
|
|
||||||
|
ast_passes_const_and_coroutine = functions cannot be both `const` and `{$coroutine_kind}`
|
||||||
|
.const = `const` because of this
|
||||||
|
.coroutine = `{$coroutine_kind}` because of this
|
||||||
|
.label = {""}
|
||||||
|
|
||||||
|
ast_passes_const_auto_trait = auto traits cannot be const
|
||||||
|
.help = remove the `const` keyword
|
||||||
|
|
||||||
|
ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types
|
||||||
|
|
||||||
|
ast_passes_const_without_body =
|
||||||
|
free constant item without body
|
||||||
|
.suggestion = provide a definition for the constant
|
||||||
|
|
||||||
|
ast_passes_constraint_on_negative_bound =
|
||||||
|
associated type constraints not allowed on negative bounds
|
||||||
|
|
||||||
|
ast_passes_coroutine_and_c_variadic = functions cannot be both `{$coroutine_kind}` and C-variadic
|
||||||
|
.const = `{$coroutine_kind}` because of this
|
||||||
|
.variadic = C-variadic because of this
|
||||||
|
|
||||||
|
ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
|
||||||
|
.label = not supported
|
||||||
|
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
|
||||||
|
.suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax
|
||||||
|
.note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
|
||||||
|
|
||||||
|
ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
|
||||||
|
|
||||||
|
ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have `{$kw}` qualifier
|
||||||
|
.label = in this `extern` block
|
||||||
|
.suggestion = remove the `{$kw}` qualifier
|
||||||
|
|
||||||
|
ast_passes_extern_invalid_safety = items in `extern` blocks without an `unsafe` qualifier cannot have safety qualifiers
|
||||||
|
.suggestion = add `unsafe` to this `extern` block
|
||||||
|
|
||||||
|
ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
|
||||||
|
.label = in this `extern` block
|
||||||
|
.note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
|
||||||
|
|
||||||
|
ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||||
|
|
||||||
|
ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr}
|
||||||
|
.suggestion = remove the {$remove_descr}
|
||||||
|
.label = `extern` block begins here
|
||||||
|
|
||||||
|
ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed
|
||||||
|
.suggestion = specify an ABI
|
||||||
|
.help = prior to Rust 2024, a default ABI was inferred
|
||||||
|
|
||||||
|
ast_passes_extern_without_abi_sugg = `extern` declarations without an explicit ABI are deprecated
|
||||||
|
.label = ABI should be specified here
|
||||||
|
.suggestion = explicitly specify the {$default_abi} ABI
|
||||||
|
|
||||||
|
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
|
||||||
|
.suggestion = remove the attribute
|
||||||
|
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
|
||||||
|
|
||||||
|
ast_passes_fieldless_union = unions cannot have zero fields
|
||||||
|
|
||||||
|
ast_passes_fn_body_extern = incorrect function inside `extern` block
|
||||||
|
.cannot_have = cannot have a body
|
||||||
|
.suggestion = remove the invalid body
|
||||||
|
.help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
|
||||||
|
.label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body
|
||||||
|
|
||||||
|
ast_passes_fn_param_c_var_args_not_last =
|
||||||
|
`...` must be the last argument of a C-variadic function
|
||||||
|
|
||||||
|
ast_passes_fn_param_doc_comment =
|
||||||
|
documentation comments cannot be applied to function parameters
|
||||||
|
.label = doc comments are not allowed here
|
||||||
|
|
||||||
|
ast_passes_fn_param_forbidden_attr =
|
||||||
|
allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
|
||||||
|
|
||||||
|
ast_passes_fn_param_forbidden_self =
|
||||||
|
`self` parameter is only allowed in associated functions
|
||||||
|
.label = not semantically valid as function parameter
|
||||||
|
.note = associated functions are those in `impl` or `trait` definitions
|
||||||
|
|
||||||
|
ast_passes_fn_param_too_many =
|
||||||
|
function can not have more than {$max_num_args} arguments
|
||||||
|
|
||||||
|
ast_passes_fn_ptr_invalid_safety = function pointers cannot be declared with `safe` safety qualifier
|
||||||
|
.suggestion = remove safe from this item
|
||||||
|
|
||||||
|
ast_passes_fn_without_body =
|
||||||
|
free function without a body
|
||||||
|
.suggestion = provide a definition for the function
|
||||||
|
|
||||||
|
ast_passes_forbidden_bound =
|
||||||
|
bounds cannot be used in this context
|
||||||
|
|
||||||
|
ast_passes_forbidden_const_param =
|
||||||
|
late-bound const parameters cannot be used currently
|
||||||
|
|
||||||
|
ast_passes_forbidden_default =
|
||||||
|
`default` is only allowed on items in trait impls
|
||||||
|
.label = `default` because of this
|
||||||
|
|
||||||
|
ast_passes_forbidden_non_lifetime_param =
|
||||||
|
only lifetime parameters can be used in this context
|
||||||
|
|
||||||
|
ast_passes_generic_before_constraints = generic arguments must come before the first constraint
|
||||||
|
.constraints = {$constraint_len ->
|
||||||
|
[one] constraint
|
||||||
|
*[other] constraints
|
||||||
|
}
|
||||||
|
.args = generic {$args_len ->
|
||||||
|
[one] argument
|
||||||
|
*[other] arguments
|
||||||
|
}
|
||||||
|
.empty_string = {""},
|
||||||
|
.suggestion = move the {$constraint_len ->
|
||||||
|
[one] constraint
|
||||||
|
*[other] constraints
|
||||||
|
} after the generic {$args_len ->
|
||||||
|
[one] argument
|
||||||
|
*[other] arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_passes_generic_default_trailing = generic parameters with a default must be trailing
|
||||||
|
|
||||||
|
ast_passes_impl_fn_const =
|
||||||
|
redundant `const` fn marker in const impl
|
||||||
|
.parent_constness = this declares all associated functions implicitly const
|
||||||
|
.label = remove the `const`
|
||||||
|
|
||||||
|
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
|
||||||
|
.help = remove one of these features
|
||||||
|
|
||||||
|
ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
|
||||||
|
.suggestion = remove safe from this item
|
||||||
|
|
||||||
|
ast_passes_item_underscore = `{$kind}` items in this context need a name
|
||||||
|
.label = `_` is not a valid name for this `{$kind}` item
|
||||||
|
|
||||||
|
ast_passes_match_arm_with_no_body =
|
||||||
|
`match` arm with no body
|
||||||
|
.suggestion = add a body after the pattern
|
||||||
|
|
||||||
|
ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe
|
||||||
|
.suggestion = needs `unsafe` before the extern keyword
|
||||||
|
|
||||||
|
ast_passes_missing_unsafe_on_extern_lint = extern blocks should be unsafe
|
||||||
|
.suggestion = needs `unsafe` before the extern keyword
|
||||||
|
|
||||||
|
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
|
||||||
|
.help = consider using the `#[path]` attribute to specify filesystem path
|
||||||
|
|
||||||
|
ast_passes_negative_bound_not_supported =
|
||||||
|
negative bounds are not supported
|
||||||
|
|
||||||
|
ast_passes_negative_bound_with_parenthetical_notation =
|
||||||
|
parenthetical notation may not be used for negative bounds
|
||||||
|
|
||||||
|
ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
|
||||||
|
.outer = outer `impl Trait`
|
||||||
|
.inner = nested `impl Trait` here
|
||||||
|
|
||||||
|
ast_passes_nested_lifetimes = nested quantification of lifetimes
|
||||||
|
|
||||||
|
ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
|
||||||
|
|
||||||
|
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
|
||||||
|
.help = use `auto trait Trait {"{}"}` instead
|
||||||
|
|
||||||
|
ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
|
||||||
|
.suggestion = reorder the parameters: lifetimes, then consts and types
|
||||||
|
|
||||||
|
ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
|
||||||
|
.label = pattern not allowed in function without body
|
||||||
|
|
||||||
|
ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types
|
||||||
|
|
||||||
|
ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
|
||||||
|
.label = pattern not allowed in foreign function
|
||||||
|
|
||||||
|
ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing syntax
|
||||||
|
.label = second `use<...>` here
|
||||||
|
|
||||||
|
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
|
||||||
|
|
||||||
|
ast_passes_scalable_vector_not_tuple_struct = scalable vectors must be tuple structs
|
||||||
|
|
||||||
|
ast_passes_static_without_body =
|
||||||
|
free static item without body
|
||||||
|
.suggestion = provide a definition for the static
|
||||||
|
|
||||||
|
ast_passes_tilde_const_disallowed = `[const]` is not allowed here
|
||||||
|
.closure = closures cannot have `[const]` trait bounds
|
||||||
|
.function = this function is not `const`, so it cannot have `[const]` trait bounds
|
||||||
|
.trait = this trait is not `const`, so it cannot have `[const]` trait bounds
|
||||||
|
.trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds
|
||||||
|
.impl = inherent impls cannot have `[const]` trait bounds
|
||||||
|
.trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds
|
||||||
|
.trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds
|
||||||
|
.inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds
|
||||||
|
.struct = structs cannot have `[const]` trait bounds
|
||||||
|
.enum = enums cannot have `[const]` trait bounds
|
||||||
|
.union = unions cannot have `[const]` trait bounds
|
||||||
|
.anon_const = anonymous constants cannot have `[const]` trait bounds
|
||||||
|
.object = trait objects cannot have `[const]` trait bounds
|
||||||
|
.item = this item cannot have `[const]` trait bounds
|
||||||
|
|
||||||
|
ast_passes_trait_fn_const =
|
||||||
|
functions in {$in_impl ->
|
||||||
|
[true] trait impls
|
||||||
|
*[false] traits
|
||||||
|
} cannot be declared const
|
||||||
|
.label = functions in {$in_impl ->
|
||||||
|
[true] trait impls
|
||||||
|
*[false] traits
|
||||||
|
} cannot be const
|
||||||
|
.const_context_label = this declares all associated functions implicitly const
|
||||||
|
.remove_const_sugg = remove the `const`{$requires_multiple_changes ->
|
||||||
|
[true] {" ..."}
|
||||||
|
*[false] {""}
|
||||||
|
}
|
||||||
|
.make_impl_const_sugg = ... and declare the impl to be const instead
|
||||||
|
.make_trait_const_sugg = ... and declare the trait to be const instead
|
||||||
|
|
||||||
|
ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
|
||||||
|
|
||||||
|
ast_passes_ty_alias_without_body =
|
||||||
|
free type alias without body
|
||||||
|
.suggestion = provide a definition for the type
|
||||||
|
|
||||||
|
ast_passes_unsafe_item = {$kind} cannot be declared unsafe
|
||||||
|
|
||||||
|
ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
|
||||||
|
.negative = negative because of this
|
||||||
|
.unsafe = unsafe because of this
|
||||||
|
|
||||||
|
ast_passes_unsafe_static =
|
||||||
|
static items cannot be declared with `unsafe` safety qualifier outside of `extern` block
|
||||||
|
|
||||||
|
ast_passes_visibility_not_permitted =
|
||||||
|
visibility qualifiers are not permitted here
|
||||||
|
.enum_variant = enum variants and their fields always share the visibility of the enum they are in
|
||||||
|
.trait_impl = trait items always share the visibility of their trait
|
||||||
|
.individual_impl_items = place qualifiers on individual impl items instead
|
||||||
|
.individual_foreign_items = place qualifiers on individual foreign items instead
|
||||||
|
.remove_qualifier_sugg = remove the qualifier
|
||||||
|
|
||||||
|
ast_passes_where_clause_after_type_alias = where clauses are not allowed after the type for type aliases
|
||||||
|
.note = see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
|
||||||
|
.help = add `#![feature(lazy_type_alias)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
|
||||||
|
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
|
||||||
|
.remove_suggestion = remove this `where`
|
||||||
|
.move_suggestion = move it to the end of the type declaration
|
||||||
|
|
@ -65,28 +65,6 @@ impl TraitOrImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AllowDefault {
|
|
||||||
Yes,
|
|
||||||
No,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AllowDefault {
|
|
||||||
fn when(b: bool) -> Self {
|
|
||||||
if b { Self::Yes } else { Self::No }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AllowFinal {
|
|
||||||
Yes,
|
|
||||||
No,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AllowFinal {
|
|
||||||
fn when(b: bool) -> Self {
|
|
||||||
if b { Self::Yes } else { Self::No }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AstValidator<'a> {
|
struct AstValidator<'a> {
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
features: &'a Features,
|
features: &'a Features,
|
||||||
|
|
@ -422,7 +400,6 @@ impl<'a> AstValidator<'a> {
|
||||||
CanonAbi::C
|
CanonAbi::C
|
||||||
| CanonAbi::Rust
|
| CanonAbi::Rust
|
||||||
| CanonAbi::RustCold
|
| CanonAbi::RustCold
|
||||||
| CanonAbi::RustPreserveNone
|
|
||||||
| CanonAbi::Arm(_)
|
| CanonAbi::Arm(_)
|
||||||
| CanonAbi::X86(_) => { /* nothing to check */ }
|
| CanonAbi::X86(_) => { /* nothing to check */ }
|
||||||
|
|
||||||
|
|
@ -585,33 +562,11 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_defaultness(
|
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||||
&self,
|
if let Defaultness::Default(def_span) = defaultness {
|
||||||
span: Span,
|
|
||||||
defaultness: Defaultness,
|
|
||||||
allow_default: AllowDefault,
|
|
||||||
allow_final: AllowFinal,
|
|
||||||
) {
|
|
||||||
match defaultness {
|
|
||||||
Defaultness::Default(def_span) if matches!(allow_default, AllowDefault::No) => {
|
|
||||||
let span = self.sess.source_map().guess_head_span(span);
|
let span = self.sess.source_map().guess_head_span(span);
|
||||||
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
||||||
}
|
}
|
||||||
Defaultness::Final(def_span) if matches!(allow_final, AllowFinal::No) => {
|
|
||||||
let span = self.sess.source_map().guess_head_span(span);
|
|
||||||
self.dcx().emit_err(errors::ForbiddenFinal { span, def_span });
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_final_has_body(&self, item: &Item<AssocItemKind>, defaultness: Defaultness) {
|
|
||||||
if let AssocItemKind::Fn(box Fn { body: None, .. }) = &item.kind
|
|
||||||
&& let Defaultness::Final(def_span) = defaultness
|
|
||||||
{
|
|
||||||
let span = self.sess.source_map().guess_head_span(item.span);
|
|
||||||
self.dcx().emit_err(errors::ForbiddenFinalWithoutBody { span, def_span });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `sp` ends with a semicolon, returns it as a `Span`
|
/// If `sp` ends with a semicolon, returns it as a `Span`
|
||||||
|
|
@ -742,11 +697,13 @@ impl<'a> AstValidator<'a> {
|
||||||
unreachable!("C variable argument list cannot be used in closures")
|
unreachable!("C variable argument list cannot be used in closures")
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Const::Yes(_) = sig.header.constness
|
// C-variadics are not yet implemented in const evaluation.
|
||||||
&& !self.features.enabled(sym::const_c_variadic)
|
if let Const::Yes(const_span) = sig.header.constness {
|
||||||
{
|
self.dcx().emit_err(errors::ConstAndCVariadic {
|
||||||
let msg = format!("c-variadic const function definitions are unstable");
|
spans: vec![const_span, variadic_param.span],
|
||||||
feature_err(&self.sess, sym::const_c_variadic, sig.span, msg).emit();
|
const_span,
|
||||||
|
variadic_span: variadic_param.span,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||||
|
|
@ -1234,7 +1191,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
|
|
||||||
for EiiImpl { eii_macro_path, .. } in eii_impls {
|
for EiiImpl { eii_macro_path, .. } in eii_impls {
|
||||||
self.visit_path(eii_macro_path);
|
self.visit_path(eii_macro_path);
|
||||||
|
|
@ -1403,9 +1360,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
|
ItemKind::Const(box ConstItem { defaultness, ident, rhs, .. }) => {
|
||||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
if !rhs_kind.has_expr() {
|
if rhs.is_none() {
|
||||||
self.dcx().emit_err(errors::ConstWithoutBody {
|
self.dcx().emit_err(errors::ConstWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
replace_span: self.ending_semi_or_hi(item.span),
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
|
|
@ -1442,7 +1399,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
ItemKind::TyAlias(
|
ItemKind::TyAlias(
|
||||||
ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
|
ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
|
||||||
) => {
|
) => {
|
||||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
if ty.is_none() {
|
if ty.is_none() {
|
||||||
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
|
|
@ -1472,7 +1429,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||||
match &fi.kind {
|
match &fi.kind {
|
||||||
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
||||||
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(fi.span, *defaultness);
|
||||||
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
||||||
self.check_foreign_fn_headerless(sig.header);
|
self.check_foreign_fn_headerless(sig.header);
|
||||||
self.check_foreign_item_ascii_only(*ident);
|
self.check_foreign_item_ascii_only(*ident);
|
||||||
|
|
@ -1492,7 +1449,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
ty,
|
ty,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
self.check_defaultness(fi.span, *defaultness);
|
||||||
self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
|
self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
|
||||||
self.check_type_no_bounds(bounds, "`extern` blocks");
|
self.check_type_no_bounds(bounds, "`extern` blocks");
|
||||||
self.check_foreign_ty_genericless(generics, after_where_clause);
|
self.check_foreign_ty_genericless(generics, after_where_clause);
|
||||||
|
|
@ -1751,30 +1708,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self.check_nomangle_item_asciionly(ident, item.span);
|
self.check_nomangle_item_asciionly(ident, item.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
let defaultness = item.kind.defaultness();
|
if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
|
||||||
self.check_defaultness(
|
self.check_defaultness(item.span, item.kind.defaultness());
|
||||||
item.span,
|
}
|
||||||
defaultness,
|
|
||||||
// `default` is allowed on all associated items in impls.
|
|
||||||
AllowDefault::when(matches!(ctxt, AssocCtxt::Impl { .. })),
|
|
||||||
// `final` is allowed on all associated *functions* in traits.
|
|
||||||
AllowFinal::when(
|
|
||||||
ctxt == AssocCtxt::Trait && matches!(item.kind, AssocItemKind::Fn(..)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.check_final_has_body(item, defaultness);
|
|
||||||
|
|
||||||
if let AssocCtxt::Impl { .. } = ctxt {
|
if let AssocCtxt::Impl { .. } = ctxt {
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
AssocItemKind::Const(box ConstItem { rhs_kind, .. }) => {
|
AssocItemKind::Const(box ConstItem { rhs: None, .. }) => {
|
||||||
if !rhs_kind.has_expr() {
|
|
||||||
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
replace_span: self.ending_semi_or_hi(item.span),
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||||
if body.is_none() && !self.is_sdylib_interface {
|
if body.is_none() && !self.is_sdylib_interface {
|
||||||
self.dcx().emit_err(errors::AssocFnWithoutBody {
|
self.dcx().emit_err(errors::AssocFnWithoutBody {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,5 @@
|
||||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||||
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
|
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
|
||||||
use rustc_errors::msg;
|
|
||||||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
|
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::parse::{feature_err, feature_warn};
|
use rustc_session::parse::{feature_err, feature_warn};
|
||||||
|
|
@ -14,11 +13,15 @@ use crate::errors;
|
||||||
macro_rules! gate {
|
macro_rules! gate {
|
||||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
||||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
|
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
|
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
|
||||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||||
|
// FIXME: make this translatable
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
|
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
@ -28,11 +31,13 @@ macro_rules! gate {
|
||||||
macro_rules! gate_alt {
|
macro_rules! gate_alt {
|
||||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
|
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
|
||||||
if !$has_feature && !$span.allows_unstable($name) {
|
if !$has_feature && !$span.allows_unstable($name) {
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
||||||
if !$has_feature && !$span.allows_unstable($name) {
|
if !$has_feature && !$span.allows_unstable($name) {
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
|
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
|
||||||
for note in $notes {
|
for note in $notes {
|
||||||
diag.note(*note);
|
diag.note(*note);
|
||||||
|
|
@ -125,7 +130,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||||
&self,
|
&self,
|
||||||
non_lifetime_binders,
|
non_lifetime_binders,
|
||||||
non_lt_param_spans,
|
non_lt_param_spans,
|
||||||
msg!("only lifetime parameters can be used in this context")
|
crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME(non_lifetime_binders): Const bound params are pretty broken.
|
// FIXME(non_lifetime_binders): Const bound params are pretty broken.
|
||||||
|
|
@ -249,14 +254,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => {
|
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => {
|
||||||
self.check_impl_trait(ty, false)
|
self.check_impl_trait(ty, false)
|
||||||
}
|
}
|
||||||
ast::ItemKind::Const(box ast::ConstItem {
|
|
||||||
rhs_kind: ast::ConstItemRhsKind::TypeConst { .. },
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
// Make sure this is only allowed if the feature gate is enabled.
|
|
||||||
// #![feature(min_generic_const_args)]
|
|
||||||
gate!(&self, min_generic_const_args, i.span, "top-level `type const` are unstable");
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -338,11 +335,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
||||||
match e.kind {
|
match e.kind {
|
||||||
ast::ExprKind::TryBlock(_, None) => {
|
ast::ExprKind::TryBlock(_, None) => {
|
||||||
// `try { ... }` is old and is only gated post-expansion here.
|
|
||||||
gate!(&self, try_blocks, e.span, "`try` expression is experimental");
|
gate!(&self, try_blocks, e.span, "`try` expression is experimental");
|
||||||
}
|
}
|
||||||
ast::ExprKind::TryBlock(_, Some(_)) => {
|
ast::ExprKind::TryBlock(_, Some(_)) => {
|
||||||
// `try_blocks_heterogeneous` is new, and gated pre-expansion instead.
|
gate!(
|
||||||
|
&self,
|
||||||
|
try_blocks_heterogeneous,
|
||||||
|
e.span,
|
||||||
|
"`try bikeshed` expression is experimental"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ast::ExprKind::Lit(token::Lit {
|
ast::ExprKind::Lit(token::Lit {
|
||||||
kind: token::LitKind::Float | token::LitKind::Integer,
|
kind: token::LitKind::Float | token::LitKind::Integer,
|
||||||
|
|
@ -426,20 +427,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
ast::AssocItemKind::Const(box ast::ConstItem {
|
|
||||||
rhs_kind: ast::ConstItemRhsKind::TypeConst { .. },
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
// Make sure this is only allowed if the feature gate is enabled.
|
|
||||||
// #![feature(min_generic_const_args)]
|
|
||||||
gate!(
|
|
||||||
&self,
|
|
||||||
min_generic_const_args,
|
|
||||||
i.span,
|
|
||||||
"associated `type const` are unstable"
|
|
||||||
);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if let ast::Defaultness::Default(_) = i.kind.defaultness() {
|
if let ast::Defaultness::Default(_) = i.kind.defaultness() {
|
||||||
|
|
@ -459,7 +446,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
maybe_stage_features(sess, features, krate);
|
maybe_stage_features(sess, features, krate);
|
||||||
check_incompatible_features(sess, features);
|
check_incompatible_features(sess, features);
|
||||||
check_dependent_features(sess, features);
|
|
||||||
check_new_solver_banned_features(sess, features);
|
check_new_solver_banned_features(sess, features);
|
||||||
|
|
||||||
let mut visitor = PostExpansionVisitor { sess, features };
|
let mut visitor = PostExpansionVisitor { sess, features };
|
||||||
|
|
@ -505,6 +491,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
|
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
|
||||||
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
|
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
|
||||||
{
|
{
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
// Emit yield_expr as the error, since that will be sufficient. You can think of it
|
// Emit yield_expr as the error, since that will be sufficient. You can think of it
|
||||||
// as coroutines and gen_blocks imply yield_expr.
|
// as coroutines and gen_blocks imply yield_expr.
|
||||||
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
|
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
|
||||||
|
|
@ -518,7 +505,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
half_open_range_patterns_in_slices,
|
half_open_range_patterns_in_slices,
|
||||||
"half-open range patterns in slices are unstable"
|
"half-open range patterns in slices are unstable"
|
||||||
);
|
);
|
||||||
gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental");
|
|
||||||
gate_all!(yeet_expr, "`do yeet` expression is experimental");
|
gate_all!(yeet_expr, "`do yeet` expression is experimental");
|
||||||
gate_all!(const_closures, "const closures are experimental");
|
gate_all!(const_closures, "const closures are experimental");
|
||||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||||
|
|
@ -537,6 +523,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
if !visitor.features.min_generic_const_args()
|
if !visitor.features.min_generic_const_args()
|
||||||
&& !span.allows_unstable(sym::min_generic_const_args)
|
&& !span.allows_unstable(sym::min_generic_const_args)
|
||||||
{
|
{
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
feature_err(
|
feature_err(
|
||||||
&visitor.sess,
|
&visitor.sess,
|
||||||
sym::min_generic_const_args,
|
sym::min_generic_const_args,
|
||||||
|
|
@ -547,27 +534,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `mgca_type_const_syntax` is part of `min_generic_const_args` so either
|
|
||||||
// or both are enabled we don't need to emit a feature error.
|
|
||||||
if let Some(spans) = spans.get(&sym::mgca_type_const_syntax) {
|
|
||||||
for span in spans {
|
|
||||||
if visitor.features.min_generic_const_args()
|
|
||||||
|| visitor.features.mgca_type_const_syntax()
|
|
||||||
|| span.allows_unstable(sym::min_generic_const_args)
|
|
||||||
|| span.allows_unstable(sym::mgca_type_const_syntax)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
feature_err(
|
|
||||||
&visitor.sess,
|
|
||||||
sym::min_generic_const_args,
|
|
||||||
*span,
|
|
||||||
"`type const` syntax is experimental",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gate_all!(global_registration, "global registration is experimental");
|
gate_all!(global_registration, "global registration is experimental");
|
||||||
gate_all!(return_type_notation, "return type notation is experimental");
|
gate_all!(return_type_notation, "return type notation is experimental");
|
||||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||||
|
|
@ -579,8 +545,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
gate_all!(super_let, "`super let` is experimental");
|
gate_all!(super_let, "`super let` is experimental");
|
||||||
gate_all!(frontmatter, "frontmatters are experimental");
|
gate_all!(frontmatter, "frontmatters are experimental");
|
||||||
gate_all!(coroutines, "coroutine syntax is experimental");
|
gate_all!(coroutines, "coroutine syntax is experimental");
|
||||||
gate_all!(const_block_items, "const block items are experimental");
|
|
||||||
gate_all!(final_associated_functions, "`final` on trait functions is experimental");
|
|
||||||
|
|
||||||
if !visitor.features.never_patterns() {
|
if !visitor.features.never_patterns() {
|
||||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||||
|
|
@ -595,6 +559,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
if let Ok(snippet) = sm.span_to_snippet(span)
|
if let Ok(snippet) = sm.span_to_snippet(span)
|
||||||
&& snippet == "!"
|
&& snippet == "!"
|
||||||
{
|
{
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
|
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
|
||||||
.emit();
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -691,27 +656,6 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_dependent_features(sess: &Session, features: &Features) {
|
|
||||||
for &(parent, children) in
|
|
||||||
rustc_feature::DEPENDENT_FEATURES.iter().filter(|(parent, _)| features.enabled(*parent))
|
|
||||||
{
|
|
||||||
if children.iter().any(|f| !features.enabled(*f)) {
|
|
||||||
let parent_span = features
|
|
||||||
.enabled_features_iter_stable_order()
|
|
||||||
.find_map(|(name, span)| (name == parent).then_some(span))
|
|
||||||
.unwrap();
|
|
||||||
// FIXME: should probably format this in fluent instead of here
|
|
||||||
let missing = children
|
|
||||||
.iter()
|
|
||||||
.filter(|f| !features.enabled(**f))
|
|
||||||
.map(|s| format!("`{}`", s.as_str()))
|
|
||||||
.intersperse(String::from(", "))
|
|
||||||
.collect();
|
|
||||||
sess.dcx().emit_err(errors::MissingDependentFeatures { parent_span, parent, missing });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_new_solver_banned_features(sess: &Session, features: &Features) {
|
fn check_new_solver_banned_features(sess: &Session, features: &Features) {
|
||||||
if !sess.opts.unstable_opts.next_solver.globally {
|
if !sess.opts.unstable_opts.next_solver.globally {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(iter_intersperse)]
|
|
||||||
#![feature(iter_is_partitioned)]
|
#![feature(iter_is_partitioned)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
pub mod ast_validation;
|
pub mod ast_validation;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub mod feature_gate;
|
pub mod feature_gate;
|
||||||
|
|
||||||
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
|
||||||
|
|
@ -1961,8 +1961,7 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
|
fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
|
||||||
self.word(lifetime.ident.name.to_string());
|
self.print_name(lifetime.ident.name)
|
||||||
self.ann_post(lifetime.ident)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
|
fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ impl<'a> State<'a> {
|
||||||
expr.as_deref(),
|
expr.as_deref(),
|
||||||
vis,
|
vis,
|
||||||
*safety,
|
*safety,
|
||||||
ast::Defaultness::Implicit,
|
ast::Defaultness::Final,
|
||||||
define_opaque.as_deref(),
|
define_opaque.as_deref(),
|
||||||
),
|
),
|
||||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||||
|
|
@ -201,27 +201,16 @@ impl<'a> State<'a> {
|
||||||
body.as_deref(),
|
body.as_deref(),
|
||||||
&item.vis,
|
&item.vis,
|
||||||
ast::Safety::Default,
|
ast::Safety::Default,
|
||||||
ast::Defaultness::Implicit,
|
ast::Defaultness::Final,
|
||||||
define_opaque.as_deref(),
|
define_opaque.as_deref(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
|
|
||||||
let ib = self.ibox(INDENT_UNIT);
|
|
||||||
self.word("const");
|
|
||||||
self.nbsp();
|
|
||||||
{
|
|
||||||
let cb = self.cbox(0);
|
|
||||||
let ib = self.ibox(0);
|
|
||||||
self.print_block_with_attrs(block, &[], cb, ib);
|
|
||||||
}
|
|
||||||
self.end(ib);
|
|
||||||
}
|
|
||||||
ast::ItemKind::Const(box ast::ConstItem {
|
ast::ItemKind::Const(box ast::ConstItem {
|
||||||
defaultness,
|
defaultness,
|
||||||
ident,
|
ident,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
rhs_kind,
|
rhs,
|
||||||
define_opaque,
|
define_opaque,
|
||||||
}) => {
|
}) => {
|
||||||
self.print_item_const(
|
self.print_item_const(
|
||||||
|
|
@ -229,7 +218,7 @@ impl<'a> State<'a> {
|
||||||
None,
|
None,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
rhs_kind.expr(),
|
rhs.as_ref().map(|ct| ct.expr()),
|
||||||
&item.vis,
|
&item.vis,
|
||||||
ast::Safety::Default,
|
ast::Safety::Default,
|
||||||
*defaultness,
|
*defaultness,
|
||||||
|
|
@ -573,7 +562,7 @@ impl<'a> State<'a> {
|
||||||
ident,
|
ident,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
rhs_kind,
|
rhs,
|
||||||
define_opaque,
|
define_opaque,
|
||||||
}) => {
|
}) => {
|
||||||
self.print_item_const(
|
self.print_item_const(
|
||||||
|
|
@ -581,7 +570,7 @@ impl<'a> State<'a> {
|
||||||
None,
|
None,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
rhs_kind.expr(),
|
rhs.as_ref().map(|ct| ct.expr()),
|
||||||
vis,
|
vis,
|
||||||
ast::Safety::Default,
|
ast::Safety::Default,
|
||||||
*defaultness,
|
*defaultness,
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ edition = "2024"
|
||||||
rustc_abi = { path = "../rustc_abi" }
|
rustc_abi = { path = "../rustc_abi" }
|
||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_lexer = { path = "../rustc_lexer" }
|
rustc_lexer = { path = "../rustc_lexer" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
|
|
|
||||||
246
compiler/rustc_attr_parsing/messages.ftl
Normal file
246
compiler/rustc_attr_parsing/messages.ftl
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
attr_parsing_as_needed_compatibility =
|
||||||
|
linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds
|
||||||
|
|
||||||
|
attr_parsing_bundle_needs_static =
|
||||||
|
linking modifier `bundle` is only compatible with `static` linking kind
|
||||||
|
|
||||||
|
attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
|
||||||
|
|
||||||
|
attr_parsing_deprecated_item_suggestion =
|
||||||
|
suggestions on deprecated items are unstable
|
||||||
|
.help = add `#![feature(deprecated_suggestion)]` to the crate root
|
||||||
|
.note = see #94785 for more details
|
||||||
|
|
||||||
|
attr_parsing_doc_alias_bad_char =
|
||||||
|
{$char_} character isn't allowed in {$attr_str}
|
||||||
|
|
||||||
|
attr_parsing_doc_alias_empty =
|
||||||
|
{$attr_str} attribute cannot have empty value
|
||||||
|
|
||||||
|
attr_parsing_doc_alias_malformed =
|
||||||
|
doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
attr_parsing_doc_keyword_not_keyword =
|
||||||
|
nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]`
|
||||||
|
.help = only existing keywords are allowed in core/std
|
||||||
|
|
||||||
|
attr_parsing_empty_confusables =
|
||||||
|
expected at least one confusable name
|
||||||
|
|
||||||
|
attr_parsing_empty_link_name =
|
||||||
|
link name must not be empty
|
||||||
|
.label = empty link name
|
||||||
|
|
||||||
|
attr_parsing_expected_single_version_literal =
|
||||||
|
expected single version literal
|
||||||
|
|
||||||
|
attr_parsing_expected_version_literal =
|
||||||
|
expected a version literal
|
||||||
|
|
||||||
|
attr_parsing_expects_feature_list =
|
||||||
|
`{$name}` expects a list of feature names
|
||||||
|
|
||||||
|
attr_parsing_expects_features =
|
||||||
|
`{$name}` expects feature names
|
||||||
|
|
||||||
|
attr_parsing_import_name_type_raw =
|
||||||
|
import name type can only be used with link kind `raw-dylib`
|
||||||
|
|
||||||
|
attr_parsing_import_name_type_x86 =
|
||||||
|
import name type is only supported on x86
|
||||||
|
|
||||||
|
attr_parsing_incompatible_wasm_link =
|
||||||
|
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_align_one_arg =
|
||||||
|
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_expect_literal_integer =
|
||||||
|
incorrect `repr(align)` attribute format: `align` expects a literal integer as argument
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_generic =
|
||||||
|
incorrect `repr({$repr_arg})` attribute format
|
||||||
|
.suggestion = use parentheses instead
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_packed_expect_integer =
|
||||||
|
incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument
|
||||||
|
|
||||||
|
attr_parsing_incorrect_repr_format_packed_one_or_zero_arg =
|
||||||
|
incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
|
||||||
|
|
||||||
|
attr_parsing_invalid_alignment_value =
|
||||||
|
invalid alignment value: {$error_part}
|
||||||
|
|
||||||
|
attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
|
||||||
|
.label = this is not an unsafe attribute
|
||||||
|
.suggestion = remove the `unsafe(...)`
|
||||||
|
.note = extraneous unsafe is not allowed in attributes
|
||||||
|
|
||||||
|
attr_parsing_invalid_issue_string =
|
||||||
|
`issue` must be a non-zero numeric string or "none"
|
||||||
|
.must_not_be_zero = `issue` must not be "0", use "none" instead
|
||||||
|
.empty = cannot parse integer from empty string
|
||||||
|
.invalid_digit = invalid digit found in string
|
||||||
|
.pos_overflow = number too large to fit in target type
|
||||||
|
.neg_overflow = number too small to fit in target type
|
||||||
|
|
||||||
|
attr_parsing_invalid_link_modifier =
|
||||||
|
invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
|
||||||
|
|
||||||
|
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
|
||||||
|
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
|
||||||
|
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
|
||||||
|
.label = {$descr}s are not allowed here
|
||||||
|
|
||||||
|
attr_parsing_invalid_predicate =
|
||||||
|
invalid predicate `{$predicate}`
|
||||||
|
|
||||||
|
attr_parsing_invalid_repr_align_need_arg =
|
||||||
|
invalid `repr(align)` attribute: `align` needs an argument
|
||||||
|
.suggestion = supply an argument here
|
||||||
|
|
||||||
|
attr_parsing_invalid_repr_generic =
|
||||||
|
invalid `repr({$repr_arg})` attribute: {$error_part}
|
||||||
|
|
||||||
|
attr_parsing_invalid_repr_hint_no_paren =
|
||||||
|
invalid representation hint: `{$name}` does not take a parenthesized argument list
|
||||||
|
|
||||||
|
attr_parsing_invalid_repr_hint_no_value =
|
||||||
|
invalid representation hint: `{$name}` does not take a value
|
||||||
|
|
||||||
|
attr_parsing_invalid_since =
|
||||||
|
'since' must be a Rust version number, such as "1.31.0"
|
||||||
|
|
||||||
|
attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target}
|
||||||
|
.help = `#[{$name}]` can {$only}be applied to {$applied}
|
||||||
|
.suggestion = remove the attribute
|
||||||
|
|
||||||
|
attr_parsing_limit_invalid =
|
||||||
|
`limit` must be a non-negative integer
|
||||||
|
.label = {$error_str}
|
||||||
|
attr_parsing_link_arg_unstable =
|
||||||
|
link kind `link-arg` is unstable
|
||||||
|
|
||||||
|
attr_parsing_link_cfg_unstable =
|
||||||
|
link cfg is unstable
|
||||||
|
|
||||||
|
attr_parsing_link_framework_apple =
|
||||||
|
link kind `framework` is only supported on Apple targets
|
||||||
|
|
||||||
|
attr_parsing_link_ordinal_out_of_range = ordinal value in `link_ordinal` is too large: `{$ordinal}`
|
||||||
|
.note = the value may not exceed `u16::MAX`
|
||||||
|
|
||||||
|
attr_parsing_link_requires_name =
|
||||||
|
`#[link]` attribute requires a `name = "string"` argument
|
||||||
|
.label = missing `name` argument
|
||||||
|
|
||||||
|
attr_parsing_meta_bad_delim = wrong meta list delimiters
|
||||||
|
attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
|
||||||
|
|
||||||
|
attr_parsing_missing_feature =
|
||||||
|
missing 'feature'
|
||||||
|
|
||||||
|
attr_parsing_missing_issue =
|
||||||
|
missing 'issue'
|
||||||
|
|
||||||
|
attr_parsing_missing_note =
|
||||||
|
missing 'note'
|
||||||
|
|
||||||
|
attr_parsing_missing_since =
|
||||||
|
missing 'since'
|
||||||
|
|
||||||
|
attr_parsing_multiple_modifiers =
|
||||||
|
multiple `{$modifier}` modifiers in a single `modifiers` argument
|
||||||
|
|
||||||
|
attr_parsing_multiple_stability_levels =
|
||||||
|
multiple stability levels
|
||||||
|
|
||||||
|
attr_parsing_naked_functions_incompatible_attribute =
|
||||||
|
attribute incompatible with `#[unsafe(naked)]`
|
||||||
|
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
|
||||||
|
.naked_attribute = function marked with `#[unsafe(naked)]` here
|
||||||
|
|
||||||
|
attr_parsing_non_ident_feature =
|
||||||
|
'feature' is not an identifier
|
||||||
|
|
||||||
|
attr_parsing_null_on_export = `export_name` may not contain null characters
|
||||||
|
|
||||||
|
attr_parsing_null_on_link_section = `link_section` may not contain null characters
|
||||||
|
|
||||||
|
attr_parsing_null_on_objc_class = `objc::class!` may not contain null characters
|
||||||
|
|
||||||
|
attr_parsing_null_on_objc_selector = `objc::selector!` may not contain null characters
|
||||||
|
|
||||||
|
attr_parsing_objc_class_expected_string_literal = `objc::class!` expected a string literal
|
||||||
|
|
||||||
|
attr_parsing_objc_selector_expected_string_literal = `objc::selector!` expected a string literal
|
||||||
|
|
||||||
|
attr_parsing_raw_dylib_elf_unstable =
|
||||||
|
link kind `raw-dylib` is unstable on ELF platforms
|
||||||
|
|
||||||
|
attr_parsing_raw_dylib_no_nul =
|
||||||
|
link name must not contain NUL characters if link kind is `raw-dylib`
|
||||||
|
|
||||||
|
attr_parsing_raw_dylib_only_windows =
|
||||||
|
link kind `raw-dylib` is only supported on Windows targets
|
||||||
|
|
||||||
|
attr_parsing_repr_ident =
|
||||||
|
meta item in `repr` must be an identifier
|
||||||
|
|
||||||
|
attr_parsing_rustc_allowed_unstable_pairing =
|
||||||
|
`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
|
||||||
|
|
||||||
|
attr_parsing_rustc_promotable_pairing =
|
||||||
|
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
|
||||||
|
|
||||||
|
attr_parsing_rustc_scalable_vector_count_out_of_range = element count in `rustc_scalable_vector` is too large: `{$n}`
|
||||||
|
.note = the value may not exceed `u16::MAX`
|
||||||
|
|
||||||
|
attr_parsing_soft_no_args =
|
||||||
|
`soft` should not have any arguments
|
||||||
|
|
||||||
|
attr_parsing_stability_outside_std = stability attributes may not be used outside of the standard library
|
||||||
|
|
||||||
|
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
|
||||||
|
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||||
|
|
||||||
|
attr_parsing_unknown_version_literal =
|
||||||
|
unknown version literal format, assuming it refers to a future version
|
||||||
|
|
||||||
|
attr_parsing_unrecognized_repr_hint =
|
||||||
|
unrecognized representation hint
|
||||||
|
.help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
|
||||||
|
.note = for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
|
||||||
|
|
||||||
|
attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||||
|
.label = usage of unsafe attribute
|
||||||
|
attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||||
|
|
||||||
|
attr_parsing_unstable_cfg_target_compact =
|
||||||
|
compact `cfg(target(..))` is experimental and subject to change
|
||||||
|
|
||||||
|
attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable
|
||||||
|
.help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||||
|
|
||||||
|
attr_parsing_unsupported_instruction_set = target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`
|
||||||
|
|
||||||
|
attr_parsing_unsupported_literal_suggestion =
|
||||||
|
consider removing the prefix
|
||||||
|
|
||||||
|
attr_parsing_unused_multiple =
|
||||||
|
multiple `{$name}` attributes
|
||||||
|
.suggestion = remove this attribute
|
||||||
|
.note = attribute also specified here
|
||||||
|
|
||||||
|
attr_parsing_whole_archive_needs_static =
|
||||||
|
linking modifier `whole-archive` is only compatible with `static` linking kind
|
||||||
|
|
@ -29,7 +29,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
||||||
|
|
||||||
pub(crate) struct UnstableFeatureBoundParser;
|
pub(crate) struct UnstableFeatureBoundParser;
|
||||||
impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
|
impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
|
||||||
const PATH: &[rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
||||||
type Item = (Symbol, Span);
|
type Item = (Symbol, Span);
|
||||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
|
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
|
|
@ -57,7 +57,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||||
type Item = Symbol;
|
type Item = Symbol;
|
||||||
const CONVERT: ConvertFn<Self::Item> =
|
const CONVERT: ConvertFn<Self::Item> =
|
||||||
|items, first_span| AttributeKind::RustcAllowConstFnUnstable(items, first_span);
|
|items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
Allow(Target::Fn),
|
Allow(Target::Fn),
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ use std::convert::identity;
|
||||||
use rustc_ast::token::Delimiter;
|
use rustc_ast::token::Delimiter;
|
||||||
use rustc_ast::tokenstream::DelimSpan;
|
use rustc_ast::tokenstream::DelimSpan;
|
||||||
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
|
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
|
||||||
use rustc_errors::{Applicability, PResult, msg};
|
use rustc_errors::{Applicability, PResult};
|
||||||
use rustc_feature::{
|
use rustc_feature::{
|
||||||
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
|
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
|
||||||
};
|
};
|
||||||
use rustc_hir::attrs::CfgEntry;
|
use rustc_hir::attrs::CfgEntry;
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
use rustc_hir::lints::AttributeLintKind;
|
||||||
use rustc_hir::{AttrPath, RustcVersion, Target};
|
use rustc_hir::{AttrPath, RustcVersion, Target};
|
||||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
use rustc_parse::parser::{ForceCollect, Parser};
|
||||||
use rustc_parse::{exp, parse_in};
|
use rustc_parse::{exp, parse_in};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::config::ExpectedValues;
|
use rustc_session::config::ExpectedValues;
|
||||||
|
|
@ -25,7 +25,7 @@ use crate::session_diagnostics::{
|
||||||
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
|
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
|
||||||
ParsedDescription,
|
ParsedDescription,
|
||||||
};
|
};
|
||||||
use crate::{AttributeParser, parse_version, session_diagnostics};
|
use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics};
|
||||||
|
|
||||||
pub const CFG_TEMPLATE: AttributeTemplate = template!(
|
pub const CFG_TEMPLATE: AttributeTemplate = template!(
|
||||||
List: &["predicate"],
|
List: &["predicate"],
|
||||||
|
|
@ -141,7 +141,7 @@ fn parse_cfg_entry_target<S: Stage>(
|
||||||
cx.sess(),
|
cx.sess(),
|
||||||
sym::cfg_target_compact,
|
sym::cfg_target_compact,
|
||||||
meta_span,
|
meta_span,
|
||||||
msg!("compact `cfg(target(..))` is experimental and subject to change"),
|
fluent_generated::attr_parsing_unstable_cfg_target_compact,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -360,10 +360,7 @@ fn parse_cfg_attr_internal<'a>(
|
||||||
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
|
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
|
||||||
// Parse cfg predicate
|
// Parse cfg predicate
|
||||||
let pred_start = parser.token.span;
|
let pred_start = parser.token.span;
|
||||||
let meta = MetaItemOrLitParser::parse_single(
|
let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?;
|
||||||
parser,
|
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
|
||||||
)?;
|
|
||||||
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
||||||
|
|
||||||
let cfg_predicate = AttributeParser::parse_single_args(
|
let cfg_predicate = AttributeParser::parse_single_args(
|
||||||
|
|
@ -378,7 +375,7 @@ fn parse_cfg_attr_internal<'a>(
|
||||||
CRATE_NODE_ID,
|
CRATE_NODE_ID,
|
||||||
Target::Crate,
|
Target::Crate,
|
||||||
features,
|
features,
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
ShouldEmit::ErrorsAndLints,
|
||||||
&meta,
|
&meta,
|
||||||
parse_cfg_entry,
|
parse_cfg_entry,
|
||||||
&CFG_ATTR_TEMPLATE,
|
&CFG_ATTR_TEMPLATE,
|
||||||
|
|
@ -415,6 +412,7 @@ 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) {
|
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
|
||||||
let (cfg, feature, has_feature) = gated_cfg;
|
let (cfg, feature, has_feature) = gated_cfg;
|
||||||
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
|
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,22 @@
|
||||||
use rustc_ast::token::Token;
|
use rustc_ast::token::Token;
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_ast::{AttrStyle, NodeId, token};
|
use rustc_ast::{AttrStyle, NodeId, token};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
|
||||||
use rustc_feature::{AttributeTemplate, Features};
|
use rustc_feature::{AttributeTemplate, Features};
|
||||||
use rustc_hir::attrs::CfgEntry;
|
use rustc_hir::attrs::CfgEntry;
|
||||||
use rustc_hir::{AttrPath, Target};
|
use rustc_hir::{AttrPath, Target};
|
||||||
use rustc_parse::exp;
|
use rustc_parse::exp;
|
||||||
use rustc_parse::parser::{Parser, Recovery};
|
use rustc_parse::parser::Parser;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::lint::BuiltinLintDiag;
|
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||||
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
|
|
||||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
|
||||||
|
|
||||||
use crate::parser::MetaItemOrLitParser;
|
use crate::parser::MetaItemOrLitParser;
|
||||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum CfgSelectPredicate {
|
pub enum CfgSelectPredicate {
|
||||||
Cfg(CfgEntry),
|
Cfg(CfgEntry),
|
||||||
Wildcard(Token),
|
Wildcard(Token),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CfgSelectPredicate {
|
|
||||||
fn span(&self) -> Span {
|
|
||||||
match self {
|
|
||||||
CfgSelectPredicate::Cfg(cfg_entry) => cfg_entry.span(),
|
|
||||||
CfgSelectPredicate::Wildcard(token) => token.span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CfgSelectBranches {
|
pub struct CfgSelectBranches {
|
||||||
/// All the conditional branches.
|
/// All the conditional branches.
|
||||||
|
|
@ -91,10 +78,7 @@ pub fn parse_cfg_select(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let meta = MetaItemOrLitParser::parse_single(
|
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
|
||||||
p,
|
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
|
||||||
)
|
|
||||||
.map_err(|diag| diag.emit())?;
|
.map_err(|diag| diag.emit())?;
|
||||||
let cfg_span = meta.span();
|
let cfg_span = meta.span();
|
||||||
let cfg = AttributeParser::parse_single_args(
|
let cfg = AttributeParser::parse_single_args(
|
||||||
|
|
@ -110,7 +94,7 @@ pub fn parse_cfg_select(
|
||||||
// Doesn't matter what the target actually is here.
|
// Doesn't matter what the target actually is here.
|
||||||
Target::Crate,
|
Target::Crate,
|
||||||
features,
|
features,
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
ShouldEmit::ErrorsAndLints,
|
||||||
&meta,
|
&meta,
|
||||||
parse_cfg_entry,
|
parse_cfg_entry,
|
||||||
&AttributeTemplate::default(),
|
&AttributeTemplate::default(),
|
||||||
|
|
@ -128,102 +112,5 @@ pub fn parse_cfg_select(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(features) = features
|
|
||||||
&& features.enabled(sym::cfg_select)
|
|
||||||
{
|
|
||||||
let it = branches
|
|
||||||
.reachable
|
|
||||||
.iter()
|
|
||||||
.map(|(entry, _, _)| CfgSelectPredicate::Cfg(entry.clone()))
|
|
||||||
.chain(branches.wildcard.as_ref().map(|(t, _, _)| CfgSelectPredicate::Wildcard(*t)))
|
|
||||||
.chain(
|
|
||||||
branches.unreachable.iter().map(|(entry, _, _)| CfgSelectPredicate::clone(entry)),
|
|
||||||
);
|
|
||||||
|
|
||||||
lint_unreachable(p, it, lint_node_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(branches)
|
Ok(branches)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_unreachable(
|
|
||||||
p: &mut Parser<'_>,
|
|
||||||
predicates: impl Iterator<Item = CfgSelectPredicate>,
|
|
||||||
lint_node_id: NodeId,
|
|
||||||
) {
|
|
||||||
// Symbols that have a known value.
|
|
||||||
let mut known = FxHashMap::<Symbol, bool>::default();
|
|
||||||
let mut wildcard_span = None;
|
|
||||||
let mut it = predicates;
|
|
||||||
|
|
||||||
let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| {
|
|
||||||
let span = predicate.span();
|
|
||||||
p.psess.buffer_lint(
|
|
||||||
UNREACHABLE_CFG_SELECT_PREDICATES,
|
|
||||||
span,
|
|
||||||
lint_node_id,
|
|
||||||
BuiltinLintDiag::UnreachableCfg { span, wildcard_span },
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
for predicate in &mut it {
|
|
||||||
let CfgSelectPredicate::Cfg(ref cfg_entry) = predicate else {
|
|
||||||
wildcard_span = Some(predicate.span());
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
match cfg_entry {
|
|
||||||
CfgEntry::Bool(true, _) => {
|
|
||||||
wildcard_span = Some(predicate.span());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
CfgEntry::Bool(false, _) => continue,
|
|
||||||
CfgEntry::NameValue { name, value, .. } => match value {
|
|
||||||
None => {
|
|
||||||
// `name` will be false in all subsequent branches.
|
|
||||||
let current = known.insert(*name, false);
|
|
||||||
|
|
||||||
match current {
|
|
||||||
None => continue,
|
|
||||||
Some(false) => {
|
|
||||||
branch_is_unreachable(predicate, None);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Some(true) => {
|
|
||||||
// this branch will be taken, so all subsequent branches are unreachable.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(_) => { /* for now we don't bother solving these */ }
|
|
||||||
},
|
|
||||||
CfgEntry::Not(inner, _) => match &**inner {
|
|
||||||
CfgEntry::NameValue { name, value: None, .. } => {
|
|
||||||
// `name` will be true in all subsequent branches.
|
|
||||||
let current = known.insert(*name, true);
|
|
||||||
|
|
||||||
match current {
|
|
||||||
None => continue,
|
|
||||||
Some(true) => {
|
|
||||||
branch_is_unreachable(predicate, None);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Some(false) => {
|
|
||||||
// this branch will be taken, so all subsequent branches are unreachable.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => { /* for now we don't bother solving these */ }
|
|
||||||
},
|
|
||||||
CfgEntry::All(_, _) | CfgEntry::Any(_, _) => {
|
|
||||||
/* for now we don't bother solving these */
|
|
||||||
}
|
|
||||||
CfgEntry::Version(..) => { /* don't bother solving these */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for predicate in it {
|
|
||||||
branch_is_unreachable(predicate, wildcard_span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser {
|
||||||
cx.emit_err(NullOnObjcClass { span: nv.value_span });
|
cx.emit_err(NullOnObjcClass { span: nv.value_span });
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(AttributeKind::RustcObjcClass { classname, span: cx.attr_span })
|
Some(AttributeKind::ObjcClass { classname, span: cx.attr_span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,7 +213,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcSelectorParser {
|
||||||
cx.emit_err(NullOnObjcSelector { span: nv.value_span });
|
cx.emit_err(NullOnObjcSelector { span: nv.value_span });
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(AttributeKind::RustcObjcSelector { methname, span: cx.attr_span })
|
Some(AttributeKind::ObjcSelector { methname, span: cx.attr_span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -717,100 +717,3 @@ impl<S: Stage> NoArgsAttributeParser<S> for EiiForeignItemParser {
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiForeignItem;
|
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),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(AttributeKind::RustcConfusables {
|
Some(AttributeKind::Confusables {
|
||||||
symbols: self.confusables,
|
symbols: self.confusables,
|
||||||
first_span: self.first_span.unwrap(),
|
first_span: self.first_span.unwrap(),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
|
use rustc_hir::attrs::WindowsSubsystemKind;
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
|
||||||
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
|
|
||||||
use rustc_span::Symbol;
|
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
||||||
|
|
@ -30,56 +26,6 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CrateTypeParser;
|
|
||||||
|
|
||||||
impl<S: Stage> CombineAttributeParser<S> for CrateTypeParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::crate_type];
|
|
||||||
type Item = CrateType;
|
|
||||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::CrateType(items);
|
|
||||||
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
|
|
||||||
const TEMPLATE: AttributeTemplate =
|
|
||||||
template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html");
|
|
||||||
|
|
||||||
fn extend(
|
|
||||||
cx: &mut AcceptContext<'_, '_, S>,
|
|
||||||
args: &ArgParser,
|
|
||||||
) -> impl IntoIterator<Item = Self::Item> {
|
|
||||||
let ArgParser::NameValue(n) = args else {
|
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(crate_type) = n.value_as_str() else {
|
|
||||||
cx.expected_string_literal(n.value_span, Some(n.value_as_lit()));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(crate_type) = crate_type.try_into() else {
|
|
||||||
// We don't error on invalid `#![crate_type]` when not applied to a crate
|
|
||||||
if cx.shared.target == Target::Crate {
|
|
||||||
let candidate = find_best_match_for_name(
|
|
||||||
&CrateType::all_stable().iter().map(|(name, _)| *name).collect::<Vec<_>>(),
|
|
||||||
crate_type,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
cx.emit_lint(
|
|
||||||
UNKNOWN_CRATE_TYPES,
|
|
||||||
AttributeLintKind::CrateTypeUnknown {
|
|
||||||
span: n.value_span,
|
|
||||||
suggested: candidate,
|
|
||||||
},
|
|
||||||
n.value_span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(crate_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RecursionLimitParser;
|
pub(crate) struct RecursionLimitParser;
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
||||||
|
|
@ -190,15 +136,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct NoMainParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::no_main];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcCoherenceIsCoreParser;
|
pub(crate) struct RustcCoherenceIsCoreParser;
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
|
||||||
|
|
@ -238,66 +175,3 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
||||||
Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
|
Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PanicRuntimeParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::panic_runtime];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct NeedsPanicRuntimeParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct ProfilerRuntimeParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::profiler_runtime];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct NoBuiltinsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::no_builtins];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcPreserveUbChecksParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcPreserveUbChecksParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcNoImplicitBoundsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct DefaultLibAllocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::default_lib_allocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
|
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
|
||||||
use rustc_hir::{RustcVersion, VERSION_PLACEHOLDER};
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::util::parse_version;
|
use super::util::parse_version;
|
||||||
|
|
@ -144,8 +143,6 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
||||||
DeprecatedSince::Future
|
DeprecatedSince::Future
|
||||||
} else if !is_rustc {
|
} else if !is_rustc {
|
||||||
DeprecatedSince::NonStandard(since)
|
DeprecatedSince::NonStandard(since)
|
||||||
} else if since.as_str() == VERSION_PLACEHOLDER {
|
|
||||||
DeprecatedSince::RustcVersion(RustcVersion::CURRENT)
|
|
||||||
} else if let Some(version) = parse_version(since) {
|
} else if let Some(version) = parse_version(since) {
|
||||||
DeprecatedSince::RustcVersion(version)
|
DeprecatedSince::RustcVersion(version)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,6 @@ impl<S: Stage> SingleAttributeParser<S> for DummyParser {
|
||||||
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
|
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
|
||||||
|
|
||||||
fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser) -> Option<AttributeKind> {
|
fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser) -> Option<AttributeKind> {
|
||||||
Some(AttributeKind::RustcDummy)
|
Some(AttributeKind::Dummy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use super::prelude::*;
|
||||||
pub(crate) struct InlineParser;
|
pub(crate) struct InlineParser;
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||||
const PATH: &[Symbol] = &[sym::inline];
|
const PATH: &'static [Symbol] = &[sym::inline];
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
|
|
@ -67,7 +67,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||||
pub(crate) struct RustcForceInlineParser;
|
pub(crate) struct RustcForceInlineParser;
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_force_inline];
|
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use rustc_errors::msg;
|
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
|
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
|
||||||
use rustc_hir::attrs::*;
|
use rustc_hir::attrs::*;
|
||||||
|
|
@ -11,11 +10,12 @@ use rustc_target::spec::{Arch, BinaryFormat};
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::util::parse_single_integer;
|
use super::util::parse_single_integer;
|
||||||
use crate::attributes::cfg::parse_cfg_entry;
|
use crate::attributes::cfg::parse_cfg_entry;
|
||||||
|
use crate::fluent_generated;
|
||||||
use crate::session_diagnostics::{
|
use crate::session_diagnostics::{
|
||||||
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
|
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86,
|
||||||
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
|
IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
|
||||||
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
|
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
|
||||||
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
|
WholeArchiveNeedsStatic,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct LinkNameParser;
|
pub(crate) struct LinkNameParser;
|
||||||
|
|
@ -141,6 +141,8 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||||
|
|
||||||
macro report_unstable_modifier($feature: ident) {
|
macro report_unstable_modifier($feature: ident) {
|
||||||
if !features.$feature() {
|
if !features.$feature() {
|
||||||
|
// FIXME: make this translatable
|
||||||
|
#[expect(rustc::untranslatable_diagnostic)]
|
||||||
feature_err(
|
feature_err(
|
||||||
sess,
|
sess,
|
||||||
sym::$feature,
|
sym::$feature,
|
||||||
|
|
@ -165,14 +167,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||||
cx.emit_err(BundleNeedsStatic { span });
|
cx.emit_err(BundleNeedsStatic { span });
|
||||||
}
|
}
|
||||||
|
|
||||||
(sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
|
|
||||||
assign_modifier(export_symbols)
|
|
||||||
}
|
|
||||||
|
|
||||||
(sym::export_symbols, _) => {
|
|
||||||
cx.emit_err(ExportSymbolsNeedsStatic { span });
|
|
||||||
}
|
|
||||||
|
|
||||||
(sym::verbatim, _) => assign_modifier(&mut verbatim),
|
(sym::verbatim, _) => assign_modifier(&mut verbatim),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
@ -198,7 +192,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
||||||
span,
|
span,
|
||||||
&[
|
&[
|
||||||
sym::bundle,
|
sym::bundle,
|
||||||
sym::export_symbols,
|
|
||||||
sym::verbatim,
|
sym::verbatim,
|
||||||
sym::whole_dash_archive,
|
sym::whole_dash_archive,
|
||||||
sym::as_dash_needed,
|
sym::as_dash_needed,
|
||||||
|
|
@ -294,9 +287,7 @@ impl LinkParser {
|
||||||
};
|
};
|
||||||
|
|
||||||
let link_kind = match link_kind {
|
let link_kind = match link_kind {
|
||||||
kw::Static => {
|
kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
|
||||||
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
|
|
||||||
}
|
|
||||||
sym::dylib => NativeLibKind::Dylib { as_needed: None },
|
sym::dylib => NativeLibKind::Dylib { as_needed: None },
|
||||||
sym::framework => {
|
sym::framework => {
|
||||||
if !sess.target.is_like_darwin {
|
if !sess.target.is_like_darwin {
|
||||||
|
|
@ -316,7 +307,7 @@ impl LinkParser {
|
||||||
sess,
|
sess,
|
||||||
sym::raw_dylib_elf,
|
sym::raw_dylib_elf,
|
||||||
nv.value_span,
|
nv.value_span,
|
||||||
msg!("link kind `raw-dylib` is unstable on ELF platforms"),
|
fluent_generated::attr_parsing_raw_dylib_elf_unstable,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -331,7 +322,7 @@ impl LinkParser {
|
||||||
sess,
|
sess,
|
||||||
sym::link_arg_attribute,
|
sym::link_arg_attribute,
|
||||||
nv.value_span,
|
nv.value_span,
|
||||||
msg!("link kind `link-arg` is unstable"),
|
fluent_generated::attr_parsing_link_arg_unstable,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
@ -396,7 +387,13 @@ impl LinkParser {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if !features.link_cfg() {
|
if !features.link_cfg() {
|
||||||
feature_err(sess, sym::link_cfg, item.span(), msg!("link cfg is unstable")).emit();
|
feature_err(
|
||||||
|
sess,
|
||||||
|
sym::link_cfg,
|
||||||
|
item.span(),
|
||||||
|
fluent_generated::attr_parsing_link_cfg_unstable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
*cfg = parse_cfg_entry(cx, link_cfg).ok();
|
*cfg = parse_cfg_entry(cx, link_cfg).ok();
|
||||||
true
|
true
|
||||||
|
|
@ -534,7 +531,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
|
||||||
Allow(Target::Static),
|
Allow(Target::Static),
|
||||||
Allow(Target::ForeignStatic),
|
Allow(Target::ForeignStatic),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct LinkOrdinalParser;
|
pub(crate) struct LinkOrdinalParser;
|
||||||
|
|
@ -661,21 +658,3 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
||||||
Some(AttributeKind::Linkage(linkage, cx.attr_span))
|
Some(AttributeKind::Linkage(linkage, cx.attr_span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct NeedsAllocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::needs_allocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct CompilerBuiltinsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::compiler_builtins];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser {
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAsPtr;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PubTransparentParser;
|
pub(crate) struct PubTransparentParser;
|
||||||
|
|
@ -23,7 +23,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser {
|
||||||
Allow(Target::Enum),
|
Allow(Target::Enum),
|
||||||
Allow(Target::Union),
|
Allow(Target::Union),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PassByValueParser;
|
pub(crate) struct PassByValueParser;
|
||||||
|
|
@ -35,7 +35,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser {
|
||||||
Allow(Target::Enum),
|
Allow(Target::Enum),
|
||||||
Allow(Target::TyAlias),
|
Allow(Target::TyAlias),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassByValue;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcShouldNotBeCalledOnConstItems;
|
pub(crate) struct RustcShouldNotBeCalledOnConstItems;
|
||||||
|
|
|
||||||
|
|
@ -206,12 +206,3 @@ impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
|
||||||
Some(AttributeKind::CollapseDebugInfo(info))
|
Some(AttributeKind::CollapseDebugInfo(info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcProcMacroDeclsParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcProcMacroDeclsParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_proc_macro_decls];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcProcMacroDecls;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ pub(crate) mod pin_v2;
|
||||||
pub(crate) mod proc_macro_attrs;
|
pub(crate) mod proc_macro_attrs;
|
||||||
pub(crate) mod prototype;
|
pub(crate) mod prototype;
|
||||||
pub(crate) mod repr;
|
pub(crate) mod repr;
|
||||||
pub(crate) mod rustc_allocator;
|
|
||||||
pub(crate) mod rustc_dump;
|
pub(crate) mod rustc_dump;
|
||||||
pub(crate) mod rustc_internal;
|
pub(crate) mod rustc_internal;
|
||||||
pub(crate) mod semantics;
|
pub(crate) mod semantics;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
|
||||||
use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS;
|
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
||||||
const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
|
const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
|
||||||
|
|
@ -129,13 +126,6 @@ fn parse_derive_like<S: Stage>(
|
||||||
cx.expected_identifier(ident.span);
|
cx.expected_identifier(ident.span);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if rustc_feature::is_builtin_attr_name(ident.name) {
|
|
||||||
cx.emit_lint(
|
|
||||||
AMBIGUOUS_DERIVE_HELPERS,
|
|
||||||
AttributeLintKind::AmbiguousDeriveHelpers,
|
|
||||||
ident.span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
attributes.push(ident.name);
|
attributes.push(ident.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@ fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
|
||||||
pub(crate) struct AlignParser(Option<(Align, Span)>);
|
pub(crate) struct AlignParser(Option<(Align, Span)>);
|
||||||
|
|
||||||
impl AlignParser {
|
impl AlignParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_align];
|
const PATH: &'static [Symbol] = &[sym::rustc_align];
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
|
const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
|
||||||
|
|
||||||
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
||||||
|
|
@ -329,7 +329,7 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
|
||||||
pub(crate) struct AlignStaticParser(AlignParser);
|
pub(crate) struct AlignStaticParser(AlignParser);
|
||||||
|
|
||||||
impl AlignStaticParser {
|
impl AlignStaticParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_align_static];
|
const PATH: &'static [Symbol] = &[sym::rustc_align_static];
|
||||||
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
||||||
|
|
||||||
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
use super::prelude::*;
|
|
||||||
|
|
||||||
pub(crate) struct RustcAllocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_allocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcAllocatorZeroedParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorZeroedParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcAllocatorZeroedVariantParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RustcAllocatorZeroedVariantParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed_variant];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function");
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(name) = args.name_value().and_then(NameValueParser::value_as_str) else {
|
|
||||||
cx.expected_name_value(cx.attr_span, None);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::RustcAllocatorZeroedVariant { name })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcDeallocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDeallocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_deallocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcReallocatorParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcReallocatorParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_reallocator];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcReallocator;
|
|
||||||
}
|
|
||||||
|
|
@ -7,36 +7,36 @@ use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
||||||
use crate::context::Stage;
|
use crate::context::Stage;
|
||||||
use crate::target_checking::AllowedTargets;
|
use crate::target_checking::AllowedTargets;
|
||||||
|
|
||||||
pub(crate) struct RustcDumpUserArgsParser;
|
pub(crate) struct RustcDumpUserArgs;
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgsParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgs {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_user_args];
|
const PATH: &[Symbol] = &[sym::rustc_dump_user_args];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
|
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcDumpDefParentsParser;
|
pub(crate) struct RustcDumpDefParents;
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParentsParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParents {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_def_parents];
|
const PATH: &[Symbol] = &[sym::rustc_dump_def_parents];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
|
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcDumpItemBoundsParser;
|
pub(crate) struct RustcDumpItemBounds;
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBoundsParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBounds {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds];
|
const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
|
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcDumpPredicatesParser;
|
pub(crate) struct RustcDumpPredicates;
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicates {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_predicates];
|
const PATH: &[Symbol] = &[sym::rustc_dump_predicates];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
|
|
@ -49,9 +49,9 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
|
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcDumpVtableParser;
|
pub(crate) struct RustcDumpVtable;
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtableParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtable {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dump_vtable];
|
const PATH: &[Symbol] = &[sym::rustc_dump_vtable];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -173,7 +173,7 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
|
||||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||||
let (stability, span) = self.stability?;
|
let (stability, span) = self.stability?;
|
||||||
|
|
||||||
Some(AttributeKind::RustcBodyStability { stability, span })
|
Some(AttributeKind::BodyStability { stability, span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser {
|
||||||
Allow(Target::Fn),
|
Allow(Target::Fn),
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
Allow(Target::Method(MethodKind::Inherent)),
|
||||||
]);
|
]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConstStabilityIndirect;
|
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -244,20 +244,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||||
this.promotable = true;
|
this.promotable = true;
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
|
||||||
Allow(Target::Impl { of_trait: false }),
|
|
||||||
Allow(Target::Impl { of_trait: true }),
|
|
||||||
Allow(Target::Use), // FIXME I don't think this does anything?
|
|
||||||
Allow(Target::Const),
|
|
||||||
Allow(Target::AssocConst),
|
|
||||||
Allow(Target::Trait),
|
|
||||||
Allow(Target::Static),
|
|
||||||
Allow(Target::Crate),
|
|
||||||
]);
|
|
||||||
|
|
||||||
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||||
if self.promotable {
|
if self.promotable {
|
||||||
|
|
@ -271,7 +258,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||||
|
|
||||||
let (stability, span) = self.stability?;
|
let (stability, span) = self.stability?;
|
||||||
|
|
||||||
Some(AttributeKind::RustcConstStability { stability, span })
|
Some(AttributeKind::ConstStability { stability, span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use rustc_hir::attrs::RustcAbiAttrKind;
|
|
||||||
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
@ -92,201 +91,3 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RustcVarianceParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_variance];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Struct),
|
|
||||||
Allow(Target::Enum),
|
|
||||||
Allow(Target::Union),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVariance;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcVarianceOfOpaquesParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceOfOpaquesParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_variance_of_opaques];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVarianceOfOpaques;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct ReexportTestHarnessMainParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for ReexportTestHarnessMainParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::reexport_test_harness_main];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(nv) = args.name_value() else {
|
|
||||||
cx.expected_name_value(
|
|
||||||
args.span().unwrap_or(cx.inner_span),
|
|
||||||
Some(sym::reexport_test_harness_main),
|
|
||||||
);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(name) = nv.value_as_str() else {
|
|
||||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::ReexportTestHarnessMain(name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcAbiParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RustcAbiParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_abi];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::debug, sym::assert_eq]);
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::TyAlias),
|
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::ForeignFn),
|
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
|
||||||
]);
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(args) = args.list() else {
|
|
||||||
cx.expected_specific_argument_and_list(cx.attr_span, &[sym::assert_eq, sym::debug]);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(arg) = args.single() else {
|
|
||||||
cx.expected_single_argument(cx.attr_span);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let fail_incorrect_argument =
|
|
||||||
|span| cx.expected_specific_argument(span, &[sym::assert_eq, sym::debug]);
|
|
||||||
|
|
||||||
let Some(arg) = arg.meta_item() else {
|
|
||||||
fail_incorrect_argument(args.span);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let kind: RustcAbiAttrKind = match arg.path().word_sym() {
|
|
||||||
Some(sym::assert_eq) => RustcAbiAttrKind::AssertEq,
|
|
||||||
Some(sym::debug) => RustcAbiAttrKind::Debug,
|
|
||||||
None | Some(_) => {
|
|
||||||
fail_incorrect_argument(arg.span());
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::RustcAbi { attr_span: cx.attr_span, kind })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcDelayedBugFromInsideQueryParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDelayedBugFromInsideQueryParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_delayed_bug_from_inside_query];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDelayedBugFromInsideQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcEvaluateWhereClausesParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcEvaluateWhereClausesParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_evaluate_where_clauses];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::Method(MethodKind::Inherent)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
|
||||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
|
||||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEvaluateWhereClauses;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcOutlivesParser;
|
|
||||||
|
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcOutlivesParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_outlives];
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Struct),
|
|
||||||
Allow(Target::Enum),
|
|
||||||
Allow(Target::Union),
|
|
||||||
Allow(Target::TyAlias),
|
|
||||||
]);
|
|
||||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOutlives;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct TestRunnerParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::test_runner];
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(List: &["path"]);
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(list) = args.list() else {
|
|
||||||
cx.expected_list(cx.attr_span, args);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(single) = list.single() else {
|
|
||||||
cx.expected_single_argument(list.span);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(meta) = single.meta_item() else {
|
|
||||||
cx.unexpected_literal(single.span());
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(AttributeKind::TestRunner(meta.path().0.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct RustcTestMarkerParser;
|
|
||||||
|
|
||||||
impl<S: Stage> SingleAttributeParser<S> for RustcTestMarkerParser {
|
|
||||||
const PATH: &[Symbol] = &[sym::rustc_test_marker];
|
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|
||||||
Allow(Target::Const),
|
|
||||||
Allow(Target::Fn),
|
|
||||||
Allow(Target::Static),
|
|
||||||
]);
|
|
||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "test_path");
|
|
||||||
|
|
||||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
|
||||||
let Some(name_value) = args.name_value() else {
|
|
||||||
cx.expected_name_value(cx.attr_span, Some(sym::rustc_test_marker));
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(value_str) = name_value.value_as_str() else {
|
|
||||||
cx.expected_string_literal(name_value.value_span, None);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
if value_str.as_str().trim().is_empty() {
|
|
||||||
cx.expected_non_empty_string_literal(name_value.value_span);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(AttributeKind::RustcTestMarker(value_str))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,7 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
|
||||||
cx.duplicate_key(arg.span(), key);
|
cx.duplicate_key(arg.span(), key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(AttributeKind::RustcSkipDuringMethodDispatch {
|
Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
|
||||||
array,
|
|
||||||
boxed_slice,
|
|
||||||
span: cx.attr_span,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,7 +59,16 @@ impl<S: Stage> NoArgsAttributeParser<S> for ParenSugarParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
|
const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ParenSugar;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TypeConstParser;
|
||||||
|
impl<S: Stage> NoArgsAttributeParser<S> for TypeConstParser {
|
||||||
|
const PATH: &[Symbol] = &[sym::type_const];
|
||||||
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
|
const ALLOWED_TARGETS: AllowedTargets =
|
||||||
|
AllowedTargets::AllowList(&[Allow(Target::Const), Allow(Target::AssocConst)]);
|
||||||
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Markers
|
// Markers
|
||||||
|
|
@ -86,15 +91,15 @@ impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
|
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDenyExplicitImpl;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DynIncompatibleTraitParser;
|
pub(crate) struct DoNotImplementViaObjectParser;
|
||||||
impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
|
impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
|
const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDynIncompatibleTrait;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specialization
|
// Specialization
|
||||||
|
|
@ -104,7 +109,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for SpecializationTraitParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
|
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcSpecializationTrait;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::SpecializationTrait;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct UnsafeSpecializationMarkerParser;
|
pub(crate) struct UnsafeSpecializationMarkerParser;
|
||||||
|
|
@ -112,7 +117,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for UnsafeSpecializationMarkerParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
|
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcUnsafeSpecializationMarker;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coherence
|
// Coherence
|
||||||
|
|
@ -122,7 +127,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for CoinductiveParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_coinductive];
|
const PATH: &[Symbol] = &[sym::rustc_coinductive];
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoinductive;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Coinductive;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct AllowIncoherentImplParser;
|
pub(crate) struct AllowIncoherentImplParser;
|
||||||
|
|
@ -131,7 +136,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
|
||||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||||
const ALLOWED_TARGETS: AllowedTargets =
|
const ALLOWED_TARGETS: AllowedTargets =
|
||||||
AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
|
AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
|
||||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAllowIncoherentImpl;
|
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FundamentalParser;
|
pub(crate) struct FundamentalParser;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ use super::prelude::*;
|
||||||
|
|
||||||
pub(crate) struct TransparencyParser;
|
pub(crate) struct TransparencyParser;
|
||||||
|
|
||||||
|
// FIXME(jdonszelmann): make these proper diagnostics
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
||||||
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
||||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||||
|
|
@ -32,6 +35,6 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
.map(AttributeKind::RustcMacroTransparency)
|
.map(AttributeKind::MacroTransparency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::btree_map::Entry;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
|
@ -11,48 +10,85 @@ use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
|
||||||
use rustc_hir::attrs::AttributeKind;
|
use rustc_hir::attrs::AttributeKind;
|
||||||
use rustc_hir::lints::AttributeLintKind;
|
use rustc_hir::lints::AttributeLintKind;
|
||||||
use rustc_hir::{AttrPath, HirId};
|
use rustc_hir::{AttrPath, HirId};
|
||||||
use rustc_parse::parser::Recovery;
|
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::lint::{Lint, LintId};
|
use rustc_session::lint::{Lint, LintId};
|
||||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||||
|
|
||||||
use crate::AttributeParser;
|
use crate::AttributeParser;
|
||||||
// Glob imports to avoid big, bitrotty import lists
|
use crate::attributes::allow_unstable::{
|
||||||
use crate::attributes::allow_unstable::*;
|
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
|
||||||
use crate::attributes::body::*;
|
};
|
||||||
use crate::attributes::cfi_encoding::*;
|
use crate::attributes::body::CoroutineParser;
|
||||||
use crate::attributes::codegen_attrs::*;
|
use crate::attributes::cfi_encoding::CfiEncodingParser;
|
||||||
use crate::attributes::confusables::*;
|
use crate::attributes::codegen_attrs::{
|
||||||
use crate::attributes::crate_level::*;
|
ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser,
|
||||||
use crate::attributes::debugger::*;
|
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
|
||||||
use crate::attributes::deprecation::*;
|
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
|
||||||
use crate::attributes::do_not_recommend::*;
|
ThreadLocalParser, TrackCallerParser, UsedParser,
|
||||||
use crate::attributes::doc::*;
|
};
|
||||||
use crate::attributes::dummy::*;
|
use crate::attributes::confusables::ConfusablesParser;
|
||||||
use crate::attributes::inline::*;
|
use crate::attributes::crate_level::{
|
||||||
use crate::attributes::instruction_set::*;
|
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
|
||||||
use crate::attributes::link_attrs::*;
|
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
|
||||||
use crate::attributes::lint_helpers::*;
|
WindowsSubsystemParser,
|
||||||
use crate::attributes::loop_match::*;
|
};
|
||||||
use crate::attributes::macro_attrs::*;
|
use crate::attributes::debugger::DebuggerViualizerParser;
|
||||||
use crate::attributes::must_not_suspend::*;
|
use crate::attributes::deprecation::DeprecationParser;
|
||||||
use crate::attributes::must_use::*;
|
use crate::attributes::do_not_recommend::DoNotRecommendParser;
|
||||||
use crate::attributes::no_implicit_prelude::*;
|
use crate::attributes::doc::DocParser;
|
||||||
use crate::attributes::no_link::*;
|
use crate::attributes::dummy::DummyParser;
|
||||||
use crate::attributes::non_exhaustive::*;
|
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,
|
||||||
|
};
|
||||||
|
use crate::attributes::lint_helpers::{
|
||||||
|
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
|
||||||
|
RustcShouldNotBeCalledOnConstItems,
|
||||||
|
};
|
||||||
|
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
|
||||||
|
use crate::attributes::macro_attrs::{
|
||||||
|
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;
|
||||||
|
use crate::attributes::non_exhaustive::NonExhaustiveParser;
|
||||||
use crate::attributes::path::PathParser as PathAttributeParser;
|
use crate::attributes::path::PathParser as PathAttributeParser;
|
||||||
use crate::attributes::pin_v2::*;
|
use crate::attributes::pin_v2::PinV2Parser;
|
||||||
use crate::attributes::proc_macro_attrs::*;
|
use crate::attributes::proc_macro_attrs::{
|
||||||
use crate::attributes::prototype::*;
|
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
|
||||||
use crate::attributes::repr::*;
|
};
|
||||||
use crate::attributes::rustc_allocator::*;
|
use crate::attributes::prototype::CustomMirParser;
|
||||||
use crate::attributes::rustc_dump::*;
|
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||||
use crate::attributes::rustc_internal::*;
|
use crate::attributes::rustc_dump::{
|
||||||
use crate::attributes::semantics::*;
|
RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs,
|
||||||
use crate::attributes::stability::*;
|
RustcDumpVtable,
|
||||||
use crate::attributes::test_attrs::*;
|
};
|
||||||
use crate::attributes::traits::*;
|
use crate::attributes::rustc_internal::{
|
||||||
use crate::attributes::transparency::*;
|
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
|
||||||
|
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
|
||||||
|
RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser,
|
||||||
|
RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser,
|
||||||
|
RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser,
|
||||||
|
RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, 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::traits::{
|
||||||
|
AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
|
||||||
|
DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
|
||||||
|
PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
|
||||||
|
UnsafeSpecializationMarkerParser,
|
||||||
|
};
|
||||||
|
use crate::attributes::transparency::TransparencyParser;
|
||||||
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
|
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
|
||||||
use crate::parser::{ArgParser, RefPathParser};
|
use crate::parser::{ArgParser, RefPathParser};
|
||||||
use crate::session_diagnostics::{
|
use crate::session_diagnostics::{
|
||||||
|
|
@ -62,19 +98,19 @@ use crate::target_checking::AllowedTargets;
|
||||||
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
||||||
|
|
||||||
pub(super) struct GroupTypeInner<S: Stage> {
|
pub(super) struct GroupTypeInner<S: Stage> {
|
||||||
pub(super) accepters: BTreeMap<&'static [Symbol], GroupTypeInnerAccept<S>>,
|
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
|
||||||
|
pub(super) finalizers: Vec<FinalizeFn<S>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
||||||
pub(super) template: AttributeTemplate,
|
pub(super) template: AttributeTemplate,
|
||||||
pub(super) accept_fn: AcceptFn<S>,
|
pub(super) accept_fn: AcceptFn<S>,
|
||||||
pub(super) allowed_targets: AllowedTargets,
|
pub(super) allowed_targets: AllowedTargets,
|
||||||
pub(super) finalizer: FinalizeFn<S>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type AcceptFn<S> =
|
type AcceptFn<S> =
|
||||||
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
|
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
|
||||||
pub(crate) type FinalizeFn<S> =
|
type FinalizeFn<S> =
|
||||||
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
||||||
|
|
||||||
macro_rules! attribute_parsers {
|
macro_rules! attribute_parsers {
|
||||||
|
|
@ -102,7 +138,8 @@ macro_rules! attribute_parsers {
|
||||||
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||||
) => {
|
) => {
|
||||||
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
|
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
|
||||||
let mut accepters = BTreeMap::<_, GroupTypeInnerAccept<$stage>>::new();
|
let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||||
|
let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
|
||||||
$(
|
$(
|
||||||
{
|
{
|
||||||
thread_local! {
|
thread_local! {
|
||||||
|
|
@ -110,9 +147,7 @@ macro_rules! attribute_parsers {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||||
match accepters.entry(*path) {
|
accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||||
Entry::Vacant(e) => {
|
|
||||||
e.insert(GroupTypeInnerAccept {
|
|
||||||
template: *template,
|
template: *template,
|
||||||
accept_fn: Box::new(|cx, args| {
|
accept_fn: Box::new(|cx, args| {
|
||||||
STATE_OBJECT.with_borrow_mut(|s| {
|
STATE_OBJECT.with_borrow_mut(|s| {
|
||||||
|
|
@ -120,19 +155,17 @@ macro_rules! attribute_parsers {
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
||||||
finalizer: Box::new(|cx| {
|
|
||||||
let state = STATE_OBJECT.take();
|
|
||||||
state.finalize(cx)
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"),
|
|
||||||
}
|
finalizes.push(Box::new(|cx| {
|
||||||
}
|
let state = STATE_OBJECT.take();
|
||||||
|
state.finalize(cx)
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
GroupTypeInner { accepters }
|
GroupTypeInner { accepters:accepts, finalizers:finalizes }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +180,6 @@ attribute_parsers!(
|
||||||
DocParser,
|
DocParser,
|
||||||
MacroUseParser,
|
MacroUseParser,
|
||||||
NakedParser,
|
NakedParser,
|
||||||
RustcCguTestAttributeParser,
|
|
||||||
StabilityParser,
|
StabilityParser,
|
||||||
UsedParser,
|
UsedParser,
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
@ -155,15 +187,10 @@ attribute_parsers!(
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
Combine<AllowConstFnUnstableParser>,
|
Combine<AllowConstFnUnstableParser>,
|
||||||
Combine<AllowInternalUnstableParser>,
|
Combine<AllowInternalUnstableParser>,
|
||||||
Combine<CrateTypeParser>,
|
|
||||||
Combine<DebuggerViualizerParser>,
|
Combine<DebuggerViualizerParser>,
|
||||||
Combine<ForceTargetFeatureParser>,
|
Combine<ForceTargetFeatureParser>,
|
||||||
Combine<LinkParser>,
|
Combine<LinkParser>,
|
||||||
Combine<ReprParser>,
|
Combine<ReprParser>,
|
||||||
Combine<RustcCleanParser>,
|
|
||||||
Combine<RustcLayoutParser>,
|
|
||||||
Combine<RustcMirParser>,
|
|
||||||
Combine<RustcThenThisWouldNeedParser>,
|
|
||||||
Combine<TargetFeatureParser>,
|
Combine<TargetFeatureParser>,
|
||||||
Combine<UnstableFeatureBoundParser>,
|
Combine<UnstableFeatureBoundParser>,
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
@ -181,7 +208,6 @@ attribute_parsers!(
|
||||||
Single<IgnoreParser>,
|
Single<IgnoreParser>,
|
||||||
Single<InlineParser>,
|
Single<InlineParser>,
|
||||||
Single<InstructionSetParser>,
|
Single<InstructionSetParser>,
|
||||||
Single<LangParser>,
|
|
||||||
Single<LinkNameParser>,
|
Single<LinkNameParser>,
|
||||||
Single<LinkOrdinalParser>,
|
Single<LinkOrdinalParser>,
|
||||||
Single<LinkSectionParser>,
|
Single<LinkSectionParser>,
|
||||||
|
|
@ -193,35 +219,23 @@ attribute_parsers!(
|
||||||
Single<ObjcClassParser>,
|
Single<ObjcClassParser>,
|
||||||
Single<ObjcSelectorParser>,
|
Single<ObjcSelectorParser>,
|
||||||
Single<OptimizeParser>,
|
Single<OptimizeParser>,
|
||||||
Single<PatchableFunctionEntryParser>,
|
|
||||||
Single<PathAttributeParser>,
|
Single<PathAttributeParser>,
|
||||||
Single<PatternComplexityLimitParser>,
|
Single<PatternComplexityLimitParser>,
|
||||||
Single<ProcMacroDeriveParser>,
|
Single<ProcMacroDeriveParser>,
|
||||||
Single<RecursionLimitParser>,
|
Single<RecursionLimitParser>,
|
||||||
Single<ReexportTestHarnessMainParser>,
|
|
||||||
Single<RustcAbiParser>,
|
|
||||||
Single<RustcAllocatorZeroedVariantParser>,
|
|
||||||
Single<RustcBuiltinMacroParser>,
|
Single<RustcBuiltinMacroParser>,
|
||||||
Single<RustcDefPath>,
|
|
||||||
Single<RustcDeprecatedSafe2024Parser>,
|
|
||||||
Single<RustcDiagnosticItemParser>,
|
|
||||||
Single<RustcForceInlineParser>,
|
Single<RustcForceInlineParser>,
|
||||||
Single<RustcIfThisChangedParser>,
|
|
||||||
Single<RustcLayoutScalarValidRangeEndParser>,
|
Single<RustcLayoutScalarValidRangeEndParser>,
|
||||||
Single<RustcLayoutScalarValidRangeStartParser>,
|
Single<RustcLayoutScalarValidRangeStartParser>,
|
||||||
Single<RustcLegacyConstGenericsParser>,
|
Single<RustcLegacyConstGenericsParser>,
|
||||||
Single<RustcLintOptDenyFieldAccessParser>,
|
Single<RustcLintOptDenyFieldAccessParser>,
|
||||||
Single<RustcMustImplementOneOfParser>,
|
Single<RustcMustImplementOneOfParser>,
|
||||||
Single<RustcNeverTypeOptionsParser>,
|
Single<RustcObjectLifetimeDefaultParser>,
|
||||||
Single<RustcReservationImplParser>,
|
|
||||||
Single<RustcScalableVectorParser>,
|
Single<RustcScalableVectorParser>,
|
||||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||||
Single<RustcSymbolName>,
|
|
||||||
Single<RustcTestMarkerParser>,
|
|
||||||
Single<SanitizeParser>,
|
Single<SanitizeParser>,
|
||||||
Single<ShouldPanicParser>,
|
Single<ShouldPanicParser>,
|
||||||
Single<SkipDuringMethodDispatchParser>,
|
Single<SkipDuringMethodDispatchParser>,
|
||||||
Single<TestRunnerParser>,
|
|
||||||
Single<TransparencyParser>,
|
Single<TransparencyParser>,
|
||||||
Single<TypeLengthLimitParser>,
|
Single<TypeLengthLimitParser>,
|
||||||
Single<WindowsSubsystemParser>,
|
Single<WindowsSubsystemParser>,
|
||||||
|
|
@ -231,13 +245,11 @@ attribute_parsers!(
|
||||||
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
||||||
Single<WithoutArgs<CoinductiveParser>>,
|
Single<WithoutArgs<CoinductiveParser>>,
|
||||||
Single<WithoutArgs<ColdParser>>,
|
Single<WithoutArgs<ColdParser>>,
|
||||||
Single<WithoutArgs<CompilerBuiltinsParser>>,
|
|
||||||
Single<WithoutArgs<ConstContinueParser>>,
|
Single<WithoutArgs<ConstContinueParser>>,
|
||||||
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
||||||
Single<WithoutArgs<CoroutineParser>>,
|
Single<WithoutArgs<CoroutineParser>>,
|
||||||
Single<WithoutArgs<DefaultLibAllocatorParser>>,
|
|
||||||
Single<WithoutArgs<DenyExplicitImplParser>>,
|
Single<WithoutArgs<DenyExplicitImplParser>>,
|
||||||
Single<WithoutArgs<DynIncompatibleTraitParser>>,
|
Single<WithoutArgs<DoNotImplementViaObjectParser>>,
|
||||||
Single<WithoutArgs<EiiForeignItemParser>>,
|
Single<WithoutArgs<EiiForeignItemParser>>,
|
||||||
Single<WithoutArgs<ExportStableParser>>,
|
Single<WithoutArgs<ExportStableParser>>,
|
||||||
Single<WithoutArgs<FfiConstParser>>,
|
Single<WithoutArgs<FfiConstParser>>,
|
||||||
|
|
@ -247,75 +259,40 @@ attribute_parsers!(
|
||||||
Single<WithoutArgs<MacroEscapeParser>>,
|
Single<WithoutArgs<MacroEscapeParser>>,
|
||||||
Single<WithoutArgs<MarkerParser>>,
|
Single<WithoutArgs<MarkerParser>>,
|
||||||
Single<WithoutArgs<MayDangleParser>>,
|
Single<WithoutArgs<MayDangleParser>>,
|
||||||
Single<WithoutArgs<NeedsAllocatorParser>>,
|
|
||||||
Single<WithoutArgs<NeedsPanicRuntimeParser>>,
|
|
||||||
Single<WithoutArgs<NoBuiltinsParser>>,
|
|
||||||
Single<WithoutArgs<NoCoreParser>>,
|
Single<WithoutArgs<NoCoreParser>>,
|
||||||
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
||||||
Single<WithoutArgs<NoLinkParser>>,
|
Single<WithoutArgs<NoLinkParser>>,
|
||||||
Single<WithoutArgs<NoMainParser>>,
|
|
||||||
Single<WithoutArgs<NoMangleParser>>,
|
Single<WithoutArgs<NoMangleParser>>,
|
||||||
Single<WithoutArgs<NoStdParser>>,
|
Single<WithoutArgs<NoStdParser>>,
|
||||||
Single<WithoutArgs<NonExhaustiveParser>>,
|
Single<WithoutArgs<NonExhaustiveParser>>,
|
||||||
Single<WithoutArgs<PanicHandlerParser>>,
|
|
||||||
Single<WithoutArgs<PanicRuntimeParser>>,
|
|
||||||
Single<WithoutArgs<ParenSugarParser>>,
|
Single<WithoutArgs<ParenSugarParser>>,
|
||||||
Single<WithoutArgs<PassByValueParser>>,
|
Single<WithoutArgs<PassByValueParser>>,
|
||||||
Single<WithoutArgs<PinV2Parser>>,
|
Single<WithoutArgs<PinV2Parser>>,
|
||||||
Single<WithoutArgs<PointeeParser>>,
|
Single<WithoutArgs<PointeeParser>>,
|
||||||
Single<WithoutArgs<PreludeImportParser>>,
|
|
||||||
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
||||||
Single<WithoutArgs<ProcMacroParser>>,
|
Single<WithoutArgs<ProcMacroParser>>,
|
||||||
Single<WithoutArgs<ProfilerRuntimeParser>>,
|
|
||||||
Single<WithoutArgs<PubTransparentParser>>,
|
Single<WithoutArgs<PubTransparentParser>>,
|
||||||
Single<WithoutArgs<RustcAllocatorParser>>,
|
|
||||||
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
|
|
||||||
Single<WithoutArgs<RustcCaptureAnalysisParser>>,
|
|
||||||
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
||||||
Single<WithoutArgs<RustcConversionSuggestionParser>>,
|
Single<WithoutArgs<RustcDumpDefParents>>,
|
||||||
Single<WithoutArgs<RustcDeallocatorParser>>,
|
Single<WithoutArgs<RustcDumpItemBounds>>,
|
||||||
Single<WithoutArgs<RustcDelayedBugFromInsideQueryParser>>,
|
Single<WithoutArgs<RustcDumpPredicates>>,
|
||||||
Single<WithoutArgs<RustcDoNotConstCheckParser>>,
|
Single<WithoutArgs<RustcDumpUserArgs>>,
|
||||||
Single<WithoutArgs<RustcDumpDefParentsParser>>,
|
Single<WithoutArgs<RustcDumpVtable>>,
|
||||||
Single<WithoutArgs<RustcDumpItemBoundsParser>>,
|
|
||||||
Single<WithoutArgs<RustcDumpPredicatesParser>>,
|
|
||||||
Single<WithoutArgs<RustcDumpUserArgsParser>>,
|
|
||||||
Single<WithoutArgs<RustcDumpVtableParser>>,
|
|
||||||
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
|
|
||||||
Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
|
|
||||||
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
||||||
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
|
Single<WithoutArgs<RustcLintDiagnosticsParser>>,
|
||||||
Single<WithoutArgs<RustcInsignificantDtorParser>>,
|
|
||||||
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
|
|
||||||
Single<WithoutArgs<RustcIntrinsicParser>>,
|
|
||||||
Single<WithoutArgs<RustcLintOptTyParser>>,
|
Single<WithoutArgs<RustcLintOptTyParser>>,
|
||||||
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
|
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
|
||||||
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
|
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
|
||||||
Single<WithoutArgs<RustcMainParser>>,
|
Single<WithoutArgs<RustcMainParser>>,
|
||||||
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
||||||
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
||||||
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
|
|
||||||
Single<WithoutArgs<RustcNoMirInlineParser>>,
|
|
||||||
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
|
|
||||||
Single<WithoutArgs<RustcNonnullOptimizationGuaranteedParser>>,
|
|
||||||
Single<WithoutArgs<RustcNounwindParser>>,
|
|
||||||
Single<WithoutArgs<RustcObjectLifetimeDefaultParser>>,
|
|
||||||
Single<WithoutArgs<RustcOffloadKernelParser>>,
|
|
||||||
Single<WithoutArgs<RustcOutlivesParser>>,
|
|
||||||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||||
Single<WithoutArgs<RustcPreserveUbChecksParser>>,
|
|
||||||
Single<WithoutArgs<RustcProcMacroDeclsParser>>,
|
|
||||||
Single<WithoutArgs<RustcReallocatorParser>>,
|
|
||||||
Single<WithoutArgs<RustcRegionsParser>>,
|
|
||||||
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
||||||
Single<WithoutArgs<RustcStrictCoherenceParser>>,
|
|
||||||
Single<WithoutArgs<RustcTrivialFieldReadsParser>>,
|
|
||||||
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
|
|
||||||
Single<WithoutArgs<RustcVarianceParser>>,
|
|
||||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||||
Single<WithoutArgs<StdInternalSymbolParser>>,
|
Single<WithoutArgs<StdInternalSymbolParser>>,
|
||||||
Single<WithoutArgs<ThreadLocalParser>>,
|
Single<WithoutArgs<ThreadLocalParser>>,
|
||||||
Single<WithoutArgs<TrackCallerParser>>,
|
Single<WithoutArgs<TrackCallerParser>>,
|
||||||
|
Single<WithoutArgs<TypeConstParser>>,
|
||||||
Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
|
Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
];
|
];
|
||||||
|
|
@ -381,7 +358,7 @@ impl Stage for Late {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_emit(&self) -> ShouldEmit {
|
fn should_emit(&self) -> ShouldEmit {
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }
|
ShouldEmit::ErrorsAndLints
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,7 +415,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
||||||
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
|
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
|
||||||
if !matches!(
|
if !matches!(
|
||||||
self.stage.should_emit(),
|
self.stage.should_emit(),
|
||||||
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -510,27 +487,10 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error that a filename string literal was expected.
|
|
||||||
pub(crate) fn expected_filename_literal(&self, span: Span) {
|
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedFilenameLiteral);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
|
pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
|
||||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral)
|
self.emit_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 {
|
pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
|
||||||
let span = match args {
|
let span = match args {
|
||||||
ArgParser::NoArgs => span,
|
ArgParser::NoArgs => span,
|
||||||
|
|
@ -770,18 +730,9 @@ pub enum ShouldEmit {
|
||||||
EarlyFatal { also_emit_lints: bool },
|
EarlyFatal { also_emit_lints: bool },
|
||||||
/// The operation will emit errors and lints.
|
/// The operation will emit errors and lints.
|
||||||
/// This is usually what you need.
|
/// This is usually what you need.
|
||||||
ErrorsAndLints {
|
ErrorsAndLints,
|
||||||
/// Whether [`ArgParser`] will attempt to recover from errors.
|
/// The operation will emit *not* errors and lints.
|
||||||
///
|
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
|
||||||
/// Whether it is allowed to recover from bad input (like an invalid literal). Setting
|
|
||||||
/// this to `Forbidden` will instead return early, and not raise errors except at the top
|
|
||||||
/// level (in [`ArgParser::from_attr_args`]).
|
|
||||||
recovery: Recovery,
|
|
||||||
},
|
|
||||||
/// The operation will *not* emit errors and lints.
|
|
||||||
///
|
|
||||||
/// The parser can still call `delay_bug`, so you *must* ensure that this operation will also be
|
|
||||||
/// called with `ShouldEmit::ErrorsAndLints`.
|
|
||||||
Nothing,
|
Nothing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -790,7 +741,7 @@ impl ShouldEmit {
|
||||||
match self {
|
match self {
|
||||||
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
|
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
|
||||||
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
|
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
|
||||||
ShouldEmit::ErrorsAndLints { .. } => diag.emit(),
|
ShouldEmit::ErrorsAndLints => diag.emit(),
|
||||||
ShouldEmit::Nothing => diag.delay_as_bug(),
|
ShouldEmit::Nothing => diag.delay_as_bug(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use rustc_session::Session;
|
||||||
use rustc_session::lint::{BuiltinLintDiag, LintId};
|
use rustc_session::lint::{BuiltinLintDiag, LintId};
|
||||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||||
|
|
||||||
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
|
use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
|
||||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
||||||
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
||||||
use crate::session_diagnostics::ParsedDescription;
|
use crate::session_diagnostics::ParsedDescription;
|
||||||
|
|
@ -270,8 +270,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
|
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
|
||||||
let mut early_parsed_state = EarlyParsedState::default();
|
let mut early_parsed_state = EarlyParsedState::default();
|
||||||
|
|
||||||
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
|
|
||||||
|
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||||
if let Some(expected) = self.parse_only {
|
if let Some(expected) = self.parse_only {
|
||||||
|
|
@ -327,7 +325,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
let parts =
|
let parts =
|
||||||
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||||
|
|
||||||
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
|
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||||
let Some(args) = ArgParser::from_attr_args(
|
let Some(args) = ArgParser::from_attr_args(
|
||||||
args,
|
args,
|
||||||
&parts,
|
&parts,
|
||||||
|
|
@ -368,6 +366,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for accept in accepts {
|
||||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||||
shared: SharedContext {
|
shared: SharedContext {
|
||||||
cx: self,
|
cx: self,
|
||||||
|
|
@ -384,11 +383,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
};
|
};
|
||||||
|
|
||||||
(accept.accept_fn)(&mut cx, &args);
|
(accept.accept_fn)(&mut cx, &args);
|
||||||
finalizers.push(&accept.finalizer);
|
|
||||||
|
|
||||||
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
||||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If we're here, we must be compiling a tool attribute... Or someone
|
// If we're here, we must be compiling a tool attribute... Or someone
|
||||||
// forgot to parse their fancy new attribute. Let's warn them in any case.
|
// forgot to parse their fancy new attribute. Let's warn them in any case.
|
||||||
|
|
@ -419,7 +417,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
|
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
|
||||||
for f in &finalizers {
|
for f in &S::parsers().finalizers {
|
||||||
if let Some(attr) = f(&mut FinalizeContext {
|
if let Some(attr) = f(&mut FinalizeContext {
|
||||||
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
|
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
|
||||||
all_attrs: &attr_paths,
|
all_attrs: &attr_paths,
|
||||||
|
|
|
||||||
|
|
@ -113,3 +113,5 @@ pub use attributes::util::{is_builtin_attr, parse_version};
|
||||||
pub use context::{Early, Late, OmitDoc, ShouldEmit};
|
pub use context::{Early, Late, OmitDoc, ShouldEmit};
|
||||||
pub use interface::AttributeParser;
|
pub use interface::AttributeParser;
|
||||||
pub use session_diagnostics::ParsedDescription;
|
pub use session_diagnostics::ParsedDescription;
|
||||||
|
|
||||||
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ use rustc_ast_pretty::pprust;
|
||||||
use rustc_errors::{Diag, PResult};
|
use rustc_errors::{Diag, PResult};
|
||||||
use rustc_hir::{self as hir, AttrPath};
|
use rustc_hir::{self as hir, AttrPath};
|
||||||
use rustc_parse::exp;
|
use rustc_parse::exp;
|
||||||
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr};
|
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
|
||||||
use rustc_session::errors::create_lit_error;
|
use rustc_session::errors::{create_lit_error, report_lit_error};
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_span::{Ident, Span, Symbol, sym};
|
use rustc_span::{Ident, Span, Symbol, sym};
|
||||||
use thin_vec::ThinVec;
|
use thin_vec::ThinVec;
|
||||||
|
|
@ -113,30 +113,17 @@ impl ArgParser {
|
||||||
Some(match value {
|
Some(match value {
|
||||||
AttrArgs::Empty => Self::NoArgs,
|
AttrArgs::Empty => Self::NoArgs,
|
||||||
AttrArgs::Delimited(args) => {
|
AttrArgs::Delimited(args) => {
|
||||||
// Diagnostic attributes can't error if they encounter non meta item syntax.
|
// The arguments of rustc_dummy and diagnostic::do_not_recommend are not validated
|
||||||
// However, the current syntax for diagnostic attributes is meta item syntax.
|
// if the arguments are delimited.
|
||||||
// Therefore we can substitute with a dummy value on invalid syntax.
|
// See https://doc.rust-lang.org/reference/attributes/diagnostics.html#r-attributes.diagnostic.namespace.unknown-invalid-syntax
|
||||||
if matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
|
if parts == &[sym::rustc_dummy]
|
||||||
match MetaItemListParser::new(
|
|| parts == &[sym::diagnostic, sym::do_not_recommend]
|
||||||
&args.tokens,
|
{
|
||||||
args.dspan.entire(),
|
|
||||||
psess,
|
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
|
|
||||||
) {
|
|
||||||
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 {
|
return Some(ArgParser::List(MetaItemListParser {
|
||||||
sub_parsers: ThinVec::new(),
|
sub_parsers: ThinVec::new(),
|
||||||
span: args.dspan.entire(),
|
span: args.dspan.entire(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.delim != Delimiter::Parenthesis {
|
if args.delim != Delimiter::Parenthesis {
|
||||||
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
|
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
|
||||||
|
|
@ -154,9 +141,7 @@ impl ArgParser {
|
||||||
}
|
}
|
||||||
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
||||||
eq_span: *eq_span,
|
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,
|
value_span: expr.span,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
@ -351,56 +336,58 @@ impl NameValueParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_to_lit<'sess>(
|
fn expr_to_lit(
|
||||||
psess: &'sess ParseSess,
|
psess: &ParseSess,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
span: Span,
|
span: Span,
|
||||||
should_emit: ShouldEmit,
|
should_emit: ShouldEmit,
|
||||||
) -> PResult<'sess, Option<MetaItemLit>> {
|
) -> Option<MetaItemLit> {
|
||||||
if let ExprKind::Lit(token_lit) = expr.kind {
|
if let ExprKind::Lit(token_lit) = expr.kind {
|
||||||
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
|
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
|
||||||
match res {
|
match res {
|
||||||
Ok(lit) => {
|
Ok(lit) => {
|
||||||
if token_lit.suffix.is_some() {
|
if token_lit.suffix.is_some() {
|
||||||
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
|
should_emit.emit_err(
|
||||||
|
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||||
|
);
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
if lit.kind.is_unsuffixed() {
|
if !lit.kind.is_unsuffixed() {
|
||||||
Ok(Some(lit))
|
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||||
} else {
|
should_emit.emit_err(
|
||||||
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
|
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(lit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let err = create_lit_error(psess, err, token_lit, expr.span);
|
let guar = report_lit_error(psess, err, token_lit, expr.span);
|
||||||
if matches!(
|
|
||||||
should_emit,
|
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
|
|
||||||
) {
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
let lit = MetaItemLit {
|
let lit = MetaItemLit {
|
||||||
symbol: token_lit.symbol,
|
symbol: token_lit.symbol,
|
||||||
suffix: token_lit.suffix,
|
suffix: token_lit.suffix,
|
||||||
kind: LitKind::Err(err.emit()),
|
kind: LitKind::Err(guar),
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
};
|
};
|
||||||
Ok(Some(lit))
|
Some(lit)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if matches!(should_emit, ShouldEmit::Nothing) {
|
if matches!(should_emit, ShouldEmit::Nothing) {
|
||||||
return Ok(None);
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example cases:
|
// Example cases:
|
||||||
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
|
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
|
||||||
// - `#[foo = include_str!("nonexistent-file.rs")]`:
|
// - `#[foo = include_str!("nonexistent-file.rs")]`:
|
||||||
// results in `ast::ExprKind::Err`.
|
// results in `ast::ExprKind::Err`. In that case we delay
|
||||||
|
// the error because an earlier error will have already
|
||||||
|
// been reported.
|
||||||
let msg = "attribute value must be a literal";
|
let msg = "attribute value must be a literal";
|
||||||
let err = psess.dcx().struct_span_err(span, msg);
|
let err = psess.dcx().struct_span_err(span, msg);
|
||||||
Err(err)
|
should_emit.emit_err(err);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,15 +420,9 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||||
|
|
||||||
if !lit.kind.is_unsuffixed() {
|
if !lit.kind.is_unsuffixed() {
|
||||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||||
let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
|
self.should_emit.emit_err(
|
||||||
if matches!(
|
self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||||
self.should_emit,
|
);
|
||||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
|
|
||||||
) {
|
|
||||||
return Err(err);
|
|
||||||
} else {
|
|
||||||
self.should_emit.emit_err(err)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(lit)
|
Ok(lit)
|
||||||
|
|
@ -575,10 +556,6 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||||
should_emit: ShouldEmit,
|
should_emit: ShouldEmit,
|
||||||
) -> PResult<'sess, MetaItemListParser> {
|
) -> PResult<'sess, MetaItemListParser> {
|
||||||
let mut parser = Parser::new(psess, tokens, None);
|
let mut parser = Parser::new(psess, tokens, None);
|
||||||
if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
|
|
||||||
parser = parser.recovery(recovery);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
|
let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
|
||||||
|
|
||||||
// Presumably, the majority of the time there will only be one attr.
|
// Presumably, the majority of the time there will only be one attr.
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::spec::TargetTuple;
|
use rustc_target::spec::TargetTuple;
|
||||||
|
|
||||||
|
use crate::fluent_generated as fluent;
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid predicate `{$predicate}`", code = E0537)]
|
#[diag(attr_parsing_invalid_predicate, code = E0537)]
|
||||||
pub(crate) struct InvalidPredicate {
|
pub(crate) struct InvalidPredicate {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -21,7 +23,7 @@ pub(crate) struct InvalidPredicate {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("{$attr_str} attribute cannot have empty value")]
|
#[diag(attr_parsing_doc_alias_empty)]
|
||||||
pub(crate) struct DocAliasEmpty<'a> {
|
pub(crate) struct DocAliasEmpty<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -29,7 +31,7 @@ pub(crate) struct DocAliasEmpty<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("{$char_} character isn't allowed in {$attr_str}")]
|
#[diag(attr_parsing_doc_alias_bad_char)]
|
||||||
pub(crate) struct DocAliasBadChar<'a> {
|
pub(crate) struct DocAliasBadChar<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -38,7 +40,7 @@ pub(crate) struct DocAliasBadChar<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("{$attr_str} cannot start or end with ' '")]
|
#[diag(attr_parsing_doc_alias_start_end)]
|
||||||
pub(crate) struct DocAliasStartEnd<'a> {
|
pub(crate) struct DocAliasStartEnd<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -46,16 +48,7 @@ pub(crate) struct DocAliasStartEnd<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`#[{$name})]` is missing a `{$field}` argument")]
|
#[diag(attr_parsing_doc_attr_not_crate_level)]
|
||||||
pub(crate) struct CguFieldsMissing<'a> {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
pub name: &'a AttrPath,
|
|
||||||
pub field: Symbol,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("`#![doc({$attr_name} = \"...\")]` isn't allowed as a crate-level attribute")]
|
|
||||||
pub(crate) struct DocAttrNotCrateLevel {
|
pub(crate) struct DocAttrNotCrateLevel {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -63,8 +56,8 @@ pub(crate) struct DocAttrNotCrateLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("nonexistent keyword `{$keyword}` used in `#[doc(keyword = \"...\")]`")]
|
#[diag(attr_parsing_doc_keyword_not_keyword)]
|
||||||
#[help("only existing keywords are allowed in core/std")]
|
#[help]
|
||||||
pub(crate) struct DocKeywordNotKeyword {
|
pub(crate) struct DocKeywordNotKeyword {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -72,8 +65,8 @@ pub(crate) struct DocKeywordNotKeyword {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = \"...\")]`")]
|
#[diag(attr_parsing_doc_attribute_not_attribute)]
|
||||||
#[help("only existing builtin attributes are allowed in core/std")]
|
#[help]
|
||||||
pub(crate) struct DocAttributeNotAttribute {
|
pub(crate) struct DocAttributeNotAttribute {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -81,28 +74,28 @@ pub(crate) struct DocAttributeNotAttribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("missing 'since'", code = E0542)]
|
#[diag(attr_parsing_missing_since, code = E0542)]
|
||||||
pub(crate) struct MissingSince {
|
pub(crate) struct MissingSince {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("missing 'note'", code = E0543)]
|
#[diag(attr_parsing_missing_note, code = E0543)]
|
||||||
pub(crate) struct MissingNote {
|
pub(crate) struct MissingNote {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("multiple stability levels", code = E0544)]
|
#[diag(attr_parsing_multiple_stability_levels, code = E0544)]
|
||||||
pub(crate) struct MultipleStabilityLevels {
|
pub(crate) struct MultipleStabilityLevels {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`issue` must be a non-zero numeric string or \"none\"", code = E0545)]
|
#[diag(attr_parsing_invalid_issue_string, code = E0545)]
|
||||||
pub(crate) struct InvalidIssueString {
|
pub(crate) struct InvalidIssueString {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -115,31 +108,31 @@ pub(crate) struct InvalidIssueString {
|
||||||
// translatable.
|
// translatable.
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum InvalidIssueStringCause {
|
pub(crate) enum InvalidIssueStringCause {
|
||||||
#[label("`issue` must not be \"0\", use \"none\" instead")]
|
#[label(attr_parsing_must_not_be_zero)]
|
||||||
MustNotBeZero {
|
MustNotBeZero {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[label("cannot parse integer from empty string")]
|
#[label(attr_parsing_empty)]
|
||||||
Empty {
|
Empty {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[label("invalid digit found in string")]
|
#[label(attr_parsing_invalid_digit)]
|
||||||
InvalidDigit {
|
InvalidDigit {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[label("number too large to fit in target type")]
|
#[label(attr_parsing_pos_overflow)]
|
||||||
PosOverflow {
|
PosOverflow {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[label("number too small to fit in target type")]
|
#[label(attr_parsing_neg_overflow)]
|
||||||
NegOverflow {
|
NegOverflow {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -160,21 +153,21 @@ impl InvalidIssueStringCause {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("missing 'feature'", code = E0546)]
|
#[diag(attr_parsing_missing_feature, code = E0546)]
|
||||||
pub(crate) struct MissingFeature {
|
pub(crate) struct MissingFeature {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("'feature' is not an identifier", code = E0546)]
|
#[diag(attr_parsing_non_ident_feature, code = E0546)]
|
||||||
pub(crate) struct NonIdentFeature {
|
pub(crate) struct NonIdentFeature {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("missing 'issue'", code = E0547)]
|
#[diag(attr_parsing_missing_issue, code = E0547)]
|
||||||
pub(crate) struct MissingIssue {
|
pub(crate) struct MissingIssue {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -183,20 +176,20 @@ pub(crate) struct MissingIssue {
|
||||||
// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
|
// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
|
||||||
// It is more similar to `IncorrectReprFormatGeneric`.
|
// It is more similar to `IncorrectReprFormatGeneric`.
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all", code = E0552)]
|
#[diag(attr_parsing_incorrect_repr_format_packed_one_or_zero_arg, code = E0552)]
|
||||||
pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
|
pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument", code = E0552)]
|
#[diag(attr_parsing_incorrect_repr_format_packed_expect_integer, code = E0552)]
|
||||||
pub(crate) struct IncorrectReprFormatPackedExpectInteger {
|
pub(crate) struct IncorrectReprFormatPackedExpectInteger {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid representation hint: `{$name}` does not take a parenthesized argument list", code = E0552)]
|
#[diag(attr_parsing_invalid_repr_hint_no_paren, code = E0552)]
|
||||||
pub(crate) struct InvalidReprHintNoParen {
|
pub(crate) struct InvalidReprHintNoParen {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -205,7 +198,7 @@ pub(crate) struct InvalidReprHintNoParen {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid representation hint: `{$name}` does not take a value", code = E0552)]
|
#[diag(attr_parsing_invalid_repr_hint_no_value, code = E0552)]
|
||||||
pub(crate) struct InvalidReprHintNoValue {
|
pub(crate) struct InvalidReprHintNoValue {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -214,19 +207,15 @@ pub(crate) struct InvalidReprHintNoValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid `repr(align)` attribute: `align` needs an argument", code = E0589)]
|
#[diag(attr_parsing_invalid_repr_align_need_arg, code = E0589)]
|
||||||
pub(crate) struct InvalidReprAlignNeedArg {
|
pub(crate) struct InvalidReprAlignNeedArg {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion(
|
#[suggestion(code = "align(...)", applicability = "has-placeholders")]
|
||||||
"supply an argument here",
|
|
||||||
code = "align(...)",
|
|
||||||
applicability = "has-placeholders"
|
|
||||||
)]
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid `repr({$repr_arg})` attribute: {$error_part}", code = E0589)]
|
#[diag(attr_parsing_invalid_repr_generic, code = E0589)]
|
||||||
pub(crate) struct InvalidReprGeneric<'a> {
|
pub(crate) struct InvalidReprGeneric<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -236,21 +225,21 @@ pub(crate) struct InvalidReprGeneric<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses", code = E0693)]
|
#[diag(attr_parsing_incorrect_repr_format_align_one_arg, code = E0693)]
|
||||||
pub(crate) struct IncorrectReprFormatAlignOneArg {
|
pub(crate) struct IncorrectReprFormatAlignOneArg {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("incorrect `repr(align)` attribute format: `align` expects a literal integer as argument", code = E0693)]
|
#[diag(attr_parsing_incorrect_repr_format_expect_literal_integer, code = E0693)]
|
||||||
pub(crate) struct IncorrectReprFormatExpectInteger {
|
pub(crate) struct IncorrectReprFormatExpectInteger {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("incorrect `repr({$repr_arg})` attribute format", code = E0693)]
|
#[diag(attr_parsing_incorrect_repr_format_generic, code = E0693)]
|
||||||
pub(crate) struct IncorrectReprFormatGeneric {
|
pub(crate) struct IncorrectReprFormatGeneric {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -264,7 +253,7 @@ pub(crate) struct IncorrectReprFormatGeneric {
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum IncorrectReprFormatGenericCause {
|
pub(crate) enum IncorrectReprFormatGenericCause {
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
"use parentheses instead",
|
attr_parsing_suggestion,
|
||||||
code = "{name}({value})",
|
code = "{name}({value})",
|
||||||
applicability = "machine-applicable"
|
applicability = "machine-applicable"
|
||||||
)]
|
)]
|
||||||
|
|
@ -280,7 +269,7 @@ pub(crate) enum IncorrectReprFormatGenericCause {
|
||||||
},
|
},
|
||||||
|
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
"use parentheses instead",
|
attr_parsing_suggestion,
|
||||||
code = "{name}({value})",
|
code = "{name}({value})",
|
||||||
applicability = "machine-applicable"
|
applicability = "machine-applicable"
|
||||||
)]
|
)]
|
||||||
|
|
@ -309,48 +298,48 @@ impl IncorrectReprFormatGenericCause {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute", code = E0717)]
|
#[diag(attr_parsing_rustc_promotable_pairing, code = E0717)]
|
||||||
pub(crate) struct RustcPromotablePairing {
|
pub(crate) struct RustcPromotablePairing {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute", code = E0789)]
|
#[diag(attr_parsing_rustc_allowed_unstable_pairing, code = E0789)]
|
||||||
pub(crate) struct RustcAllowedUnstablePairing {
|
pub(crate) struct RustcAllowedUnstablePairing {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("suggestions on deprecated items are unstable")]
|
#[diag(attr_parsing_deprecated_item_suggestion)]
|
||||||
pub(crate) struct DeprecatedItemSuggestion {
|
pub(crate) struct DeprecatedItemSuggestion {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
||||||
#[help("add `#![feature(deprecated_suggestion)]` to the crate root")]
|
#[help]
|
||||||
pub is_nightly: bool,
|
pub is_nightly: bool,
|
||||||
|
|
||||||
#[note("see #94785 for more details")]
|
#[note]
|
||||||
pub details: (),
|
pub details: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("expected single version literal")]
|
#[diag(attr_parsing_expected_single_version_literal)]
|
||||||
pub(crate) struct ExpectedSingleVersionLiteral {
|
pub(crate) struct ExpectedSingleVersionLiteral {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("expected a version literal")]
|
#[diag(attr_parsing_expected_version_literal)]
|
||||||
pub(crate) struct ExpectedVersionLiteral {
|
pub(crate) struct ExpectedVersionLiteral {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`{$name}` expects a list of feature names")]
|
#[diag(attr_parsing_expects_feature_list)]
|
||||||
pub(crate) struct ExpectsFeatureList {
|
pub(crate) struct ExpectsFeatureList {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -359,7 +348,7 @@ pub(crate) struct ExpectsFeatureList {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`{$name}` expects feature names")]
|
#[diag(attr_parsing_expects_features)]
|
||||||
pub(crate) struct ExpectsFeatures {
|
pub(crate) struct ExpectsFeatures {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -368,21 +357,21 @@ pub(crate) struct ExpectsFeatures {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("'since' must be a Rust version number, such as \"1.31.0\"")]
|
#[diag(attr_parsing_invalid_since)]
|
||||||
pub(crate) struct InvalidSince {
|
pub(crate) struct InvalidSince {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`soft` should not have any arguments")]
|
#[diag(attr_parsing_soft_no_args)]
|
||||||
pub(crate) struct SoftNoArgs {
|
pub(crate) struct SoftNoArgs {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("unknown version literal format, assuming it refers to a future version")]
|
#[diag(attr_parsing_unknown_version_literal)]
|
||||||
pub(crate) struct UnknownVersionLiteral {
|
pub(crate) struct UnknownVersionLiteral {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -390,83 +379,78 @@ pub(crate) struct UnknownVersionLiteral {
|
||||||
|
|
||||||
// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated.
|
// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated.
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("multiple `{$name}` attributes")]
|
#[diag(attr_parsing_unused_multiple)]
|
||||||
pub(crate) struct UnusedMultiple {
|
pub(crate) struct UnusedMultiple {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
|
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||||
pub this: Span,
|
pub this: Span,
|
||||||
#[note("attribute also specified here")]
|
#[note]
|
||||||
pub other: Span,
|
pub other: Span,
|
||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`export_name` may not contain null characters", code = E0648)]
|
#[diag(attr_parsing_null_on_export, code = E0648)]
|
||||||
pub(crate) struct NullOnExport {
|
pub(crate) struct NullOnExport {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`link_section` may not contain null characters", code = E0648)]
|
#[diag(attr_parsing_null_on_link_section, code = E0648)]
|
||||||
pub(crate) struct NullOnLinkSection {
|
pub(crate) struct NullOnLinkSection {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`objc::class!` may not contain null characters")]
|
#[diag(attr_parsing_null_on_objc_class)]
|
||||||
pub(crate) struct NullOnObjcClass {
|
pub(crate) struct NullOnObjcClass {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`objc::selector!` may not contain null characters")]
|
#[diag(attr_parsing_null_on_objc_selector)]
|
||||||
pub(crate) struct NullOnObjcSelector {
|
pub(crate) struct NullOnObjcSelector {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`objc::class!` expected a string literal")]
|
#[diag(attr_parsing_objc_class_expected_string_literal)]
|
||||||
pub(crate) struct ObjcClassExpectedStringLiteral {
|
pub(crate) struct ObjcClassExpectedStringLiteral {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`objc::selector!` expected a string literal")]
|
#[diag(attr_parsing_objc_selector_expected_string_literal)]
|
||||||
pub(crate) struct ObjcSelectorExpectedStringLiteral {
|
pub(crate) struct ObjcSelectorExpectedStringLiteral {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("stability attributes may not be used outside of the standard library", code = E0734)]
|
#[diag(attr_parsing_stability_outside_std, code = E0734)]
|
||||||
pub(crate) struct StabilityOutsideStd {
|
pub(crate) struct StabilityOutsideStd {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("expected at least one confusable name")]
|
#[diag(attr_parsing_empty_confusables)]
|
||||||
pub(crate) struct EmptyConfusables {
|
pub(crate) struct EmptyConfusables {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[help("`#[{$name}]` can {$only}be applied to {$applied}")]
|
#[help]
|
||||||
#[diag("`#[{$name}]` attribute cannot be used on {$target}")]
|
#[diag(attr_parsing_invalid_target)]
|
||||||
pub(crate) struct InvalidTarget {
|
pub(crate) struct InvalidTarget {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[suggestion(
|
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
|
||||||
"remove the attribute",
|
|
||||||
code = "",
|
|
||||||
applicability = "machine-applicable",
|
|
||||||
style = "tool-only"
|
|
||||||
)]
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: AttrPath,
|
pub name: AttrPath,
|
||||||
pub target: &'static str,
|
pub target: &'static str,
|
||||||
|
|
@ -475,7 +459,7 @@ pub(crate) struct InvalidTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("invalid alignment value: {$error_part}", code = E0589)]
|
#[diag(attr_parsing_invalid_alignment_value, code = E0589)]
|
||||||
pub(crate) struct InvalidAlignmentValue {
|
pub(crate) struct InvalidAlignmentValue {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -483,49 +467,43 @@ pub(crate) struct InvalidAlignmentValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("meta item in `repr` must be an identifier", code = E0565)]
|
#[diag(attr_parsing_repr_ident, code = E0565)]
|
||||||
pub(crate) struct ReprIdent {
|
pub(crate) struct ReprIdent {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("unrecognized representation hint", code = E0552)]
|
#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
|
||||||
#[help(
|
#[help]
|
||||||
"valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`"
|
#[note]
|
||||||
)]
|
|
||||||
#[note(
|
|
||||||
"for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>"
|
|
||||||
)]
|
|
||||||
pub(crate) struct UnrecognizedReprHint {
|
pub(crate) struct UnrecognizedReprHint {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("item annotated with `#[unstable_feature_bound]` should not be stable")]
|
#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)]
|
||||||
#[help(
|
#[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]`"
|
|
||||||
)]
|
|
||||||
pub(crate) struct UnstableFeatureBoundIncompatibleStability {
|
pub(crate) struct UnstableFeatureBoundIncompatibleStability {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("attribute incompatible with `#[unsafe(naked)]`", code = E0736)]
|
#[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)]
|
||||||
pub(crate) struct NakedFunctionIncompatibleAttribute {
|
pub(crate) struct NakedFunctionIncompatibleAttribute {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[label("function marked with `#[unsafe(naked)]` here")]
|
#[label(attr_parsing_naked_attribute)]
|
||||||
pub naked_span: Span,
|
pub naked_span: Span,
|
||||||
pub attr: String,
|
pub attr: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("ordinal value in `link_ordinal` is too large: `{$ordinal}`")]
|
#[diag(attr_parsing_link_ordinal_out_of_range)]
|
||||||
#[note("the value may not exceed `u16::MAX`")]
|
#[note]
|
||||||
pub(crate) struct LinkOrdinalOutOfRange {
|
pub(crate) struct LinkOrdinalOutOfRange {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -533,33 +511,20 @@ pub(crate) struct LinkOrdinalOutOfRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("element count in `rustc_scalable_vector` is too large: `{$n}`")]
|
#[diag(attr_parsing_rustc_scalable_vector_count_out_of_range)]
|
||||||
#[note("the value may not exceed `u16::MAX`")]
|
#[note]
|
||||||
pub(crate) struct RustcScalableVectorCountOutOfRange {
|
pub(crate) struct RustcScalableVectorCountOutOfRange {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub n: u128,
|
pub n: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("attribute requires {$opt} to be enabled")]
|
|
||||||
pub(crate) struct AttributeRequiresOpt {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
pub opt: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) enum AttributeParseErrorReason<'a> {
|
pub(crate) enum AttributeParseErrorReason<'a> {
|
||||||
ExpectedNoArgs,
|
ExpectedNoArgs,
|
||||||
ExpectedStringLiteral {
|
ExpectedStringLiteral {
|
||||||
byte_string: Option<Span>,
|
byte_string: Option<Span>,
|
||||||
},
|
},
|
||||||
ExpectedFilenameLiteral,
|
|
||||||
ExpectedIntegerLiteral,
|
ExpectedIntegerLiteral,
|
||||||
ExpectedIntegerLiteralInRange {
|
|
||||||
lower_bound: isize,
|
|
||||||
upper_bound: isize,
|
|
||||||
},
|
|
||||||
ExpectedAtLeastOneArgument,
|
ExpectedAtLeastOneArgument,
|
||||||
ExpectedSingleArgument,
|
ExpectedSingleArgument,
|
||||||
ExpectedList,
|
ExpectedList,
|
||||||
|
|
@ -617,7 +582,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
||||||
if let Some(start_point_span) = byte_string {
|
if let Some(start_point_span) = byte_string {
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
start_point_span,
|
start_point_span,
|
||||||
"consider removing the prefix",
|
fluent::attr_parsing_unsupported_literal_suggestion,
|
||||||
"",
|
"",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
|
@ -628,23 +593,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
||||||
diag.span_label(self.span, "expected a string literal here");
|
diag.span_label(self.span, "expected a string literal here");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AttributeParseErrorReason::ExpectedFilenameLiteral => {
|
|
||||||
diag.span_label(self.span, "expected a filename string literal here");
|
|
||||||
}
|
|
||||||
AttributeParseErrorReason::ExpectedIntegerLiteral => {
|
AttributeParseErrorReason::ExpectedIntegerLiteral => {
|
||||||
diag.span_label(self.span, "expected an integer literal here");
|
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 => {
|
AttributeParseErrorReason::ExpectedSingleArgument => {
|
||||||
diag.span_label(self.span, "expected a single argument here");
|
diag.span_label(self.span, "expected a single argument here");
|
||||||
diag.code(E0805);
|
diag.code(E0805);
|
||||||
|
|
@ -785,27 +736,30 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`{$name}` is not an unsafe attribute")]
|
#[diag(attr_parsing_invalid_attr_unsafe)]
|
||||||
#[note("extraneous unsafe is not allowed in attributes")]
|
#[note]
|
||||||
pub(crate) struct InvalidAttrUnsafe {
|
pub(crate) struct InvalidAttrUnsafe {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("this is not an unsafe attribute")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: AttrPath,
|
pub name: AttrPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("unsafe attribute used without unsafe")]
|
#[diag(attr_parsing_unsafe_attr_outside_unsafe)]
|
||||||
pub(crate) struct UnsafeAttrOutsideUnsafe {
|
pub(crate) struct UnsafeAttrOutsideUnsafe {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("usage of unsafe attribute")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub suggestion: Option<UnsafeAttrOutsideUnsafeSuggestion>,
|
pub suggestion: Option<UnsafeAttrOutsideUnsafeSuggestion>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion("wrap the attribute in `unsafe(...)`", applicability = "machine-applicable")]
|
#[multipart_suggestion(
|
||||||
|
attr_parsing_unsafe_attr_outside_unsafe_suggestion,
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
||||||
#[suggestion_part(code = "unsafe(")]
|
#[suggestion_part(code = "unsafe(")]
|
||||||
pub left: Span,
|
pub left: Span,
|
||||||
|
|
@ -814,7 +768,7 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("wrong meta list delimiters")]
|
#[diag(attr_parsing_meta_bad_delim)]
|
||||||
pub(crate) struct MetaBadDelim {
|
pub(crate) struct MetaBadDelim {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -824,7 +778,7 @@ pub(crate) struct MetaBadDelim {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(
|
||||||
"the delimiters should be `(` and `)`",
|
attr_parsing_meta_bad_delim_suggestion,
|
||||||
applicability = "machine-applicable"
|
applicability = "machine-applicable"
|
||||||
)]
|
)]
|
||||||
pub(crate) struct MetaBadDelimSugg {
|
pub(crate) struct MetaBadDelimSugg {
|
||||||
|
|
@ -835,7 +789,7 @@ pub(crate) struct MetaBadDelimSugg {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("expected a literal (`1u8`, `1.0f32`, `\"string\"`, etc.) here, found {$descr}")]
|
#[diag(attr_parsing_invalid_meta_item)]
|
||||||
pub(crate) struct InvalidMetaItem {
|
pub(crate) struct InvalidMetaItem {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -844,15 +798,12 @@ pub(crate) struct InvalidMetaItem {
|
||||||
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
|
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
|
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
|
||||||
#[label("{$descr}s are not allowed here")]
|
#[label]
|
||||||
pub label: Option<Span>,
|
pub label: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(attr_parsing_quote_ident_sugg, applicability = "machine-applicable")]
|
||||||
"surround the identifier with quotation marks to make it into a string literal",
|
|
||||||
applicability = "machine-applicable"
|
|
||||||
)]
|
|
||||||
pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
||||||
#[suggestion_part(code = "\"")]
|
#[suggestion_part(code = "\"")]
|
||||||
pub before: Span,
|
pub before: Span,
|
||||||
|
|
@ -861,80 +812,73 @@ pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(attr_parsing_remove_neg_sugg, applicability = "machine-applicable")]
|
||||||
"negative numbers are not literals, try removing the `-` sign",
|
|
||||||
applicability = "machine-applicable"
|
|
||||||
)]
|
|
||||||
pub(crate) struct InvalidMetaItemRemoveNegSugg {
|
pub(crate) struct InvalidMetaItemRemoveNegSugg {
|
||||||
#[suggestion_part(code = "")]
|
#[suggestion_part(code = "")]
|
||||||
pub negative_sign: Span,
|
pub negative_sign: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("suffixed literals are not allowed in attributes")]
|
#[diag(attr_parsing_suffixed_literal_in_attribute)]
|
||||||
#[help(
|
#[help]
|
||||||
"instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)"
|
|
||||||
)]
|
|
||||||
pub(crate) struct SuffixedLiteralInAttribute {
|
pub(crate) struct SuffixedLiteralInAttribute {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("link name must not be empty", code = E0454)]
|
#[diag(attr_parsing_empty_link_name, code = E0454)]
|
||||||
pub(crate) struct EmptyLinkName {
|
pub(crate) struct EmptyLinkName {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("empty link name")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("link kind `framework` is only supported on Apple targets", code = E0455)]
|
#[diag(attr_parsing_link_framework_apple, code = E0455)]
|
||||||
pub(crate) struct LinkFrameworkApple {
|
pub(crate) struct LinkFrameworkApple {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`wasm_import_module` is incompatible with other arguments in `#[link]` attributes")]
|
#[diag(attr_parsing_incompatible_wasm_link)]
|
||||||
pub(crate) struct IncompatibleWasmLink {
|
pub(crate) struct IncompatibleWasmLink {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`#[link]` attribute requires a `name = \"string\"` argument", code = E0459)]
|
#[diag(attr_parsing_link_requires_name, code = E0459)]
|
||||||
pub(crate) struct LinkRequiresName {
|
pub(crate) struct LinkRequiresName {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("missing `name` argument")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("link name must not contain NUL characters if link kind is `raw-dylib`")]
|
#[diag(attr_parsing_raw_dylib_no_nul)]
|
||||||
pub(crate) struct RawDylibNoNul {
|
pub(crate) struct RawDylibNoNul {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("link kind `raw-dylib` is only supported on Windows targets", code = E0455)]
|
#[diag(attr_parsing_raw_dylib_only_windows, code = E0455)]
|
||||||
pub(crate) struct RawDylibOnlyWindows {
|
pub(crate) struct RawDylibOnlyWindows {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(
|
#[diag(attr_parsing_invalid_link_modifier)]
|
||||||
"invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols"
|
|
||||||
)]
|
|
||||||
pub(crate) struct InvalidLinkModifier {
|
pub(crate) struct InvalidLinkModifier {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("multiple `{$modifier}` modifiers in a single `modifiers` argument")]
|
#[diag(attr_parsing_multiple_modifiers)]
|
||||||
pub(crate) struct MultipleModifiers {
|
pub(crate) struct MultipleModifiers {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -942,61 +886,52 @@ pub(crate) struct MultipleModifiers {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("import name type is only supported on x86")]
|
#[diag(attr_parsing_import_name_type_x86)]
|
||||||
pub(crate) struct ImportNameTypeX86 {
|
pub(crate) struct ImportNameTypeX86 {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("linking modifier `bundle` is only compatible with `static` linking kind")]
|
#[diag(attr_parsing_bundle_needs_static)]
|
||||||
pub(crate) struct BundleNeedsStatic {
|
pub(crate) struct BundleNeedsStatic {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("linking modifier `export-symbols` is only compatible with `static` linking kind")]
|
#[diag(attr_parsing_whole_archive_needs_static)]
|
||||||
pub(crate) struct ExportSymbolsNeedsStatic {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("linking modifier `whole-archive` is only compatible with `static` linking kind")]
|
|
||||||
pub(crate) struct WholeArchiveNeedsStatic {
|
pub(crate) struct WholeArchiveNeedsStatic {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(
|
#[diag(attr_parsing_as_needed_compatibility)]
|
||||||
"linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds"
|
|
||||||
)]
|
|
||||||
pub(crate) struct AsNeededCompatibility {
|
pub(crate) struct AsNeededCompatibility {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("import name type can only be used with link kind `raw-dylib`")]
|
#[diag(attr_parsing_import_name_type_raw)]
|
||||||
pub(crate) struct ImportNameTypeRaw {
|
pub(crate) struct ImportNameTypeRaw {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`limit` must be a non-negative integer")]
|
#[diag(attr_parsing_limit_invalid)]
|
||||||
pub(crate) struct LimitInvalid<'a> {
|
pub(crate) struct LimitInvalid<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[label("{$error_str}")]
|
#[label]
|
||||||
pub value_span: Span,
|
pub value_span: Span,
|
||||||
pub error_str: &'a str,
|
pub error_str: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("wrong `cfg_attr` delimiters")]
|
#[diag(attr_parsing_cfg_attr_bad_delim)]
|
||||||
pub(crate) struct CfgAttrBadDelim {
|
pub(crate) struct CfgAttrBadDelim {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -1005,25 +940,14 @@ pub(crate) struct CfgAttrBadDelim {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(
|
#[diag(attr_parsing_doc_alias_malformed)]
|
||||||
"doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of strings `#[doc(alias(\"a\", \"b\"))]`"
|
|
||||||
)]
|
|
||||||
pub(crate) struct DocAliasMalformed {
|
pub(crate) struct DocAliasMalformed {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("definition of an unknown lang item: `{$name}`", code = E0522)]
|
#[diag(attr_parsing_unsupported_instruction_set)]
|
||||||
pub(crate) struct UnknownLangItem {
|
|
||||||
#[primary_span]
|
|
||||||
#[label("definition of unknown lang item `{$name}`")]
|
|
||||||
pub span: Span,
|
|
||||||
pub name: Symbol,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`")]
|
|
||||||
pub(crate) struct UnsupportedInstructionSet<'a> {
|
pub(crate) struct UnsupportedInstructionSet<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ pub(crate) fn allowed_targets_applied(
|
||||||
];
|
];
|
||||||
const IMPL_LIKE: &[Target] =
|
const IMPL_LIKE: &[Target] =
|
||||||
&[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }];
|
&[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }];
|
||||||
const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum, Target::Union];
|
const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum];
|
||||||
|
|
||||||
let mut added_fake_targets = Vec::new();
|
let mut added_fake_targets = Vec::new();
|
||||||
filter_targets(
|
filter_targets(
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ polonius-engine = "0.13.0"
|
||||||
rustc_abi = { path = "../rustc_abi" }
|
rustc_abi = { path = "../rustc_abi" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_graphviz = { path = "../rustc_graphviz" }
|
rustc_graphviz = { path = "../rustc_graphviz" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
|
|
|
||||||
296
compiler/rustc_borrowck/messages.ftl
Normal file
296
compiler/rustc_borrowck/messages.ftl
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
borrowck_assign_due_to_use_closure =
|
||||||
|
assignment occurs due to use in closure
|
||||||
|
|
||||||
|
borrowck_assign_due_to_use_coroutine =
|
||||||
|
assign occurs due to use in coroutine
|
||||||
|
|
||||||
|
borrowck_assign_part_due_to_use_closure =
|
||||||
|
assignment to part occurs due to use in closure
|
||||||
|
|
||||||
|
borrowck_assign_part_due_to_use_coroutine =
|
||||||
|
assign to part occurs due to use in coroutine
|
||||||
|
|
||||||
|
borrowck_borrow_due_to_use_closure =
|
||||||
|
borrow occurs due to use in closure
|
||||||
|
|
||||||
|
borrowck_borrow_due_to_use_coroutine =
|
||||||
|
borrow occurs due to use in coroutine
|
||||||
|
|
||||||
|
borrowck_calling_operator_moves =
|
||||||
|
calling this operator moves the value
|
||||||
|
|
||||||
|
borrowck_calling_operator_moves_lhs =
|
||||||
|
calling this operator moves the left-hand side
|
||||||
|
|
||||||
|
borrowck_cannot_move_when_borrowed =
|
||||||
|
cannot move out of {$place ->
|
||||||
|
[value] value
|
||||||
|
*[other] {$place}
|
||||||
|
} because it is borrowed
|
||||||
|
.label = borrow of {$borrow_place ->
|
||||||
|
[value] value
|
||||||
|
*[other] {$borrow_place}
|
||||||
|
} occurs here
|
||||||
|
.move_label = move out of {$value_place ->
|
||||||
|
[value] value
|
||||||
|
*[other] {$value_place}
|
||||||
|
} occurs here
|
||||||
|
|
||||||
|
borrowck_capture_immute =
|
||||||
|
capture is immutable because of use here
|
||||||
|
|
||||||
|
borrowck_capture_move =
|
||||||
|
capture is moved because of use here
|
||||||
|
|
||||||
|
borrowck_capture_mut =
|
||||||
|
capture is mutable because of use here
|
||||||
|
|
||||||
|
borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
|
||||||
|
|
||||||
|
borrowck_closure_invoked_twice =
|
||||||
|
closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment
|
||||||
|
|
||||||
|
borrowck_closure_moved_twice =
|
||||||
|
closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment
|
||||||
|
|
||||||
|
borrowck_consider_borrow_type_contents =
|
||||||
|
help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
|
||||||
|
|
||||||
|
borrowck_could_not_normalize =
|
||||||
|
could not normalize `{$value}`
|
||||||
|
|
||||||
|
borrowck_could_not_prove =
|
||||||
|
could not prove `{$predicate}`
|
||||||
|
|
||||||
|
borrowck_dereference_suggestion =
|
||||||
|
dereference the return value
|
||||||
|
|
||||||
|
borrowck_func_take_self_moved_place =
|
||||||
|
`{$func}` takes ownership of the receiver `self`, which moves {$place_name}
|
||||||
|
|
||||||
|
borrowck_generic_does_not_live_long_enough =
|
||||||
|
`{$kind}` does not live long enough
|
||||||
|
|
||||||
|
borrowck_higher_ranked_lifetime_error =
|
||||||
|
higher-ranked lifetime error
|
||||||
|
|
||||||
|
borrowck_higher_ranked_subtype_error =
|
||||||
|
higher-ranked subtype error
|
||||||
|
|
||||||
|
borrowck_implicit_static =
|
||||||
|
this has an implicit `'static` lifetime requirement
|
||||||
|
|
||||||
|
borrowck_implicit_static_introduced =
|
||||||
|
calling this method introduces the `impl`'s `'static` requirement
|
||||||
|
|
||||||
|
borrowck_implicit_static_relax =
|
||||||
|
consider relaxing the implicit `'static` requirement
|
||||||
|
|
||||||
|
borrowck_lifetime_constraints_error =
|
||||||
|
lifetime may not live long enough
|
||||||
|
|
||||||
|
borrowck_limitations_implies_static =
|
||||||
|
due to a current limitation of the type system, this implies a `'static` lifetime
|
||||||
|
|
||||||
|
borrowck_move_closure_suggestion =
|
||||||
|
consider adding 'move' keyword before the nested closure
|
||||||
|
|
||||||
|
borrowck_move_out_place_here =
|
||||||
|
{$place} is moved here
|
||||||
|
|
||||||
|
borrowck_move_unsized =
|
||||||
|
cannot move a value of type `{$ty}`
|
||||||
|
.label = the size of `{$ty}` cannot be statically determined
|
||||||
|
|
||||||
|
borrowck_moved_a_fn_once_in_call =
|
||||||
|
this value implements `FnOnce`, which causes it to be moved when called
|
||||||
|
|
||||||
|
borrowck_moved_a_fn_once_in_call_call =
|
||||||
|
`FnOnce` closures can only be called once
|
||||||
|
|
||||||
|
borrowck_moved_a_fn_once_in_call_def =
|
||||||
|
`{$ty}` is made to be an `FnOnce` closure here
|
||||||
|
|
||||||
|
borrowck_moved_due_to_await =
|
||||||
|
{$place_name} {$is_partial ->
|
||||||
|
[true] partially moved
|
||||||
|
*[false] moved
|
||||||
|
} due to this {$is_loop_message ->
|
||||||
|
[true] await, in previous iteration of loop
|
||||||
|
*[false] await
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowck_moved_due_to_call =
|
||||||
|
{$place_name} {$is_partial ->
|
||||||
|
[true] partially moved
|
||||||
|
*[false] moved
|
||||||
|
} due to this {$is_loop_message ->
|
||||||
|
[true] call, in previous iteration of loop
|
||||||
|
*[false] call
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowck_moved_due_to_implicit_into_iter_call =
|
||||||
|
{$place_name} {$is_partial ->
|
||||||
|
[true] partially moved
|
||||||
|
*[false] moved
|
||||||
|
} due to this implicit call to {$is_loop_message ->
|
||||||
|
[true] `.into_iter()`, in previous iteration of loop
|
||||||
|
*[false] `.into_iter()`
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowck_moved_due_to_method_call =
|
||||||
|
{$place_name} {$is_partial ->
|
||||||
|
[true] partially moved
|
||||||
|
*[false] moved
|
||||||
|
} due to this method {$is_loop_message ->
|
||||||
|
[true] call, in previous iteration of loop
|
||||||
|
*[false] call
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowck_moved_due_to_usage_in_operator =
|
||||||
|
{$place_name} {$is_partial ->
|
||||||
|
[true] partially moved
|
||||||
|
*[false] moved
|
||||||
|
} due to usage in {$is_loop_message ->
|
||||||
|
[true] operator, in previous iteration of loop
|
||||||
|
*[false] operator
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowck_opaque_type_lifetime_mismatch =
|
||||||
|
opaque type used twice with different lifetimes
|
||||||
|
.label = lifetime `{$arg}` used here
|
||||||
|
.prev_lifetime_label = lifetime `{$prev}` previously used here
|
||||||
|
.note = if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
|
||||||
|
|
||||||
|
borrowck_partial_var_move_by_use_in_closure =
|
||||||
|
variable {$is_partial ->
|
||||||
|
[true] partially moved
|
||||||
|
*[false] moved
|
||||||
|
} due to use in closure
|
||||||
|
|
||||||
|
borrowck_partial_var_move_by_use_in_coroutine =
|
||||||
|
variable {$is_partial ->
|
||||||
|
[true] partially moved
|
||||||
|
*[false] moved
|
||||||
|
} due to use in coroutine
|
||||||
|
|
||||||
|
borrowck_restrict_to_static =
|
||||||
|
consider restricting the type parameter to the `'static` lifetime
|
||||||
|
|
||||||
|
borrowck_returned_async_block_escaped =
|
||||||
|
returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
|
||||||
|
|
||||||
|
borrowck_returned_closure_escaped =
|
||||||
|
returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
||||||
|
|
||||||
|
borrowck_returned_lifetime_short =
|
||||||
|
{$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`
|
||||||
|
|
||||||
|
borrowck_returned_lifetime_wrong =
|
||||||
|
{$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`
|
||||||
|
|
||||||
|
borrowck_returned_ref_escaped =
|
||||||
|
returns a reference to a captured variable which escapes the closure body
|
||||||
|
|
||||||
|
borrowck_simd_intrinsic_arg_const =
|
||||||
|
{$arg ->
|
||||||
|
[1] 1st
|
||||||
|
[2] 2nd
|
||||||
|
[3] 3rd
|
||||||
|
*[other] {$arg}th
|
||||||
|
} argument of `{$intrinsic}` is required to be a `const` item
|
||||||
|
|
||||||
|
borrowck_suggest_create_fresh_reborrow =
|
||||||
|
consider reborrowing the `Pin` instead of moving it
|
||||||
|
|
||||||
|
borrowck_suggest_iterate_over_slice =
|
||||||
|
consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
|
||||||
|
|
||||||
|
borrowck_tail_expr_drop_order = relative drop order changing in Rust 2024
|
||||||
|
.label = this temporary value will be dropped at the end of the block
|
||||||
|
.note = consider using a `let` binding to ensure the value will live long enough
|
||||||
|
|
||||||
|
borrowck_ty_no_impl_copy =
|
||||||
|
{$is_partial_move ->
|
||||||
|
[true] partial move
|
||||||
|
*[false] move
|
||||||
|
} occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait
|
||||||
|
|
||||||
|
borrowck_use_due_to_use_closure =
|
||||||
|
use occurs due to use in closure
|
||||||
|
|
||||||
|
borrowck_use_due_to_use_coroutine =
|
||||||
|
use occurs due to use in coroutine
|
||||||
|
|
||||||
|
borrowck_used_impl_require_static =
|
||||||
|
the used `impl` has a `'static` requirement
|
||||||
|
|
||||||
|
borrowck_value_capture_here =
|
||||||
|
value captured {$is_within ->
|
||||||
|
[true] here by coroutine
|
||||||
|
*[false] here
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowck_value_moved_here =
|
||||||
|
value {$is_partial ->
|
||||||
|
[true] partially moved
|
||||||
|
*[false] moved
|
||||||
|
} {$is_move_msg ->
|
||||||
|
[true] into closure here
|
||||||
|
*[false] here
|
||||||
|
}{$is_loop_message ->
|
||||||
|
[true] , in previous iteration of loop
|
||||||
|
*[false] {""}
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowck_var_borrow_by_use_in_closure =
|
||||||
|
borrow occurs due to use in closure
|
||||||
|
|
||||||
|
borrowck_var_borrow_by_use_in_coroutine =
|
||||||
|
borrow occurs due to use in coroutine
|
||||||
|
|
||||||
|
borrowck_var_borrow_by_use_place_in_closure =
|
||||||
|
{$is_single_var ->
|
||||||
|
*[true] borrow occurs
|
||||||
|
[false] borrows occur
|
||||||
|
} due to use of {$place} in closure
|
||||||
|
|
||||||
|
borrowck_var_borrow_by_use_place_in_coroutine =
|
||||||
|
{$is_single_var ->
|
||||||
|
*[true] borrow occurs
|
||||||
|
[false] borrows occur
|
||||||
|
} due to use of {$place} in coroutine
|
||||||
|
|
||||||
|
borrowck_var_cannot_escape_closure =
|
||||||
|
captured variable cannot escape `FnMut` closure body
|
||||||
|
.note = `FnMut` closures only have access to their captured variables while they are executing...
|
||||||
|
.cannot_escape = ...therefore, they cannot allow references to captured variables to escape
|
||||||
|
|
||||||
|
borrowck_var_does_not_need_mut =
|
||||||
|
variable does not need to be mutable
|
||||||
|
.suggestion = remove this `mut`
|
||||||
|
|
||||||
|
borrowck_var_first_borrow_by_use_place_in_closure =
|
||||||
|
first borrow occurs due to use of {$place} in closure
|
||||||
|
|
||||||
|
borrowck_var_first_borrow_by_use_place_in_coroutine =
|
||||||
|
first borrow occurs due to use of {$place} in coroutine
|
||||||
|
|
||||||
|
borrowck_var_here_captured = variable captured here
|
||||||
|
|
||||||
|
borrowck_var_here_defined = variable defined here
|
||||||
|
|
||||||
|
borrowck_var_move_by_use_in_closure =
|
||||||
|
move occurs due to use in closure
|
||||||
|
|
||||||
|
borrowck_var_move_by_use_in_coroutine =
|
||||||
|
move occurs due to use in coroutine
|
||||||
|
|
||||||
|
borrowck_var_mutable_borrow_by_use_place_in_closure =
|
||||||
|
mutable borrow occurs due to use of {$place} in closure
|
||||||
|
|
||||||
|
borrowck_var_second_borrow_by_use_place_in_closure =
|
||||||
|
second borrow occurs due to use of {$place} in closure
|
||||||
|
|
||||||
|
borrowck_var_second_borrow_by_use_place_in_coroutine =
|
||||||
|
second borrow occurs due to use of {$place} in coroutine
|
||||||
|
|
@ -253,52 +253,19 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let region = region.as_var();
|
let region = region.as_var();
|
||||||
let borrow = |activation_location| BorrowData {
|
|
||||||
|
let borrow = BorrowData {
|
||||||
kind,
|
kind,
|
||||||
region,
|
region,
|
||||||
reserve_location: location,
|
reserve_location: location,
|
||||||
activation_location,
|
activation_location: TwoPhaseActivation::NotTwoPhase,
|
||||||
borrowed_place,
|
borrowed_place,
|
||||||
assigned_place: *assigned_place,
|
assigned_place: *assigned_place,
|
||||||
};
|
};
|
||||||
|
let (idx, _) = self.location_map.insert_full(location, borrow);
|
||||||
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);
|
let idx = BorrowIndex::from(idx);
|
||||||
|
|
||||||
// Insert `temp` into the list of pending activations. From
|
self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx);
|
||||||
// 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);
|
self.local_map.entry(borrowed_place.local).or_default().insert(idx);
|
||||||
}
|
}
|
||||||
|
|
@ -367,3 +334,62 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
|
||||||
self.super_rvalue(rvalue, location)
|
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,3 +1,6 @@
|
||||||
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, struct_span_code_err};
|
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, struct_span_code_err};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use crate::MirBorrowckCtxt;
|
use crate::MirBorrowckCtxt;
|
||||||
|
use crate::region_infer::values::RegionElement;
|
||||||
use crate::session_diagnostics::{
|
use crate::session_diagnostics::{
|
||||||
HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
|
HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
|
||||||
};
|
};
|
||||||
|
|
@ -48,12 +49,11 @@ impl<'tcx> UniverseInfo<'tcx> {
|
||||||
UniverseInfo::RelateTys { expected, found }
|
UniverseInfo::RelateTys { expected, found }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Report an error where an element erroneously made its way into `placeholder`.
|
|
||||||
pub(crate) fn report_erroneous_element(
|
pub(crate) fn report_erroneous_element(
|
||||||
&self,
|
&self,
|
||||||
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
|
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
|
||||||
placeholder: ty::PlaceholderRegion<'tcx>,
|
placeholder: ty::PlaceholderRegion<'tcx>,
|
||||||
error_element: Option<ty::PlaceholderRegion<'tcx>>,
|
error_element: RegionElement<'tcx>,
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
) {
|
) {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
@ -153,7 +153,7 @@ pub(crate) trait TypeOpInfo<'tcx> {
|
||||||
&self,
|
&self,
|
||||||
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
|
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
|
||||||
placeholder: ty::PlaceholderRegion<'tcx>,
|
placeholder: ty::PlaceholderRegion<'tcx>,
|
||||||
error_element: Option<ty::PlaceholderRegion<'tcx>>,
|
error_element: RegionElement<'tcx>,
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
) {
|
) {
|
||||||
let tcx = mbcx.infcx.tcx;
|
let tcx = mbcx.infcx.tcx;
|
||||||
|
|
@ -169,20 +169,22 @@ pub(crate) trait TypeOpInfo<'tcx> {
|
||||||
|
|
||||||
let placeholder_region = ty::Region::new_placeholder(
|
let placeholder_region = ty::Region::new_placeholder(
|
||||||
tcx,
|
tcx,
|
||||||
ty::PlaceholderRegion::new(adjusted_universe.into(), placeholder.bound),
|
ty::Placeholder::new(adjusted_universe.into(), placeholder.bound),
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME: one day this should just be error_element,
|
let error_region =
|
||||||
// and this method shouldn't do anything.
|
if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
|
||||||
let error_region = error_element.and_then(|e| {
|
let adjusted_universe =
|
||||||
let adjusted_universe = e.universe.as_u32().checked_sub(base_universe.as_u32());
|
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
|
||||||
adjusted_universe.map(|adjusted| {
|
adjusted_universe.map(|adjusted| {
|
||||||
ty::Region::new_placeholder(
|
ty::Region::new_placeholder(
|
||||||
tcx,
|
tcx,
|
||||||
ty::PlaceholderRegion::new(adjusted.into(), e.bound),
|
ty::Placeholder::new(adjusted.into(), error_placeholder.bound),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
});
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
debug!(?placeholder_region);
|
debug!(?placeholder_region);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
// ignore-tidy-filelength
|
// ignore-tidy-filelength
|
||||||
|
|
||||||
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
|
@ -1256,7 +1259,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
self.suggest_cloning_inner(err, ty, expr);
|
self.suggest_cloning_inner(err, ty, expr);
|
||||||
}
|
}
|
||||||
} else if let ty::Adt(def, args) = ty.kind()
|
} else if let ty::Adt(def, args) = ty.kind()
|
||||||
&& let Some(local_did) = def.did().as_local()
|
&& def.did().as_local().is_some()
|
||||||
&& def.variants().iter().all(|variant| {
|
&& def.variants().iter().all(|variant| {
|
||||||
variant
|
variant
|
||||||
.fields
|
.fields
|
||||||
|
|
@ -1266,50 +1269,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
{
|
{
|
||||||
let ty_span = self.infcx.tcx.def_span(def.did());
|
let ty_span = self.infcx.tcx.def_span(def.did());
|
||||||
let mut span: MultiSpan = ty_span.into();
|
let mut span: MultiSpan = ty_span.into();
|
||||||
let mut derive_clone = false;
|
span.push_span_label(ty_span, "consider implementing `Clone` for this type");
|
||||||
self.infcx.tcx.for_each_relevant_impl(
|
|
||||||
self.infcx.tcx.lang_items().clone_trait().unwrap(),
|
|
||||||
ty,
|
|
||||||
|def_id| {
|
|
||||||
if self.infcx.tcx.is_automatically_derived(def_id) {
|
|
||||||
derive_clone = true;
|
|
||||||
span.push_span_label(
|
|
||||||
self.infcx.tcx.def_span(def_id),
|
|
||||||
"derived `Clone` adds implicit bounds on type parameters",
|
|
||||||
);
|
|
||||||
if let Some(generics) = self.infcx.tcx.hir_get_generics(local_did) {
|
|
||||||
for param in generics.params {
|
|
||||||
if let hir::GenericParamKind::Type { .. } = param.kind {
|
|
||||||
span.push_span_label(
|
|
||||||
param.span,
|
|
||||||
format!(
|
|
||||||
"introduces an implicit `{}: Clone` bound",
|
|
||||||
param.name.ident()
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let msg = if !derive_clone {
|
|
||||||
span.push_span_label(
|
|
||||||
ty_span,
|
|
||||||
format!(
|
|
||||||
"consider {}implementing `Clone` for this type",
|
|
||||||
if derive_clone { "manually " } else { "" }
|
|
||||||
),
|
|
||||||
);
|
|
||||||
format!("if `{ty}` implemented `Clone`, you could clone the value")
|
|
||||||
} else {
|
|
||||||
format!("if all bounds were met, you could clone the value")
|
|
||||||
};
|
|
||||||
span.push_span_label(expr.span, "you could clone this value");
|
span.push_span_label(expr.span, "you could clone this value");
|
||||||
err.span_note(span, msg);
|
err.span_note(
|
||||||
if derive_clone {
|
span,
|
||||||
err.help("consider manually implementing `Clone` to avoid undesired bounds");
|
format!("if `{ty}` implemented `Clone`, you could clone the value"),
|
||||||
}
|
);
|
||||||
} else if let ty::Param(param) = ty.kind()
|
} else if let ty::Param(param) = ty.kind()
|
||||||
&& let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
|
&& let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
|
||||||
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
|
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
|
||||||
|
|
@ -2347,12 +2312,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
tcx: TyCtxt<'hir>,
|
tcx: TyCtxt<'hir>,
|
||||||
issue_span: Span,
|
issue_span: Span,
|
||||||
expr_span: Span,
|
expr_span: Span,
|
||||||
body_expr: Option<&'hir hir::Expr<'hir>> = None,
|
body_expr: Option<&'hir hir::Expr<'hir>>,
|
||||||
loop_bind: Option<&'hir Ident> = None,
|
loop_bind: Option<&'hir Ident>,
|
||||||
loop_span: Option<Span> = None,
|
loop_span: Option<Span>,
|
||||||
head_span: Option<Span> = None,
|
head_span: Option<Span>,
|
||||||
pat_span: Option<Span> = None,
|
pat_span: Option<Span>,
|
||||||
head: Option<&'hir hir::Expr<'hir>> = None,
|
head: Option<&'hir hir::Expr<'hir>>,
|
||||||
}
|
}
|
||||||
impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
|
impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
|
||||||
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
||||||
|
|
@ -2418,7 +2383,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
hir::intravisit::walk_expr(self, ex);
|
hir::intravisit::walk_expr(self, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut finder = ExprFinder { tcx, expr_span: span, issue_span, .. };
|
let mut finder = ExprFinder {
|
||||||
|
tcx,
|
||||||
|
expr_span: span,
|
||||||
|
issue_span,
|
||||||
|
loop_bind: None,
|
||||||
|
body_expr: None,
|
||||||
|
head_span: None,
|
||||||
|
loop_span: None,
|
||||||
|
pat_span: None,
|
||||||
|
head: None,
|
||||||
|
};
|
||||||
finder.visit_expr(tcx.hir_body(body_id).value);
|
finder.visit_expr(tcx.hir_body(body_id).value);
|
||||||
|
|
||||||
if let Some(body_expr) = finder.body_expr
|
if let Some(body_expr) = finder.body_expr
|
||||||
|
|
@ -2653,13 +2628,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
|
|
||||||
struct ExpressionFinder<'tcx> {
|
struct ExpressionFinder<'tcx> {
|
||||||
capture_span: Span,
|
capture_span: Span,
|
||||||
closure_change_spans: Vec<Span> = vec![],
|
closure_change_spans: Vec<Span>,
|
||||||
closure_arg_span: Option<Span> = None,
|
closure_arg_span: Option<Span>,
|
||||||
in_closure: bool = false,
|
in_closure: bool,
|
||||||
suggest_arg: String = String::new(),
|
suggest_arg: String,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
closure_local_id: Option<hir::HirId> = None,
|
closure_local_id: Option<hir::HirId>,
|
||||||
closure_call_changes: Vec<(Span, String)> = vec![],
|
closure_call_changes: Vec<(Span, String)>,
|
||||||
}
|
}
|
||||||
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
|
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
|
||||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||||
|
|
@ -2740,8 +2715,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}) = self.infcx.tcx.hir_node(self.mir_hir_id())
|
}) = self.infcx.tcx.hir_node(self.mir_hir_id())
|
||||||
&& let hir::Node::Expr(expr) = self.infcx.tcx.hir_node(body_id.hir_id)
|
&& let hir::Node::Expr(expr) = self.infcx.tcx.hir_node(body_id.hir_id)
|
||||||
{
|
{
|
||||||
let mut finder =
|
let mut finder = ExpressionFinder {
|
||||||
ExpressionFinder { capture_span: *capture_kind_span, tcx: self.infcx.tcx, .. };
|
capture_span: *capture_kind_span,
|
||||||
|
closure_change_spans: vec![],
|
||||||
|
closure_arg_span: None,
|
||||||
|
in_closure: false,
|
||||||
|
suggest_arg: String::new(),
|
||||||
|
closure_local_id: None,
|
||||||
|
closure_call_changes: vec![],
|
||||||
|
tcx: self.infcx.tcx,
|
||||||
|
};
|
||||||
finder.visit_expr(expr);
|
finder.visit_expr(expr);
|
||||||
|
|
||||||
if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
|
if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
//! Print diagnostics to explain why values are borrowed.
|
//! Print diagnostics to explain why values are borrowed.
|
||||||
|
|
||||||
use rustc_data_structures::assert_matches;
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
|
use std::assert_matches::assert_matches;
|
||||||
|
|
||||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
|
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
|
|
@ -649,8 +653,8 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||||
// We want to focus on relevant live locals in diagnostics, so when polonius is enabled, we
|
// We want to focus on relevant live locals in diagnostics, so when polonius is enabled, we
|
||||||
// ensure that we don't emit live boring locals as explanations.
|
// ensure that we don't emit live boring locals as explanations.
|
||||||
let is_local_boring = |local| {
|
let is_local_boring = |local| {
|
||||||
if let Some(polonius_context) = self.polonius_context {
|
if let Some(polonius_diagnostics) = self.polonius_diagnostics {
|
||||||
polonius_context.boring_nll_locals.contains(&local)
|
polonius_diagnostics.boring_nll_locals.contains(&local)
|
||||||
} else {
|
} else {
|
||||||
assert!(!tcx.sess.opts.unstable_opts.polonius.is_next_enabled());
|
assert!(!tcx.sess.opts.unstable_opts.polonius.is_next_enabled());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::collections::BTreeMap;
|
||||||
|
|
||||||
use rustc_abi::{FieldIdx, VariantIdx};
|
use rustc_abi::{FieldIdx, VariantIdx};
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_errors::{Applicability, Diag, DiagMessage, EmissionGuarantee, MultiSpan, listify, msg};
|
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
|
||||||
use rustc_hir::def::{CtorKind, Namespace};
|
use rustc_hir::def::{CtorKind, Namespace};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
self as hir, CoroutineKind, GenericBound, LangItem, WhereBoundPredicate, WherePredicateKind,
|
self as hir, CoroutineKind, GenericBound, LangItem, WhereBoundPredicate, WherePredicateKind,
|
||||||
|
|
@ -35,6 +35,7 @@ use tracing::debug;
|
||||||
use super::MirBorrowckCtxt;
|
use super::MirBorrowckCtxt;
|
||||||
use super::borrow_set::BorrowData;
|
use super::borrow_set::BorrowData;
|
||||||
use crate::constraints::OutlivesConstraint;
|
use crate::constraints::OutlivesConstraint;
|
||||||
|
use crate::fluent_generated as fluent;
|
||||||
use crate::nll::ConstraintDescription;
|
use crate::nll::ConstraintDescription;
|
||||||
use crate::session_diagnostics::{
|
use crate::session_diagnostics::{
|
||||||
CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
|
CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
|
||||||
|
|
@ -161,6 +162,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}
|
}
|
||||||
for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
|
for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
|
||||||
if count > 10 {
|
if count > 10 {
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||||
}
|
}
|
||||||
self.buffer_error(diag);
|
self.buffer_error(diag);
|
||||||
|
|
@ -233,6 +236,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
/// LL | for (key, value) in dict {
|
/// LL | for (key, value) in dict {
|
||||||
/// | ^^^^
|
/// | ^^^^
|
||||||
/// ```
|
/// ```
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||||
pub(super) fn add_moved_or_invoked_closure_note(
|
pub(super) fn add_moved_or_invoked_closure_note(
|
||||||
&self,
|
&self,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
|
@ -699,7 +703,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
|
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
diag.span_note(pred.span, LIMITATION_NOTE);
|
diag.span_note(pred.span, fluent::borrowck_limitations_implies_static);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for bound in bounds.iter() {
|
for bound in bounds.iter() {
|
||||||
|
|
@ -710,7 +714,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
|
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
diag.span_note(bound.span, LIMITATION_NOTE);
|
diag.span_note(bound.span, fluent::borrowck_limitations_implies_static);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -816,6 +820,7 @@ impl UseSpans<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a span label to the arguments of the closure, if it exists.
|
/// 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) {
|
pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
|
||||||
if let UseSpans::ClosureUse { args_span, .. } = self {
|
if let UseSpans::ClosureUse { args_span, .. } = self {
|
||||||
err.subdiagnostic(f(args_span));
|
err.subdiagnostic(f(args_span));
|
||||||
|
|
@ -824,6 +829,7 @@ impl UseSpans<'_> {
|
||||||
|
|
||||||
/// Add a span label to the use of the captured variable, if it exists.
|
/// Add a span label to the use of the captured variable, if it exists.
|
||||||
/// only adds label to the `path_span`
|
/// only adds label to the `path_span`
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub(super) fn var_path_only_subdiag(
|
pub(super) fn var_path_only_subdiag(
|
||||||
self,
|
self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
|
|
@ -855,6 +861,7 @@ impl UseSpans<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a subdiagnostic to the use of the captured variable, if it exists.
|
/// Add a subdiagnostic to the use of the captured variable, if it exists.
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub(super) fn var_subdiag(
|
pub(super) fn var_subdiag(
|
||||||
self,
|
self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
|
|
@ -1218,6 +1225,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
self.borrow_spans(span, borrow.reserve_location)
|
self.borrow_spans(span, borrow.reserve_location)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||||
fn explain_captures(
|
fn explain_captures(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diag<'infcx>,
|
err: &mut Diag<'infcx>,
|
||||||
|
|
@ -1311,7 +1320,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let mut span: MultiSpan = spans.clone().into();
|
let mut span: MultiSpan = spans.clone().into();
|
||||||
err.arg("ty", param_ty.to_string());
|
err.arg("ty", param_ty.to_string());
|
||||||
let msg = err.dcx.eagerly_translate_to_string(
|
let msg = err.dcx.eagerly_translate_to_string(
|
||||||
msg!("`{$ty}` is made to be an `FnOnce` closure here"),
|
fluent::borrowck_moved_a_fn_once_in_call_def,
|
||||||
err.args.iter(),
|
err.args.iter(),
|
||||||
);
|
);
|
||||||
err.remove_arg("ty");
|
err.remove_arg("ty");
|
||||||
|
|
@ -1320,9 +1329,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}
|
}
|
||||||
span.push_span_label(
|
span.push_span_label(
|
||||||
fn_call_span,
|
fn_call_span,
|
||||||
msg!("this value implements `FnOnce`, which causes it to be moved when called"),
|
fluent::borrowck_moved_a_fn_once_in_call,
|
||||||
);
|
);
|
||||||
err.span_note(span, msg!("`FnOnce` closures can only be called once"));
|
err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
|
||||||
} else {
|
} else {
|
||||||
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
|
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
|
||||||
}
|
}
|
||||||
|
|
@ -1567,6 +1576,3 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
self.local_name(index).is_none_or(|name| name.as_str().starts_with('_'))
|
self.local_name(index).is_none_or(|name| name.as_str().starts_with('_'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const LIMITATION_NOTE: DiagMessage =
|
|
||||||
msg!("due to a current limitation of the type system, this implies a `'static` lifetime");
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
use rustc_abi::FieldIdx;
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{Applicability, Diag};
|
use rustc_errors::{Applicability, Diag};
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
|
|
@ -8,7 +10,7 @@ use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
|
use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span};
|
||||||
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
@ -473,29 +475,48 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
if def_id.as_local() == Some(self.mir_def_id())
|
if def_id.as_local() == Some(self.mir_def_id())
|
||||||
&& let Some(upvar_field) = upvar_field =>
|
&& let Some(upvar_field) = upvar_field =>
|
||||||
{
|
{
|
||||||
self.report_closure_move_error(
|
let closure_kind_ty = closure_args.as_closure().kind_ty();
|
||||||
span,
|
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
|
||||||
move_place,
|
Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
|
||||||
*def_id,
|
Some(ty::ClosureKind::FnOnce) => {
|
||||||
closure_args.as_closure().kind_ty(),
|
bug!("closure kind does not match first argument type")
|
||||||
upvar_field,
|
|
||||||
ty::Asyncness::No,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
ty::CoroutineClosure(def_id, closure_args)
|
None => bug!("closure kind not inferred by borrowck"),
|
||||||
if def_id.as_local() == Some(self.mir_def_id())
|
};
|
||||||
&& let Some(upvar_field) = upvar_field
|
let capture_description =
|
||||||
&& self
|
format!("captured variable in an `{closure_kind}` closure");
|
||||||
.get_closure_bound_clause_span(*def_id, ty::Asyncness::Yes)
|
|
||||||
.is_some() =>
|
let upvar = &self.upvars[upvar_field.index()];
|
||||||
{
|
let upvar_hir_id = upvar.get_root_variable();
|
||||||
self.report_closure_move_error(
|
let upvar_name = upvar.to_string(tcx);
|
||||||
span,
|
let upvar_span = tcx.hir_span(upvar_hir_id);
|
||||||
move_place,
|
|
||||||
*def_id,
|
let place_name = self.describe_any_place(move_place.as_ref());
|
||||||
closure_args.as_coroutine_closure().kind_ty(),
|
|
||||||
upvar_field,
|
let place_description =
|
||||||
ty::Asyncness::Yes,
|
if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
|
||||||
|
format!("{place_name}, a {capture_description}")
|
||||||
|
} else {
|
||||||
|
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}",
|
||||||
|
closure_kind_ty, closure_kind, place_description,
|
||||||
|
);
|
||||||
|
|
||||||
|
let closure_span = tcx.def_span(def_id);
|
||||||
|
|
||||||
|
self.cannot_move_out_of(span, &place_description)
|
||||||
|
.with_span_label(upvar_span, "captured outer variable")
|
||||||
|
.with_span_label(
|
||||||
|
closure_span,
|
||||||
|
format!("captured by this `{closure_kind}` closure"),
|
||||||
|
)
|
||||||
|
.with_span_help(
|
||||||
|
self.get_closure_bound_clause_span(*def_id),
|
||||||
|
"`Fn` and `FnMut` closures require captured values to be able to be \
|
||||||
|
consumed multiple times, but `FnOnce` closures may consume them only once",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -545,134 +566,45 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_closure_move_error(
|
fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
|
||||||
&self,
|
|
||||||
span: Span,
|
|
||||||
move_place: Place<'tcx>,
|
|
||||||
def_id: DefId,
|
|
||||||
closure_kind_ty: Ty<'tcx>,
|
|
||||||
upvar_field: FieldIdx,
|
|
||||||
asyncness: ty::Asyncness,
|
|
||||||
) -> Diag<'infcx> {
|
|
||||||
let tcx = self.infcx.tcx;
|
|
||||||
|
|
||||||
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
|
|
||||||
Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
|
|
||||||
Some(ty::ClosureKind::FnOnce) => {
|
|
||||||
bug!("closure kind does not match first argument type")
|
|
||||||
}
|
|
||||||
None => bug!("closure kind not inferred by borrowck"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let async_prefix = if asyncness.is_async() { "Async" } else { "" };
|
|
||||||
let capture_description =
|
|
||||||
format!("captured variable in an `{async_prefix}{closure_kind}` closure");
|
|
||||||
|
|
||||||
let upvar = &self.upvars[upvar_field.index()];
|
|
||||||
let upvar_hir_id = upvar.get_root_variable();
|
|
||||||
let upvar_name = upvar.to_string(tcx);
|
|
||||||
let upvar_span = tcx.hir_span(upvar_hir_id);
|
|
||||||
|
|
||||||
let place_name = self.describe_any_place(move_place.as_ref());
|
|
||||||
|
|
||||||
let place_description = if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
|
|
||||||
format!("{place_name}, a {capture_description}")
|
|
||||||
} else {
|
|
||||||
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!(?closure_kind_ty, ?closure_kind, ?place_description);
|
|
||||||
|
|
||||||
let closure_span = tcx.def_span(def_id);
|
|
||||||
|
|
||||||
let help_msg = format!(
|
|
||||||
"`{async_prefix}Fn` and `{async_prefix}FnMut` closures require captured values to \
|
|
||||||
be able to be consumed multiple times, but `{async_prefix}FnOnce` closures may \
|
|
||||||
consume them only once"
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut err = self
|
|
||||||
.cannot_move_out_of(span, &place_description)
|
|
||||||
.with_span_label(upvar_span, "captured outer variable")
|
|
||||||
.with_span_label(
|
|
||||||
closure_span,
|
|
||||||
format!("captured by this `{async_prefix}{closure_kind}` closure"),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(bound_span) = self.get_closure_bound_clause_span(def_id, asyncness) {
|
|
||||||
err.span_help(bound_span, help_msg);
|
|
||||||
} else if !asyncness.is_async() {
|
|
||||||
// For sync closures, always emit the help message even without a span.
|
|
||||||
// For async closures, we only enter this branch if we found a valid span
|
|
||||||
// (due to the match guard), so no fallback is needed.
|
|
||||||
err.help(help_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
err
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_closure_bound_clause_span(
|
|
||||||
&self,
|
|
||||||
def_id: DefId,
|
|
||||||
asyncness: ty::Asyncness,
|
|
||||||
) -> Option<Span> {
|
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let typeck_result = tcx.typeck(self.mir_def_id());
|
let typeck_result = tcx.typeck(self.mir_def_id());
|
||||||
// Check whether the closure is an argument to a call, if so,
|
// Check whether the closure is an argument to a call, if so,
|
||||||
// get the instantiated where-bounds of that call.
|
// get the instantiated where-bounds of that call.
|
||||||
let closure_hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
|
let closure_hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
|
||||||
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return None };
|
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return DUMMY_SP };
|
||||||
|
|
||||||
let predicates = match parent.kind {
|
let predicates = match parent.kind {
|
||||||
hir::ExprKind::Call(callee, _) => {
|
hir::ExprKind::Call(callee, _) => {
|
||||||
let ty = typeck_result.node_type_opt(callee.hir_id)?;
|
let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP };
|
||||||
let ty::FnDef(fn_def_id, args) = ty.kind() else { return None };
|
let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP };
|
||||||
tcx.predicates_of(fn_def_id).instantiate(tcx, args)
|
tcx.predicates_of(fn_def_id).instantiate(tcx, args)
|
||||||
}
|
}
|
||||||
hir::ExprKind::MethodCall(..) => {
|
hir::ExprKind::MethodCall(..) => {
|
||||||
let (_, method) = typeck_result.type_dependent_def(parent.hir_id)?;
|
let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
|
||||||
|
return DUMMY_SP;
|
||||||
|
};
|
||||||
let args = typeck_result.node_args(parent.hir_id);
|
let args = typeck_result.node_args(parent.hir_id);
|
||||||
tcx.predicates_of(method).instantiate(tcx, args)
|
tcx.predicates_of(method).instantiate(tcx, args)
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return DUMMY_SP,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`
|
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`.
|
||||||
// or `AsyncFn[Mut]`.
|
|
||||||
for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
|
for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
|
||||||
let dominated_by_fn_trait = self
|
if let Some(clause) = pred.as_trait_clause()
|
||||||
.closure_clause_kind(*pred, def_id, asyncness)
|
&& let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
|
||||||
.is_some_and(|kind| matches!(kind, ty::ClosureKind::Fn | ty::ClosureKind::FnMut));
|
&& *clause_closure_def_id == def_id
|
||||||
if dominated_by_fn_trait {
|
&& (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
|
||||||
// Found `<TyOfCapturingClosure as FnMut>` or
|
|| tcx.lang_items().fn_trait() == Some(clause.def_id()))
|
||||||
// `<TyOfCapturingClosure as AsyncFnMut>`.
|
{
|
||||||
// We point at the bound that coerced the closure, which could be changed
|
// Found `<TyOfCapturingClosure as FnMut>`
|
||||||
// to `FnOnce()` or `AsyncFnOnce()` to avoid the move error.
|
// We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
|
||||||
return Some(*span);
|
// could be changed to `FnOnce()` to avoid the move error.
|
||||||
|
return *span;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
DUMMY_SP
|
||||||
}
|
|
||||||
|
|
||||||
/// If `pred` is a trait clause binding the closure `def_id` to `Fn`/`FnMut`/`FnOnce`
|
|
||||||
/// (or their async equivalents based on `asyncness`), returns the corresponding
|
|
||||||
/// `ClosureKind`. Otherwise returns `None`.
|
|
||||||
fn closure_clause_kind(
|
|
||||||
&self,
|
|
||||||
pred: ty::Clause<'tcx>,
|
|
||||||
def_id: DefId,
|
|
||||||
asyncness: ty::Asyncness,
|
|
||||||
) -> Option<ty::ClosureKind> {
|
|
||||||
let tcx = self.infcx.tcx;
|
|
||||||
let clause = pred.as_trait_clause()?;
|
|
||||||
let kind = match asyncness {
|
|
||||||
ty::Asyncness::Yes => tcx.async_fn_trait_kind_from_def_id(clause.def_id()),
|
|
||||||
ty::Asyncness::No => tcx.fn_trait_kind_from_def_id(clause.def_id()),
|
|
||||||
}?;
|
|
||||||
match clause.self_ty().skip_binder().kind() {
|
|
||||||
ty::Closure(id, _) | ty::CoroutineClosure(id, _) if *id == def_id => Some(kind),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
|
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
use core::ops::ControlFlow;
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
|
@ -354,71 +357,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
|
self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
|
||||||
{
|
{
|
||||||
if snippet.starts_with("&mut ") {
|
if snippet.starts_with("&mut ") {
|
||||||
// In calls, `&mut &mut T` may be deref-coerced to `&mut T`, and
|
// We don't have access to the HIR to get accurate spans, but we can
|
||||||
// removing the extra `&mut` is the most direct suggestion. But for
|
// give a best effort structured suggestion.
|
||||||
// pattern-matching expressions (`match`, `if let`, `while let`), that
|
|
||||||
// can easily turn into a move, so prefer suggesting an explicit
|
|
||||||
// reborrow via `&mut *x` instead.
|
|
||||||
let mut in_pat_scrutinee = false;
|
|
||||||
let mut is_deref_coerced = false;
|
|
||||||
if let Some(expr) = self.find_expr(source_info.span) {
|
|
||||||
let tcx = self.infcx.tcx;
|
|
||||||
let span = expr.span.source_callsite();
|
|
||||||
for (_, node) in tcx.hir_parent_iter(expr.hir_id) {
|
|
||||||
if let Node::Expr(parent_expr) = node {
|
|
||||||
match parent_expr.kind {
|
|
||||||
ExprKind::Match(scrutinee, ..)
|
|
||||||
if scrutinee
|
|
||||||
.span
|
|
||||||
.source_callsite()
|
|
||||||
.contains(span) =>
|
|
||||||
{
|
|
||||||
in_pat_scrutinee = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ExprKind::Let(let_expr)
|
|
||||||
if let_expr
|
|
||||||
.init
|
|
||||||
.span
|
|
||||||
.source_callsite()
|
|
||||||
.contains(span) =>
|
|
||||||
{
|
|
||||||
in_pat_scrutinee = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let typeck = tcx.typeck(expr.hir_id.owner.def_id);
|
|
||||||
is_deref_coerced =
|
|
||||||
typeck.expr_adjustments(expr).iter().any(|adj| {
|
|
||||||
matches!(adj.kind, ty::adjustment::Adjust::Deref(_))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if in_pat_scrutinee {
|
|
||||||
// Best-effort structured suggestion: insert `*` after `&mut `.
|
|
||||||
err.span_suggestion_verbose(
|
|
||||||
source_info
|
|
||||||
.span
|
|
||||||
.with_lo(source_info.span.lo() + BytePos(5))
|
|
||||||
.shrink_to_lo(),
|
|
||||||
"to reborrow the mutable reference, add `*`",
|
|
||||||
"*",
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else if is_deref_coerced {
|
|
||||||
// We don't have access to the HIR to get accurate spans, but we
|
|
||||||
// can give a best effort structured suggestion.
|
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
|
source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
|
||||||
"if there is only one mutable reborrow, remove the `&mut`",
|
"if there is only one mutable reborrow, remove the `&mut`",
|
||||||
"",
|
"",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// This can occur with things like `(&mut self).foo()`.
|
// This can occur with things like `(&mut self).foo()`.
|
||||||
err.span_help(source_info.span, "try removing `&mut` here");
|
err.span_help(source_info.span, "try removing `&mut` here");
|
||||||
|
|
@ -1752,7 +1698,7 @@ fn suggest_ampmut<'tcx>(
|
||||||
&& let Either::Left(rhs_stmt_new) = body.stmt_at(*assign)
|
&& let Either::Left(rhs_stmt_new) = body.stmt_at(*assign)
|
||||||
&& let StatementKind::Assign(box (_, rvalue_new)) = &rhs_stmt_new.kind
|
&& let StatementKind::Assign(box (_, rvalue_new)) = &rhs_stmt_new.kind
|
||||||
&& let rhs_span_new = rhs_stmt_new.source_info.span
|
&& let rhs_span_new = rhs_stmt_new.source_info.span
|
||||||
&& let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span_new)
|
&& let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span)
|
||||||
{
|
{
|
||||||
(rvalue, rhs_span, rhs_str) = (rvalue_new, rhs_span_new, rhs_str_new);
|
(rvalue, rhs_span, rhs_str) = (rvalue_new, rhs_span_new, rhs_str_new);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
|
//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
|
||||||
//! outlives constraints.
|
//! outlives constraints.
|
||||||
|
|
||||||
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Error reporting machinery for lifetime errors.
|
//! Error reporting machinery for lifetime errors.
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, msg};
|
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::GenericBound::Trait;
|
use rustc_hir::GenericBound::Trait;
|
||||||
use rustc_hir::QPath::Resolved;
|
use rustc_hir::QPath::Resolved;
|
||||||
|
|
@ -27,15 +27,16 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
|
use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
|
||||||
use tracing::{debug, instrument, trace};
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
use super::{LIMITATION_NOTE, OutlivesSuggestionBuilder, RegionName, RegionNameSource};
|
use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
|
||||||
use crate::nll::ConstraintDescription;
|
use crate::nll::ConstraintDescription;
|
||||||
|
use crate::region_infer::values::RegionElement;
|
||||||
use crate::region_infer::{BlameConstraint, TypeTest};
|
use crate::region_infer::{BlameConstraint, TypeTest};
|
||||||
use crate::session_diagnostics::{
|
use crate::session_diagnostics::{
|
||||||
FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
|
FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
|
||||||
LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
|
LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
|
||||||
};
|
};
|
||||||
use crate::universal_regions::DefiningTy;
|
use crate::universal_regions::DefiningTy;
|
||||||
use crate::{MirBorrowckCtxt, borrowck_errors};
|
use crate::{MirBorrowckCtxt, borrowck_errors, fluent_generated as fluent};
|
||||||
|
|
||||||
impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
|
impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
|
||||||
fn description(&self) -> &'static str {
|
fn description(&self) -> &'static str {
|
||||||
|
|
@ -103,9 +104,15 @@ pub(crate) enum RegionErrorKind<'tcx> {
|
||||||
/// A generic bound failure for a type test (`T: 'a`).
|
/// A generic bound failure for a type test (`T: 'a`).
|
||||||
TypeTestError { type_test: TypeTest<'tcx> },
|
TypeTestError { type_test: TypeTest<'tcx> },
|
||||||
|
|
||||||
/// 'p outlives 'r, which does not hold. 'p is always a placeholder
|
/// Higher-ranked subtyping error.
|
||||||
/// and 'r is some other region.
|
BoundUniversalRegionError {
|
||||||
PlaceholderOutlivesIllegalRegion { longer_fr: RegionVid, illegally_outlived_r: RegionVid },
|
/// The placeholder free region.
|
||||||
|
longer_fr: RegionVid,
|
||||||
|
/// The region element that erroneously must be outlived by `longer_fr`.
|
||||||
|
error_element: RegionElement<'tcx>,
|
||||||
|
/// The placeholder region.
|
||||||
|
placeholder: ty::PlaceholderRegion<'tcx>,
|
||||||
|
},
|
||||||
|
|
||||||
/// Any other lifetime error.
|
/// Any other lifetime error.
|
||||||
RegionError {
|
RegionError {
|
||||||
|
|
@ -189,6 +196,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
// For generic associated types (GATs) which implied 'static requirement
|
// For generic associated types (GATs) which implied 'static requirement
|
||||||
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait
|
// 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
|
// 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(
|
fn suggest_static_lifetime_for_gat_from_hrtb(
|
||||||
&self,
|
&self,
|
||||||
diag: &mut Diag<'_>,
|
diag: &mut Diag<'_>,
|
||||||
|
|
@ -258,7 +266,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }) = bound else {
|
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }) = bound else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
diag.span_note(*trait_span, LIMITATION_NOTE);
|
diag.span_note(*trait_span, fluent::borrowck_limitations_implies_static);
|
||||||
let Some(generics_fn) = tcx.hir_get_generics(self.body.source.def_id().expect_local())
|
let Some(generics_fn) = tcx.hir_get_generics(self.body.source.def_id().expect_local())
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -291,7 +299,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
if suggestions.len() > 0 {
|
if suggestions.len() > 0 {
|
||||||
suggestions.dedup();
|
suggestions.dedup();
|
||||||
diag.multipart_suggestion_verbose(
|
diag.multipart_suggestion_verbose(
|
||||||
msg!("consider restricting the type parameter to the `'static` lifetime"),
|
fluent::borrowck_restrict_to_static,
|
||||||
suggestions,
|
suggestions,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
|
@ -353,11 +361,28 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionErrorKind::PlaceholderOutlivesIllegalRegion {
|
RegionErrorKind::BoundUniversalRegionError {
|
||||||
longer_fr,
|
longer_fr,
|
||||||
illegally_outlived_r,
|
placeholder,
|
||||||
|
error_element,
|
||||||
} => {
|
} => {
|
||||||
self.report_erroneous_rvid_reaches_placeholder(longer_fr, illegally_outlived_r)
|
let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
|
||||||
|
|
||||||
|
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
|
||||||
|
let cause = self
|
||||||
|
.regioncx
|
||||||
|
.best_blame_constraint(
|
||||||
|
longer_fr,
|
||||||
|
NllRegionVariableOrigin::Placeholder(placeholder),
|
||||||
|
error_vid,
|
||||||
|
)
|
||||||
|
.0
|
||||||
|
.cause;
|
||||||
|
|
||||||
|
let universe = placeholder.universe;
|
||||||
|
let universe_info = self.regioncx.universe_info(universe);
|
||||||
|
|
||||||
|
universe_info.report_erroneous_element(self, placeholder, error_element, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
|
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
|
||||||
|
|
@ -388,43 +413,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
outlives_suggestion.add_suggestion(self);
|
outlives_suggestion.add_suggestion(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Report that `longer_fr: error_vid`, which doesn't hold,
|
|
||||||
/// where `longer_fr` is a placeholder.
|
|
||||||
fn report_erroneous_rvid_reaches_placeholder(
|
|
||||||
&mut self,
|
|
||||||
longer_fr: RegionVid,
|
|
||||||
error_vid: RegionVid,
|
|
||||||
) {
|
|
||||||
use NllRegionVariableOrigin::*;
|
|
||||||
|
|
||||||
let origin_longer = self.regioncx.definitions[longer_fr].origin;
|
|
||||||
|
|
||||||
let Placeholder(placeholder) = origin_longer else {
|
|
||||||
bug!("Expected {longer_fr:?} to come from placeholder!");
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: Is throwing away the existential region really the best here?
|
|
||||||
let error_region = match self.regioncx.definitions[error_vid].origin {
|
|
||||||
FreeRegion | Existential { .. } => None,
|
|
||||||
Placeholder(other_placeholder) => Some(other_placeholder),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
|
|
||||||
let cause =
|
|
||||||
self.regioncx.best_blame_constraint(longer_fr, origin_longer, error_vid).0.cause;
|
|
||||||
|
|
||||||
// FIXME these methods should have better names, and also probably not be this generic.
|
|
||||||
// FIXME note that we *throw away* the error element here! We probably want to
|
|
||||||
// thread it through the computation further down and use it, but there currently isn't
|
|
||||||
// anything there to receive it.
|
|
||||||
self.regioncx.universe_info(placeholder.universe).report_erroneous_element(
|
|
||||||
self,
|
|
||||||
placeholder,
|
|
||||||
error_region,
|
|
||||||
cause,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report an error because the universal region `fr` was required to outlive
|
/// Report an error because the universal region `fr` was required to outlive
|
||||||
/// `outlived_fr` but it is not known to do so. For example:
|
/// `outlived_fr` but it is not known to do so. For example:
|
||||||
///
|
///
|
||||||
|
|
@ -433,6 +421,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
|
/// 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(
|
pub(crate) fn report_region_error(
|
||||||
&mut self,
|
&mut self,
|
||||||
fr: RegionVid,
|
fr: RegionVid,
|
||||||
|
|
@ -586,6 +577,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
/// executing...
|
/// executing...
|
||||||
/// = note: ...therefore, returned references to captured variables will escape the closure
|
/// = note: ...therefore, returned references to captured variables will escape the closure
|
||||||
/// ```
|
/// ```
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||||
fn report_fnmut_error(
|
fn report_fnmut_error(
|
||||||
&self,
|
&self,
|
||||||
errci: &ErrorConstraintInfo<'tcx>,
|
errci: &ErrorConstraintInfo<'tcx>,
|
||||||
|
|
@ -694,12 +686,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
|
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 {
|
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(
|
diag.span_label(
|
||||||
outlived_fr_span,
|
outlived_fr_span,
|
||||||
format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
|
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 {
|
if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
|
||||||
diag.span_label(
|
diag.span_label(
|
||||||
fr_span,
|
fr_span,
|
||||||
|
|
@ -734,6 +732,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
|
let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
|
||||||
outlived_fr_region_name.highlight_region_name(&mut diag);
|
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(
|
diag.span_label(
|
||||||
*span,
|
*span,
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -765,6 +766,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
|
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
|
||||||
/// | is returning data with lifetime `'b`
|
/// | is returning data with lifetime `'b`
|
||||||
/// ```
|
/// ```
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||||
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
|
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
|
||||||
let ErrorConstraintInfo { fr, outlived_fr, span, category, .. } = errci;
|
let ErrorConstraintInfo { fr, outlived_fr, span, category, .. } = errci;
|
||||||
|
|
||||||
|
|
@ -822,6 +824,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
|
/// 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(
|
fn add_static_impl_trait_suggestion(
|
||||||
&self,
|
&self,
|
||||||
diag: &mut Diag<'_>,
|
diag: &mut Diag<'_>,
|
||||||
|
|
@ -885,7 +889,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
for alias_ty in alias_tys {
|
for alias_ty in alias_tys {
|
||||||
if alias_ty.span.desugaring_kind().is_some() {
|
if alias_ty.span.desugaring_kind().is_some() {
|
||||||
// Skip `async` desugaring `impl Future`.
|
// Skip `async` desugaring `impl Future`.
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
|
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
|
||||||
if lt.kind == hir::LifetimeKind::ImplicitObjectLifetimeDefault {
|
if lt.kind == hir::LifetimeKind::ImplicitObjectLifetimeDefault {
|
||||||
|
|
@ -963,6 +966,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
|
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")]
|
#[instrument(skip(self, err), level = "debug")]
|
||||||
fn suggest_constrain_dyn_trait_in_impl(
|
fn suggest_constrain_dyn_trait_in_impl(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -980,18 +984,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
debug!("trait spans found: {:?}", traits);
|
debug!("trait spans found: {:?}", traits);
|
||||||
for span in &traits {
|
for span in &traits {
|
||||||
let mut multi_span: MultiSpan = vec![*span].into();
|
let mut multi_span: MultiSpan = vec![*span].into();
|
||||||
multi_span.push_span_label(
|
multi_span.push_span_label(*span, fluent::borrowck_implicit_static);
|
||||||
*span,
|
multi_span.push_span_label(ident.span, fluent::borrowck_implicit_static_introduced);
|
||||||
msg!("this has an implicit `'static` lifetime requirement"),
|
|
||||||
);
|
|
||||||
multi_span.push_span_label(
|
|
||||||
ident.span,
|
|
||||||
msg!("calling this method introduces the `impl`'s `'static` requirement"),
|
|
||||||
);
|
|
||||||
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span.shrink_to_hi(),
|
span.shrink_to_hi(),
|
||||||
msg!("consider relaxing the implicit `'static` requirement"),
|
fluent::borrowck_implicit_static_relax,
|
||||||
" + '_",
|
" + '_",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
|
@ -1034,6 +1032,7 @@ 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
|
/// 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
|
/// corresponding trait bound and see if dereferencing the closure return value would satisfy
|
||||||
/// them. If so, we produce a structured suggestion.
|
/// them. If so, we produce a structured suggestion.
|
||||||
|
|
@ -1154,13 +1153,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
if ocx.evaluate_obligations_error_on_ambiguity().is_empty() && count > 0 {
|
if ocx.evaluate_obligations_error_on_ambiguity().is_empty() && count > 0 {
|
||||||
diag.span_suggestion_verbose(
|
diag.span_suggestion_verbose(
|
||||||
tcx.hir_body(*body).value.peel_blocks().span.shrink_to_lo(),
|
tcx.hir_body(*body).value.peel_blocks().span.shrink_to_lo(),
|
||||||
msg!("dereference the return value"),
|
fluent::borrowck_dereference_suggestion,
|
||||||
"*".repeat(count),
|
"*".repeat(count),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
|
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
|
||||||
let body = self.infcx.tcx.hir_body_owned_by(self.mir_def_id());
|
let body = self.infcx.tcx.hir_body_owned_by(self.mir_def_id());
|
||||||
let expr = &body.value.peel_blocks();
|
let expr = &body.value.peel_blocks();
|
||||||
|
|
@ -1198,7 +1198,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
if let Some(closure_span) = closure_span {
|
if let Some(closure_span) = closure_span {
|
||||||
diag.span_suggestion_verbose(
|
diag.span_suggestion_verbose(
|
||||||
closure_span,
|
closure_span,
|
||||||
msg!("consider adding 'move' keyword before the nested closure"),
|
fluent::borrowck_move_closure_suggestion,
|
||||||
"move ",
|
"move ",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,11 @@ impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||||
struct PlaceholderReachability {
|
enum PlaceholderReachability {
|
||||||
|
/// This SCC reaches no placeholders.
|
||||||
|
NoPlaceholders,
|
||||||
|
/// This SCC reaches at least one placeholder.
|
||||||
|
Placeholders {
|
||||||
/// The largest-universed placeholder we can reach
|
/// The largest-universed placeholder we can reach
|
||||||
max_universe: (UniverseIndex, RegionVid),
|
max_universe: (UniverseIndex, RegionVid),
|
||||||
|
|
||||||
|
|
@ -71,14 +75,44 @@ struct PlaceholderReachability {
|
||||||
|
|
||||||
/// The placeholder with the largest ID
|
/// The placeholder with the largest ID
|
||||||
max_placeholder: RegionVid,
|
max_placeholder: RegionVid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaceholderReachability {
|
impl PlaceholderReachability {
|
||||||
/// Merge the reachable placeholders of two graph components.
|
/// Merge the reachable placeholders of two graph components.
|
||||||
fn merge(&mut self, other: &Self) {
|
fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability {
|
||||||
self.max_universe = self.max_universe.max(other.max_universe);
|
use PlaceholderReachability::*;
|
||||||
self.min_placeholder = self.min_placeholder.min(other.min_placeholder);
|
match (self, other) {
|
||||||
self.max_placeholder = self.max_placeholder.max(other.max_placeholder);
|
(NoPlaceholders, NoPlaceholders) => NoPlaceholders,
|
||||||
|
(NoPlaceholders, p @ Placeholders { .. })
|
||||||
|
| (p @ Placeholders { .. }, NoPlaceholders) => p,
|
||||||
|
(
|
||||||
|
Placeholders {
|
||||||
|
min_placeholder: min_pl,
|
||||||
|
max_placeholder: max_pl,
|
||||||
|
max_universe: max_u,
|
||||||
|
},
|
||||||
|
Placeholders { min_placeholder, max_placeholder, max_universe },
|
||||||
|
) => Placeholders {
|
||||||
|
min_placeholder: min_pl.min(min_placeholder),
|
||||||
|
max_placeholder: max_pl.max(max_placeholder),
|
||||||
|
max_universe: max_u.max(max_universe),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_universe(&self) -> Option<(UniverseIndex, RegionVid)> {
|
||||||
|
match self {
|
||||||
|
Self::NoPlaceholders => None,
|
||||||
|
Self::Placeholders { max_universe, .. } => Some(*max_universe),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If we have reached placeholders, determine if they can
|
||||||
|
/// be named from this universe.
|
||||||
|
fn can_be_named_by(&self, from: UniverseIndex) -> bool {
|
||||||
|
self.max_universe()
|
||||||
|
.is_none_or(|(max_placeholder_universe, _)| from.can_name(max_placeholder_universe))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,7 +120,7 @@ impl PlaceholderReachability {
|
||||||
/// the values of its elements. This annotates a single SCC.
|
/// the values of its elements. This annotates a single SCC.
|
||||||
#[derive(Copy, Debug, Clone)]
|
#[derive(Copy, Debug, Clone)]
|
||||||
pub(crate) struct RegionTracker {
|
pub(crate) struct RegionTracker {
|
||||||
reachable_placeholders: Option<PlaceholderReachability>,
|
reachable_placeholders: PlaceholderReachability,
|
||||||
|
|
||||||
/// The largest universe nameable from this SCC.
|
/// The largest universe nameable from this SCC.
|
||||||
/// It is the smallest nameable universes of all
|
/// It is the smallest nameable universes of all
|
||||||
|
|
@ -101,13 +135,13 @@ impl RegionTracker {
|
||||||
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
|
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
|
||||||
let reachable_placeholders =
|
let reachable_placeholders =
|
||||||
if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
|
if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
|
||||||
Some(PlaceholderReachability {
|
PlaceholderReachability::Placeholders {
|
||||||
max_universe: (definition.universe, rvid),
|
max_universe: (definition.universe, rvid),
|
||||||
min_placeholder: rvid,
|
min_placeholder: rvid,
|
||||||
max_placeholder: rvid,
|
max_placeholder: rvid,
|
||||||
})
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
PlaceholderReachability::NoPlaceholders
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -125,46 +159,43 @@ impl RegionTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
|
pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
|
||||||
self.reachable_placeholders.map(|pls| pls.max_universe.0).unwrap_or(UniverseIndex::ROOT)
|
if let Some((universe, _)) = self.reachable_placeholders.max_universe() {
|
||||||
|
universe
|
||||||
|
} else {
|
||||||
|
UniverseIndex::ROOT
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can all reachable placeholders be named from `from`?
|
|
||||||
/// True vacuously in case no placeholders were reached.
|
|
||||||
fn placeholders_can_be_named_by(&self, from: UniverseIndex) -> bool {
|
|
||||||
self.reachable_placeholders.is_none_or(|pls| from.can_name(pls.max_universe.0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine if we can name all the placeholders in `other`.
|
/// Determine if we can name all the placeholders in `other`.
|
||||||
pub(crate) fn can_name_all_placeholders(&self, other: Self) -> bool {
|
pub(crate) fn can_name_all_placeholders(&self, other: Self) -> bool {
|
||||||
// HACK: We first check whether we can name the highest existential universe
|
other.reachable_placeholders.can_be_named_by(self.max_nameable_universe.0)
|
||||||
// of `other`. This only exists to avoid errors in case that scc already
|
|
||||||
// depends on a placeholder it cannot name itself.
|
|
||||||
self.max_nameable_universe().can_name(other.max_nameable_universe())
|
|
||||||
|| other.placeholders_can_be_named_by(self.max_nameable_universe.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this SCC reaches a placeholder it can't name, return it.
|
/// If this SCC reaches a placeholder it can't name, return it.
|
||||||
fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> {
|
fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> {
|
||||||
self.reachable_placeholders
|
self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| {
|
||||||
.filter(|pls| !self.max_nameable_universe().can_name(pls.max_universe.0))
|
!self.max_nameable_universe().can_name(placeholder_universe)
|
||||||
.map(|pls| pls.max_universe)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl scc::Annotation for RegionTracker {
|
impl scc::Annotation for RegionTracker {
|
||||||
fn update_scc(&mut self, other: &Self) {
|
fn merge_scc(self, other: Self) -> Self {
|
||||||
trace!("{:?} << {:?}", self.representative, other.representative);
|
trace!("{:?} << {:?}", self.representative, other.representative);
|
||||||
self.representative = self.representative.min(other.representative);
|
|
||||||
self.update_reachable(other);
|
Self {
|
||||||
|
representative: self.representative.min(other.representative),
|
||||||
|
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
|
||||||
|
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_reachable(&mut self, other: &Self) {
|
fn merge_reached(self, other: Self) -> Self {
|
||||||
self.max_nameable_universe = self.max_nameable_universe.min(other.max_nameable_universe);
|
Self {
|
||||||
match (self.reachable_placeholders.as_mut(), other.reachable_placeholders.as_ref()) {
|
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
|
||||||
(None, None) | (Some(_), None) => (),
|
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
|
||||||
(None, Some(theirs)) => self.reachable_placeholders = Some(*theirs),
|
representative: self.representative,
|
||||||
(Some(ours), Some(theirs)) => ours.merge(theirs),
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,8 @@
|
||||||
|
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
#![cfg_attr(bootstrap, feature(assert_matches))]
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(default_field_values)]
|
|
||||||
#![feature(file_buffered)]
|
#![feature(file_buffered)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
|
|
@ -63,10 +62,10 @@ use crate::diagnostics::{
|
||||||
use crate::path_utils::*;
|
use crate::path_utils::*;
|
||||||
use crate::place_ext::PlaceExt;
|
use crate::place_ext::PlaceExt;
|
||||||
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
||||||
use crate::polonius::PoloniusContext;
|
|
||||||
use crate::polonius::legacy::{
|
use crate::polonius::legacy::{
|
||||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||||
};
|
};
|
||||||
|
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
|
||||||
use crate::prefixes::PrefixSet;
|
use crate::prefixes::PrefixSet;
|
||||||
use crate::region_infer::RegionInferenceContext;
|
use crate::region_infer::RegionInferenceContext;
|
||||||
use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
|
use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
|
||||||
|
|
@ -99,6 +98,8 @@ mod used_muts;
|
||||||
/// A public API provided for the Rust compiler consumers.
|
/// A public API provided for the Rust compiler consumers.
|
||||||
pub mod consumers;
|
pub mod consumers;
|
||||||
|
|
||||||
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
||||||
/// Associate some local constants with the `'tcx` lifetime
|
/// Associate some local constants with the `'tcx` lifetime
|
||||||
struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
|
struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
|
||||||
|
|
||||||
|
|
@ -121,11 +122,6 @@ fn mir_borrowck(
|
||||||
let (input_body, _) = tcx.mir_promoted(def);
|
let (input_body, _) = tcx.mir_promoted(def);
|
||||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
|
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
|
||||||
|
|
||||||
// We should eagerly check stalled coroutine obligations from HIR typeck.
|
|
||||||
// Not doing so leads to silent normalization failures later, which will
|
|
||||||
// fail to register opaque types in the next solver.
|
|
||||||
tcx.check_coroutine_obligations(def)?;
|
|
||||||
|
|
||||||
let input_body: &Body<'_> = &input_body.borrow();
|
let input_body: &Body<'_> = &input_body.borrow();
|
||||||
if let Some(guar) = input_body.tainted_by_errors {
|
if let Some(guar) = input_body.tainted_by_errors {
|
||||||
debug!("Skipping borrowck because of tainted body");
|
debug!("Skipping borrowck because of tainted body");
|
||||||
|
|
@ -424,7 +420,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
||||||
polonius_output,
|
polonius_output,
|
||||||
opt_closure_req,
|
opt_closure_req,
|
||||||
nll_errors,
|
nll_errors,
|
||||||
polonius_context,
|
polonius_diagnostics,
|
||||||
} = nll::compute_regions(
|
} = nll::compute_regions(
|
||||||
root_cx,
|
root_cx,
|
||||||
&infcx,
|
&infcx,
|
||||||
|
|
@ -448,7 +444,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
||||||
®ioncx,
|
®ioncx,
|
||||||
&opt_closure_req,
|
&opt_closure_req,
|
||||||
&borrow_set,
|
&borrow_set,
|
||||||
polonius_context.as_ref(),
|
polonius_diagnostics.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
||||||
|
|
@ -490,7 +486,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
||||||
polonius_output: None,
|
polonius_output: None,
|
||||||
move_errors: Vec::new(),
|
move_errors: Vec::new(),
|
||||||
diags_buffer,
|
diags_buffer,
|
||||||
polonius_context: polonius_context.as_ref(),
|
polonius_diagnostics: polonius_diagnostics.as_ref(),
|
||||||
};
|
};
|
||||||
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
|
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
|
||||||
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
|
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
|
||||||
|
|
@ -529,7 +525,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
||||||
move_errors: Vec::new(),
|
move_errors: Vec::new(),
|
||||||
diags_buffer,
|
diags_buffer,
|
||||||
polonius_output: polonius_output.as_deref(),
|
polonius_output: polonius_output.as_deref(),
|
||||||
polonius_context: polonius_context.as_ref(),
|
polonius_diagnostics: polonius_diagnostics.as_ref(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compute and report region errors, if any.
|
// Compute and report region errors, if any.
|
||||||
|
|
@ -779,7 +775,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
||||||
/// Results of Polonius analysis.
|
/// Results of Polonius analysis.
|
||||||
polonius_output: Option<&'a PoloniusOutput>,
|
polonius_output: Option<&'a PoloniusOutput>,
|
||||||
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
|
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
|
||||||
polonius_context: Option<&'a PoloniusContext>,
|
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that:
|
// Check that:
|
||||||
|
|
@ -1210,17 +1206,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
"access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
|
"access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
|
||||||
place_span, kind
|
place_span, kind
|
||||||
);
|
);
|
||||||
|
|
||||||
// If the place is being mutated, then mark it as such anyway in order to suppress the
|
|
||||||
// `unused_mut` lint, which is likely incorrect once the access place error has been
|
|
||||||
// resolved.
|
|
||||||
if rw == ReadOrWrite::Write(WriteKind::Mutate)
|
|
||||||
&& let Ok(root_place) =
|
|
||||||
self.is_mutable(place_span.0.as_ref(), is_local_mutation_allowed)
|
|
||||||
{
|
|
||||||
self.add_used_mut(root_place, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1316,7 +1301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
(Read(kind), BorrowKind::Mut { .. }) => {
|
(Read(kind), BorrowKind::Mut { .. }) => {
|
||||||
// Reading from mere reservations of mutable-borrows is OK.
|
// Reading from mere reservations of mutable-borrows is OK.
|
||||||
if !is_active(this.dominators(), borrow, location) {
|
if !is_active(this.dominators(), borrow, location) {
|
||||||
assert!(borrow.kind.is_two_phase_borrow());
|
assert!(borrow.kind.allows_two_phase_borrow());
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1479,7 +1464,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
}
|
}
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
let wk = WriteKind::MutableBorrow(bk);
|
let wk = WriteKind::MutableBorrow(bk);
|
||||||
if bk.is_two_phase_borrow() {
|
if bk.allows_two_phase_borrow() {
|
||||||
(Deep, Reservation(wk))
|
(Deep, Reservation(wk))
|
||||||
} else {
|
} else {
|
||||||
(Deep, Write(wk))
|
(Deep, Write(wk))
|
||||||
|
|
@ -1544,7 +1529,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
Rvalue::Use(operand)
|
Rvalue::Use(operand)
|
||||||
| Rvalue::Repeat(operand, _)
|
| Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
||||||
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) => {
|
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
|
||||||
|
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => {
|
||||||
self.consume_operand(location, (operand, span), state)
|
self.consume_operand(location, (operand, span), state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use polonius_engine::{Algorithm, AllFacts, Output};
|
use polonius_engine::{Algorithm, AllFacts, Output};
|
||||||
use rustc_data_structures::frozen::Frozen;
|
use rustc_data_structures::frozen::Frozen;
|
||||||
use rustc_hir::attrs::AttributeKind;
|
|
||||||
use rustc_hir::find_attr;
|
|
||||||
use rustc_index::IndexSlice;
|
use rustc_index::IndexSlice;
|
||||||
use rustc_middle::mir::pretty::PrettyPrintMirOptions;
|
use rustc_middle::mir::pretty::PrettyPrintMirOptions;
|
||||||
use rustc_middle::mir::{Body, MirDumper, PassWhere, Promoted};
|
use rustc_middle::mir::{Body, MirDumper, PassWhere, Promoted};
|
||||||
|
|
@ -17,16 +15,17 @@ use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_mir_dataflow::move_paths::MoveData;
|
use rustc_mir_dataflow::move_paths::MoveData;
|
||||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||||
use rustc_session::config::MirIncludeSpans;
|
use rustc_session::config::MirIncludeSpans;
|
||||||
|
use rustc_span::sym;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use crate::borrow_set::BorrowSet;
|
use crate::borrow_set::BorrowSet;
|
||||||
use crate::consumers::RustcFacts;
|
use crate::consumers::RustcFacts;
|
||||||
use crate::diagnostics::RegionErrors;
|
use crate::diagnostics::RegionErrors;
|
||||||
use crate::handle_placeholders::compute_sccs_applying_placeholder_outlives_constraints;
|
use crate::handle_placeholders::compute_sccs_applying_placeholder_outlives_constraints;
|
||||||
use crate::polonius::PoloniusContext;
|
|
||||||
use crate::polonius::legacy::{
|
use crate::polonius::legacy::{
|
||||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||||
};
|
};
|
||||||
|
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
|
||||||
use crate::region_infer::RegionInferenceContext;
|
use crate::region_infer::RegionInferenceContext;
|
||||||
use crate::type_check::MirTypeckRegionConstraints;
|
use crate::type_check::MirTypeckRegionConstraints;
|
||||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||||
|
|
@ -47,7 +46,7 @@ pub(crate) struct NllOutput<'tcx> {
|
||||||
|
|
||||||
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics, e.g.
|
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics, e.g.
|
||||||
/// localized typeck and liveness constraints.
|
/// localized typeck and liveness constraints.
|
||||||
pub polonius_context: Option<PoloniusContext>,
|
pub polonius_diagnostics: Option<PoloniusDiagnosticsContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
|
/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
|
||||||
|
|
@ -122,7 +121,7 @@ pub(crate) fn compute_regions<'tcx>(
|
||||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||||
mut polonius_facts: Option<AllFacts<RustcFacts>>,
|
mut polonius_facts: Option<AllFacts<RustcFacts>>,
|
||||||
mut polonius_context: Option<PoloniusContext>,
|
polonius_context: Option<PoloniusContext>,
|
||||||
) -> NllOutput<'tcx> {
|
) -> NllOutput<'tcx> {
|
||||||
let polonius_output = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_output())
|
let polonius_output = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_output())
|
||||||
|| infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
|| infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
||||||
|
|
@ -154,9 +153,9 @@ pub(crate) fn compute_regions<'tcx>(
|
||||||
|
|
||||||
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
|
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
|
||||||
// and use them to compute loan liveness.
|
// and use them to compute loan liveness.
|
||||||
if let Some(polonius_context) = polonius_context.as_mut() {
|
let polonius_diagnostics = polonius_context.map(|polonius_context| {
|
||||||
polonius_context.compute_loan_liveness(&mut regioncx, body, borrow_set)
|
polonius_context.compute_loan_liveness(infcx.tcx, &mut regioncx, body, borrow_set)
|
||||||
}
|
});
|
||||||
|
|
||||||
// If requested: dump NLL facts, and run legacy polonius analysis.
|
// If requested: dump NLL facts, and run legacy polonius analysis.
|
||||||
let polonius_output = polonius_facts.as_ref().and_then(|polonius_facts| {
|
let polonius_output = polonius_facts.as_ref().and_then(|polonius_facts| {
|
||||||
|
|
@ -189,7 +188,7 @@ pub(crate) fn compute_regions<'tcx>(
|
||||||
polonius_output,
|
polonius_output,
|
||||||
opt_closure_req: closure_region_requirements,
|
opt_closure_req: closure_region_requirements,
|
||||||
nll_errors,
|
nll_errors,
|
||||||
polonius_context,
|
polonius_diagnostics,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,13 +230,13 @@ pub(super) fn dump_nll_mir<'tcx>(
|
||||||
dumper.dump_mir(body);
|
dumper.dump_mir(body);
|
||||||
|
|
||||||
// Also dump the region constraint graph as a graphviz file.
|
// Also dump the region constraint graph as a graphviz file.
|
||||||
let _ = try {
|
let _: io::Result<()> = try {
|
||||||
let mut file = dumper.create_dump_file("regioncx.all.dot", body)?;
|
let mut file = dumper.create_dump_file("regioncx.all.dot", body)?;
|
||||||
regioncx.dump_graphviz_raw_constraints(tcx, &mut file)?;
|
regioncx.dump_graphviz_raw_constraints(tcx, &mut file)?;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Also dump the region constraint SCC graph as a graphviz file.
|
// Also dump the region constraint SCC graph as a graphviz file.
|
||||||
let _ = try {
|
let _: io::Result<()> = try {
|
||||||
let mut file = dumper.create_dump_file("regioncx.scc.dot", body)?;
|
let mut file = dumper.create_dump_file("regioncx.scc.dot", body)?;
|
||||||
regioncx.dump_graphviz_scc_constraints(tcx, &mut file)?;
|
regioncx.dump_graphviz_scc_constraints(tcx, &mut file)?;
|
||||||
};
|
};
|
||||||
|
|
@ -288,6 +287,8 @@ pub(crate) fn emit_nll_mir<'tcx>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
pub(super) fn dump_annotation<'tcx, 'infcx>(
|
pub(super) fn dump_annotation<'tcx, 'infcx>(
|
||||||
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
|
@ -296,7 +297,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
||||||
) {
|
) {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||||
if !find_attr!(tcx.get_all_attrs(base_def_id), AttributeKind::RustcRegions) {
|
if !tcx.has_attr(base_def_id, sym::rustc_regions) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,6 @@
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
|
||||||
use rustc_index::interval::SparseIntervalMatrix;
|
|
||||||
use rustc_middle::mir::{Body, Location};
|
|
||||||
use rustc_middle::ty::RegionVid;
|
use rustc_middle::ty::RegionVid;
|
||||||
use rustc_mir_dataflow::points::PointIndex;
|
use rustc_mir_dataflow::points::PointIndex;
|
||||||
|
|
||||||
use crate::BorrowSet;
|
|
||||||
use crate::constraints::OutlivesConstraint;
|
|
||||||
use crate::dataflow::BorrowIndex;
|
|
||||||
use crate::polonius::ConstraintDirection;
|
|
||||||
use crate::region_infer::values::LivenessValues;
|
|
||||||
use crate::type_check::Locations;
|
|
||||||
use crate::universal_regions::UniversalRegions;
|
|
||||||
|
|
||||||
/// A localized outlives constraint reifies the CFG location where the outlives constraint holds,
|
/// A localized outlives constraint reifies the CFG location where the outlives constraint holds,
|
||||||
/// within the origins themselves as if they were different from point to point: from `a: b`
|
/// within the origins themselves as if they were different from point to point: from `a: b`
|
||||||
/// outlives constraints to `a@p: b@p`, where `p` is the point in the CFG.
|
/// outlives constraints to `a@p: b@p`, where `p` is the point in the CFG.
|
||||||
|
|
@ -25,300 +12,32 @@ use crate::universal_regions::UniversalRegions;
|
||||||
/// of `q`. These depend on the liveness of the regions at these points, as well as their
|
/// of `q`. These depend on the liveness of the regions at these points, as well as their
|
||||||
/// variance.
|
/// variance.
|
||||||
///
|
///
|
||||||
|
/// The `source` origin at `from` flows into the `target` origin at `to`.
|
||||||
|
///
|
||||||
/// This dual of NLL's [crate::constraints::OutlivesConstraint] therefore encodes the
|
/// This dual of NLL's [crate::constraints::OutlivesConstraint] therefore encodes the
|
||||||
/// position-dependent outlives constraints used by Polonius, to model the flow-sensitive loan
|
/// position-dependent outlives constraints used by Polonius, to model the flow-sensitive loan
|
||||||
/// propagation via reachability within a graph of localized constraints.
|
/// propagation via reachability within a graph of localized constraints.
|
||||||
///
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
/// That `LocalizedConstraintGraph` can create these edges on-demand during traversal, and we
|
pub(crate) struct LocalizedOutlivesConstraint {
|
||||||
/// therefore model them as a pair of `LocalizedNode` vertices.
|
pub source: RegionVid,
|
||||||
///
|
pub from: PointIndex,
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
pub target: RegionVid,
|
||||||
pub(super) struct LocalizedNode {
|
pub to: PointIndex,
|
||||||
pub region: RegionVid,
|
|
||||||
pub point: PointIndex,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The localized constraint graph indexes the physical and logical edges to lazily compute a given
|
/// A container of [LocalizedOutlivesConstraint]s that can be turned into a traversable
|
||||||
/// node's successors during traversal.
|
/// `rustc_data_structures` graph.
|
||||||
pub(super) struct LocalizedConstraintGraph {
|
#[derive(Clone, Default, Debug)]
|
||||||
/// The actual, physical, edges we have recorded for a given node. We localize them on-demand
|
pub(crate) struct LocalizedOutlivesConstraintSet {
|
||||||
/// when traversing from the node to the successor region.
|
pub outlives: Vec<LocalizedOutlivesConstraint>,
|
||||||
edges: FxHashMap<LocalizedNode, FxIndexSet<RegionVid>>,
|
|
||||||
|
|
||||||
/// The logical edges representing the outlives constraints that hold at all points in the CFG,
|
|
||||||
/// which we don't localize to avoid creating a lot of unnecessary edges in the graph. Some CFGs
|
|
||||||
/// can be big, and we don't need to create such a physical edge for every point in the CFG.
|
|
||||||
logical_edges: FxHashMap<RegionVid, FxIndexSet<RegionVid>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The visitor interface when traversing a `LocalizedConstraintGraph`.
|
impl LocalizedOutlivesConstraintSet {
|
||||||
pub(super) trait LocalizedConstraintGraphVisitor {
|
pub(crate) fn push(&mut self, constraint: LocalizedOutlivesConstraint) {
|
||||||
/// Callback called when traversing a given `loan` encounters a localized `node` it hasn't
|
if constraint.source == constraint.target && constraint.from == constraint.to {
|
||||||
/// visited before.
|
// 'a@p: 'a@p is pretty uninteresting
|
||||||
fn on_node_traversed(&mut self, _loan: BorrowIndex, _node: LocalizedNode) {}
|
return;
|
||||||
|
}
|
||||||
/// Callback called when discovering a new `successor` node for the `current_node`.
|
self.outlives.push(constraint);
|
||||||
fn on_successor_discovered(&mut self, _current_node: LocalizedNode, _successor: LocalizedNode) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LocalizedConstraintGraph {
|
|
||||||
/// Traverses the constraints and returns the indexed graph of edges per node.
|
|
||||||
pub(super) fn new<'tcx>(
|
|
||||||
liveness: &LivenessValues,
|
|
||||||
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
|
||||||
) -> Self {
|
|
||||||
let mut edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
|
|
||||||
let mut logical_edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
|
|
||||||
|
|
||||||
for outlives_constraint in outlives_constraints {
|
|
||||||
match outlives_constraint.locations {
|
|
||||||
Locations::All(_) => {
|
|
||||||
logical_edges
|
|
||||||
.entry(outlives_constraint.sup)
|
|
||||||
.or_default()
|
|
||||||
.insert(outlives_constraint.sub);
|
|
||||||
}
|
|
||||||
|
|
||||||
Locations::Single(location) => {
|
|
||||||
let node = LocalizedNode {
|
|
||||||
region: outlives_constraint.sup,
|
|
||||||
point: liveness.point_from_location(location),
|
|
||||||
};
|
|
||||||
edges.entry(node).or_default().insert(outlives_constraint.sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalizedConstraintGraph { edges, logical_edges }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Traverses the localized constraint graph per-loan, and notifies the `visitor` of discovered
|
|
||||||
/// nodes and successors.
|
|
||||||
pub(super) fn traverse<'tcx>(
|
|
||||||
&self,
|
|
||||||
body: &Body<'tcx>,
|
|
||||||
liveness: &LivenessValues,
|
|
||||||
live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
|
|
||||||
universal_regions: &UniversalRegions<'tcx>,
|
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
|
||||||
visitor: &mut impl LocalizedConstraintGraphVisitor,
|
|
||||||
) {
|
|
||||||
let live_regions = liveness.points();
|
|
||||||
|
|
||||||
let mut visited = FxHashSet::default();
|
|
||||||
let mut stack = Vec::new();
|
|
||||||
|
|
||||||
// Compute reachability per loan by traversing each loan's subgraph starting from where it
|
|
||||||
// is introduced.
|
|
||||||
for (loan_idx, loan) in borrow_set.iter_enumerated() {
|
|
||||||
visited.clear();
|
|
||||||
stack.clear();
|
|
||||||
|
|
||||||
let start_node = LocalizedNode {
|
|
||||||
region: loan.region,
|
|
||||||
point: liveness.point_from_location(loan.reserve_location),
|
|
||||||
};
|
|
||||||
stack.push(start_node);
|
|
||||||
|
|
||||||
while let Some(node) = stack.pop() {
|
|
||||||
if !visited.insert(node) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've reached a node we haven't visited before.
|
|
||||||
let location = liveness.location_from_point(node.point);
|
|
||||||
visitor.on_node_traversed(loan_idx, node);
|
|
||||||
|
|
||||||
// When we find a _new_ successor, we'd like to
|
|
||||||
// - visit it eventually,
|
|
||||||
// - and let the generic visitor know about it.
|
|
||||||
let mut successor_found = |succ| {
|
|
||||||
if !visited.contains(&succ) {
|
|
||||||
stack.push(succ);
|
|
||||||
visitor.on_successor_discovered(node, succ);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Then, we propagate the loan along the localized constraint graph. The outgoing
|
|
||||||
// edges are computed lazily, from:
|
|
||||||
// - the various physical edges present at this node,
|
|
||||||
// - the materialized logical edges that exist virtually at all points for this
|
|
||||||
// node's region, localized at this point.
|
|
||||||
|
|
||||||
// Universal regions propagate loans along the CFG, i.e. forwards only.
|
|
||||||
let is_universal_region = universal_regions.is_universal_region(node.region);
|
|
||||||
|
|
||||||
// The physical edges present at this node are:
|
|
||||||
//
|
|
||||||
// 1. the typeck edges that flow from region to region *at this point*.
|
|
||||||
for &succ in self.edges.get(&node).into_iter().flatten() {
|
|
||||||
let succ = LocalizedNode { region: succ, point: node.point };
|
|
||||||
successor_found(succ);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2a. the liveness edges that flow *forward*, from this node's point to its
|
|
||||||
// successors in the CFG.
|
|
||||||
if body[location.block].statements.get(location.statement_index).is_some() {
|
|
||||||
// Intra-block edges, straight line constraints from each point to its successor
|
|
||||||
// within the same block.
|
|
||||||
let next_point = node.point + 1;
|
|
||||||
if let Some(succ) = compute_forward_successor(
|
|
||||||
node.region,
|
|
||||||
next_point,
|
|
||||||
live_regions,
|
|
||||||
live_region_variances,
|
|
||||||
is_universal_region,
|
|
||||||
) {
|
|
||||||
successor_found(succ);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Inter-block edges, from the block's terminator to each successor block's
|
|
||||||
// entry point.
|
|
||||||
for successor_block in body[location.block].terminator().successors() {
|
|
||||||
let next_location = Location { block: successor_block, statement_index: 0 };
|
|
||||||
let next_point = liveness.point_from_location(next_location);
|
|
||||||
if let Some(succ) = compute_forward_successor(
|
|
||||||
node.region,
|
|
||||||
next_point,
|
|
||||||
live_regions,
|
|
||||||
live_region_variances,
|
|
||||||
is_universal_region,
|
|
||||||
) {
|
|
||||||
successor_found(succ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2b. the liveness edges that flow *backward*, from this node's point to its
|
|
||||||
// predecessors in the CFG.
|
|
||||||
if !is_universal_region {
|
|
||||||
if location.statement_index > 0 {
|
|
||||||
// Backward edges to the predecessor point in the same block.
|
|
||||||
let previous_point = PointIndex::from(node.point.as_usize() - 1);
|
|
||||||
if let Some(succ) = compute_backward_successor(
|
|
||||||
node.region,
|
|
||||||
node.point,
|
|
||||||
previous_point,
|
|
||||||
live_regions,
|
|
||||||
live_region_variances,
|
|
||||||
) {
|
|
||||||
successor_found(succ);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Backward edges from the block entry point to the terminator of the
|
|
||||||
// predecessor blocks.
|
|
||||||
let predecessors = body.basic_blocks.predecessors();
|
|
||||||
for &pred_block in &predecessors[location.block] {
|
|
||||||
let previous_location = Location {
|
|
||||||
block: pred_block,
|
|
||||||
statement_index: body[pred_block].statements.len(),
|
|
||||||
};
|
|
||||||
let previous_point = liveness.point_from_location(previous_location);
|
|
||||||
if let Some(succ) = compute_backward_successor(
|
|
||||||
node.region,
|
|
||||||
node.point,
|
|
||||||
previous_point,
|
|
||||||
live_regions,
|
|
||||||
live_region_variances,
|
|
||||||
) {
|
|
||||||
successor_found(succ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// And finally, we have the logical edges, materialized at this point.
|
|
||||||
for &logical_succ in self.logical_edges.get(&node.region).into_iter().flatten() {
|
|
||||||
let succ = LocalizedNode { region: logical_succ, point: node.point };
|
|
||||||
successor_found(succ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the successor for the current region/point node when propagating a loan through forward
|
|
||||||
/// edges, if applicable, according to liveness and variance.
|
|
||||||
fn compute_forward_successor(
|
|
||||||
region: RegionVid,
|
|
||||||
next_point: PointIndex,
|
|
||||||
live_regions: &SparseIntervalMatrix<RegionVid, PointIndex>,
|
|
||||||
live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
|
|
||||||
is_universal_region: bool,
|
|
||||||
) -> Option<LocalizedNode> {
|
|
||||||
// 1. Universal regions are semantically live at all points.
|
|
||||||
if is_universal_region {
|
|
||||||
let succ = LocalizedNode { region, point: next_point };
|
|
||||||
return Some(succ);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Otherwise, gather the edges due to explicit region liveness, when applicable.
|
|
||||||
if !live_regions.contains(region, next_point) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here, `region` could be live at the current point, and is live at the next point: add a
|
|
||||||
// constraint between them, according to variance.
|
|
||||||
|
|
||||||
// Note: there currently are cases related to promoted and const generics, where we don't yet
|
|
||||||
// have variance information (possibly about temporary regions created when typeck sanitizes the
|
|
||||||
// promoteds). Until that is done, we conservatively fallback to maximizing reachability by
|
|
||||||
// adding a bidirectional edge here. This will not limit traversal whatsoever, and thus
|
|
||||||
// propagate liveness when needed.
|
|
||||||
//
|
|
||||||
// FIXME: add the missing variance information and remove this fallback bidirectional edge.
|
|
||||||
let direction =
|
|
||||||
live_region_variances.get(®ion).unwrap_or(&ConstraintDirection::Bidirectional);
|
|
||||||
|
|
||||||
match direction {
|
|
||||||
ConstraintDirection::Backward => {
|
|
||||||
// Contravariant cases: loans flow in the inverse direction, but we're only interested
|
|
||||||
// in forward successors and there are none here.
|
|
||||||
None
|
|
||||||
}
|
|
||||||
ConstraintDirection::Forward | ConstraintDirection::Bidirectional => {
|
|
||||||
// 1. For covariant cases: loans flow in the regular direction, from the current point
|
|
||||||
// to the next point.
|
|
||||||
// 2. For invariant cases, loans can flow in both directions, but here as well, we only
|
|
||||||
// want the forward path of the bidirectional edge.
|
|
||||||
Some(LocalizedNode { region, point: next_point })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the successor for the current region/point node when propagating a loan through backward
|
|
||||||
/// edges, if applicable, according to liveness and variance.
|
|
||||||
fn compute_backward_successor(
|
|
||||||
region: RegionVid,
|
|
||||||
current_point: PointIndex,
|
|
||||||
previous_point: PointIndex,
|
|
||||||
live_regions: &SparseIntervalMatrix<RegionVid, PointIndex>,
|
|
||||||
live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
|
|
||||||
) -> Option<LocalizedNode> {
|
|
||||||
// Liveness flows into the regions live at the next point. So, in a backwards view, we'll link
|
|
||||||
// the region from the current point, if it's live there, to the previous point.
|
|
||||||
if !live_regions.contains(region, current_point) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: add the missing variance information and remove this fallback bidirectional edge. See
|
|
||||||
// the same comment in `compute_forward_successor`.
|
|
||||||
let direction =
|
|
||||||
live_region_variances.get(®ion).unwrap_or(&ConstraintDirection::Bidirectional);
|
|
||||||
|
|
||||||
match direction {
|
|
||||||
ConstraintDirection::Forward => {
|
|
||||||
// Covariant cases: loans flow in the regular direction, but we're only interested in
|
|
||||||
// backward successors and there are none here.
|
|
||||||
None
|
|
||||||
}
|
|
||||||
ConstraintDirection::Backward | ConstraintDirection::Bidirectional => {
|
|
||||||
// 1. For contravariant cases: loans flow in the inverse direction, from the current
|
|
||||||
// point to the previous point.
|
|
||||||
// 2. For invariant cases, loans can flow in both directions, but here as well, we only
|
|
||||||
// want the backward path of the bidirectional edge.
|
|
||||||
Some(LocalizedNode { region, point: previous_point })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ use rustc_session::config::MirIncludeSpans;
|
||||||
|
|
||||||
use crate::borrow_set::BorrowSet;
|
use crate::borrow_set::BorrowSet;
|
||||||
use crate::constraints::OutlivesConstraint;
|
use crate::constraints::OutlivesConstraint;
|
||||||
use crate::polonius::{LocalizedConstraintGraphVisitor, LocalizedNode, PoloniusContext};
|
use crate::polonius::{
|
||||||
|
LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet, PoloniusDiagnosticsContext,
|
||||||
|
};
|
||||||
use crate::region_infer::values::LivenessValues;
|
use crate::region_infer::values::LivenessValues;
|
||||||
use crate::type_check::Locations;
|
use crate::type_check::Locations;
|
||||||
use crate::{BorrowckInferCtxt, ClosureRegionRequirements, RegionInferenceContext};
|
use crate::{BorrowckInferCtxt, ClosureRegionRequirements, RegionInferenceContext};
|
||||||
|
|
@ -22,7 +24,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
||||||
regioncx: &RegionInferenceContext<'tcx>,
|
regioncx: &RegionInferenceContext<'tcx>,
|
||||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
polonius_context: Option<&PoloniusContext>,
|
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
|
||||||
) {
|
) {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
|
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||||
|
|
@ -31,22 +33,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
||||||
|
|
||||||
let Some(dumper) = MirDumper::new(tcx, "polonius", body) else { return };
|
let Some(dumper) = MirDumper::new(tcx, "polonius", body) else { return };
|
||||||
|
|
||||||
let polonius_context =
|
let polonius_diagnostics =
|
||||||
polonius_context.expect("missing polonius context with `-Zpolonius=next`");
|
polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`");
|
||||||
|
|
||||||
// If we have a polonius graph to dump along the rest of the MIR and NLL info, we extract its
|
|
||||||
// constraints here.
|
|
||||||
let mut collector = LocalizedOutlivesConstraintCollector { constraints: Vec::new() };
|
|
||||||
if let Some(graph) = &polonius_context.graph {
|
|
||||||
graph.traverse(
|
|
||||||
body,
|
|
||||||
regioncx.liveness_constraints(),
|
|
||||||
&polonius_context.live_region_variances,
|
|
||||||
regioncx.universal_regions(),
|
|
||||||
borrow_set,
|
|
||||||
&mut collector,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let extra_data = &|pass_where, out: &mut dyn io::Write| {
|
let extra_data = &|pass_where, out: &mut dyn io::Write| {
|
||||||
emit_polonius_mir(
|
emit_polonius_mir(
|
||||||
|
|
@ -54,7 +42,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
||||||
regioncx,
|
regioncx,
|
||||||
closure_region_requirements,
|
closure_region_requirements,
|
||||||
borrow_set,
|
borrow_set,
|
||||||
&collector.constraints,
|
&polonius_diagnostics.localized_outlives_constraints,
|
||||||
pass_where,
|
pass_where,
|
||||||
out,
|
out,
|
||||||
)
|
)
|
||||||
|
|
@ -70,36 +58,19 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
||||||
|
|
||||||
let dumper = dumper.set_extra_data(extra_data).set_options(options);
|
let dumper = dumper.set_extra_data(extra_data).set_options(options);
|
||||||
|
|
||||||
let _ = try {
|
let _: io::Result<()> = try {
|
||||||
let mut file = dumper.create_dump_file("html", body)?;
|
let mut file = dumper.create_dump_file("html", body)?;
|
||||||
emit_polonius_dump(&dumper, body, regioncx, borrow_set, &collector.constraints, &mut file)?;
|
emit_polonius_dump(
|
||||||
|
&dumper,
|
||||||
|
body,
|
||||||
|
regioncx,
|
||||||
|
borrow_set,
|
||||||
|
&polonius_diagnostics.localized_outlives_constraints,
|
||||||
|
&mut file,
|
||||||
|
)?;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The constraints we'll dump as text or a mermaid graph.
|
|
||||||
struct LocalizedOutlivesConstraint {
|
|
||||||
source: RegionVid,
|
|
||||||
from: PointIndex,
|
|
||||||
target: RegionVid,
|
|
||||||
to: PointIndex,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Visitor to record constraints encountered when traversing the localized constraint graph.
|
|
||||||
struct LocalizedOutlivesConstraintCollector {
|
|
||||||
constraints: Vec<LocalizedOutlivesConstraint>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LocalizedConstraintGraphVisitor for LocalizedOutlivesConstraintCollector {
|
|
||||||
fn on_successor_discovered(&mut self, current_node: LocalizedNode, successor: LocalizedNode) {
|
|
||||||
self.constraints.push(LocalizedOutlivesConstraint {
|
|
||||||
source: current_node.region,
|
|
||||||
from: current_node.point,
|
|
||||||
target: successor.region,
|
|
||||||
to: successor.point,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The polonius dump consists of:
|
/// The polonius dump consists of:
|
||||||
/// - the NLL MIR
|
/// - the NLL MIR
|
||||||
/// - the list of polonius localized constraints
|
/// - the list of polonius localized constraints
|
||||||
|
|
@ -111,7 +82,7 @@ fn emit_polonius_dump<'tcx>(
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
regioncx: &RegionInferenceContext<'tcx>,
|
regioncx: &RegionInferenceContext<'tcx>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||||
out: &mut dyn io::Write,
|
out: &mut dyn io::Write,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
// Prepare the HTML dump file prologue.
|
// Prepare the HTML dump file prologue.
|
||||||
|
|
@ -222,7 +193,7 @@ fn emit_polonius_mir<'tcx>(
|
||||||
regioncx: &RegionInferenceContext<'tcx>,
|
regioncx: &RegionInferenceContext<'tcx>,
|
||||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||||
pass_where: PassWhere,
|
pass_where: PassWhere,
|
||||||
out: &mut dyn io::Write,
|
out: &mut dyn io::Write,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
|
|
@ -241,10 +212,10 @@ fn emit_polonius_mir<'tcx>(
|
||||||
// Add localized outlives constraints
|
// Add localized outlives constraints
|
||||||
match pass_where {
|
match pass_where {
|
||||||
PassWhere::BeforeCFG => {
|
PassWhere::BeforeCFG => {
|
||||||
if localized_outlives_constraints.len() > 0 {
|
if localized_outlives_constraints.outlives.len() > 0 {
|
||||||
writeln!(out, "| Localized constraints")?;
|
writeln!(out, "| Localized constraints")?;
|
||||||
|
|
||||||
for constraint in localized_outlives_constraints {
|
for constraint in &localized_outlives_constraints.outlives {
|
||||||
let LocalizedOutlivesConstraint { source, from, target, to } = constraint;
|
let LocalizedOutlivesConstraint { source, from, target, to } = constraint;
|
||||||
let from = liveness.location_from_point(*from);
|
let from = liveness.location_from_point(*from);
|
||||||
let to = liveness.location_from_point(*to);
|
let to = liveness.location_from_point(*to);
|
||||||
|
|
@ -428,7 +399,7 @@ fn emit_mermaid_nll_sccs<'tcx>(
|
||||||
fn emit_mermaid_constraint_graph<'tcx>(
|
fn emit_mermaid_constraint_graph<'tcx>(
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
liveness: &LivenessValues,
|
liveness: &LivenessValues,
|
||||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||||
out: &mut dyn io::Write,
|
out: &mut dyn io::Write,
|
||||||
) -> io::Result<usize> {
|
) -> io::Result<usize> {
|
||||||
let location_name = |location: Location| {
|
let location_name = |location: Location| {
|
||||||
|
|
@ -467,7 +438,7 @@ fn emit_mermaid_constraint_graph<'tcx>(
|
||||||
// The regions subgraphs containing the region/point nodes.
|
// The regions subgraphs containing the region/point nodes.
|
||||||
let mut points_per_region: FxIndexMap<RegionVid, FxIndexSet<PointIndex>> =
|
let mut points_per_region: FxIndexMap<RegionVid, FxIndexSet<PointIndex>> =
|
||||||
FxIndexMap::default();
|
FxIndexMap::default();
|
||||||
for constraint in localized_outlives_constraints {
|
for constraint in &localized_outlives_constraints.outlives {
|
||||||
points_per_region.entry(constraint.source).or_default().insert(constraint.from);
|
points_per_region.entry(constraint.source).or_default().insert(constraint.from);
|
||||||
points_per_region.entry(constraint.target).or_default().insert(constraint.to);
|
points_per_region.entry(constraint.target).or_default().insert(constraint.to);
|
||||||
}
|
}
|
||||||
|
|
@ -480,7 +451,7 @@ fn emit_mermaid_constraint_graph<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// The constraint graph edges.
|
// The constraint graph edges.
|
||||||
for constraint in localized_outlives_constraints {
|
for constraint in &localized_outlives_constraints.outlives {
|
||||||
// FIXME: add killed loans and constraint kind as edge labels.
|
// FIXME: add killed loans and constraint kind as edge labels.
|
||||||
writeln!(
|
writeln!(
|
||||||
out,
|
out,
|
||||||
|
|
@ -492,6 +463,6 @@ fn emit_mermaid_constraint_graph<'tcx>(
|
||||||
|
|
||||||
// Return the number of edges: this is the biggest graph in the dump and its edge count will be
|
// Return the number of edges: this is the biggest graph in the dump and its edge count will be
|
||||||
// mermaid's max edge count to support.
|
// mermaid's max edge count to support.
|
||||||
let edge_count = borrow_set.len() + localized_outlives_constraints.len();
|
let edge_count = borrow_set.len() + localized_outlives_constraints.outlives.len();
|
||||||
Ok(edge_count)
|
Ok(edge_count)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
let wk = WriteKind::MutableBorrow(bk);
|
let wk = WriteKind::MutableBorrow(bk);
|
||||||
if bk.is_two_phase_borrow() {
|
if bk.allows_two_phase_borrow() {
|
||||||
(Deep, Reservation(wk))
|
(Deep, Reservation(wk))
|
||||||
} else {
|
} else {
|
||||||
(Deep, Write(wk))
|
(Deep, Write(wk))
|
||||||
|
|
@ -297,9 +297,8 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
||||||
Rvalue::Use(operand)
|
Rvalue::Use(operand)
|
||||||
| Rvalue::Repeat(operand, _)
|
| Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
||||||
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) => {
|
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
|
||||||
self.consume_operand(location, operand)
|
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand),
|
||||||
}
|
|
||||||
|
|
||||||
&Rvalue::Discriminant(place) => {
|
&Rvalue::Discriminant(place) => {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
|
|
@ -385,7 +384,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
||||||
// Reading from mere reservations of mutable-borrows is OK.
|
// Reading from mere reservations of mutable-borrows is OK.
|
||||||
if !is_active(this.dominators, borrow, location) {
|
if !is_active(this.dominators, borrow, location) {
|
||||||
// If the borrow isn't active yet, reads don't invalidate it
|
// If the borrow isn't active yet, reads don't invalidate it
|
||||||
assert!(borrow.kind.is_two_phase_borrow());
|
assert!(borrow.kind.allows_two_phase_borrow());
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,22 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_index::bit_set::SparseBitMatrix;
|
||||||
|
use rustc_middle::mir::{Body, Location};
|
||||||
use rustc_middle::ty::relate::{
|
use rustc_middle::ty::relate::{
|
||||||
self, Relate, RelateResult, TypeRelation, relate_args_with_variances,
|
self, Relate, RelateResult, TypeRelation, relate_args_with_variances,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
|
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
|
||||||
|
use rustc_mir_dataflow::points::PointIndex;
|
||||||
|
|
||||||
use super::{ConstraintDirection, PoloniusContext};
|
use super::{
|
||||||
|
ConstraintDirection, LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet,
|
||||||
|
PoloniusLivenessContext,
|
||||||
|
};
|
||||||
|
use crate::region_infer::values::LivenessValues;
|
||||||
use crate::universal_regions::UniversalRegions;
|
use crate::universal_regions::UniversalRegions;
|
||||||
|
|
||||||
impl PoloniusContext {
|
impl PoloniusLivenessContext {
|
||||||
/// Record the variance of each region contained within the given value.
|
/// Record the variance of each region contained within the given value.
|
||||||
pub(crate) fn record_live_region_variance<'tcx>(
|
pub(crate) fn record_live_region_variance<'tcx>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -27,6 +34,165 @@ impl PoloniusContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Propagate loans throughout the CFG: for each statement in the MIR, create localized outlives
|
||||||
|
/// constraints for loans that are propagated to the next statements.
|
||||||
|
pub(super) fn create_liveness_constraints<'tcx>(
|
||||||
|
body: &Body<'tcx>,
|
||||||
|
liveness: &LivenessValues,
|
||||||
|
live_regions: &SparseBitMatrix<PointIndex, RegionVid>,
|
||||||
|
live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
|
||||||
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
|
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
|
||||||
|
) {
|
||||||
|
for (block, bb) in body.basic_blocks.iter_enumerated() {
|
||||||
|
let statement_count = bb.statements.len();
|
||||||
|
for statement_index in 0..=statement_count {
|
||||||
|
let current_location = Location { block, statement_index };
|
||||||
|
let current_point = liveness.point_from_location(current_location);
|
||||||
|
|
||||||
|
if statement_index < statement_count {
|
||||||
|
// Intra-block edges, straight line constraints from each point to its successor
|
||||||
|
// within the same block.
|
||||||
|
let next_location = Location { block, statement_index: statement_index + 1 };
|
||||||
|
let next_point = liveness.point_from_location(next_location);
|
||||||
|
propagate_loans_between_points(
|
||||||
|
current_point,
|
||||||
|
next_point,
|
||||||
|
live_regions,
|
||||||
|
live_region_variances,
|
||||||
|
universal_regions,
|
||||||
|
localized_outlives_constraints,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Inter-block edges, from the block's terminator to each successor block's entry
|
||||||
|
// point.
|
||||||
|
for successor_block in bb.terminator().successors() {
|
||||||
|
let next_location = Location { block: successor_block, statement_index: 0 };
|
||||||
|
let next_point = liveness.point_from_location(next_location);
|
||||||
|
propagate_loans_between_points(
|
||||||
|
current_point,
|
||||||
|
next_point,
|
||||||
|
live_regions,
|
||||||
|
live_region_variances,
|
||||||
|
universal_regions,
|
||||||
|
localized_outlives_constraints,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Propagate loans within a region between two points in the CFG, if that region is live at both
|
||||||
|
/// the source and target points.
|
||||||
|
fn propagate_loans_between_points(
|
||||||
|
current_point: PointIndex,
|
||||||
|
next_point: PointIndex,
|
||||||
|
live_regions: &SparseBitMatrix<PointIndex, RegionVid>,
|
||||||
|
live_region_variances: &BTreeMap<RegionVid, ConstraintDirection>,
|
||||||
|
universal_regions: &UniversalRegions<'_>,
|
||||||
|
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
|
||||||
|
) {
|
||||||
|
// Universal regions are semantically live at all points.
|
||||||
|
// Note: we always have universal regions but they're not always (or often) involved in the
|
||||||
|
// subset graph. For now, we emit all their edges unconditionally, but some of these subgraphs
|
||||||
|
// will be disconnected from the rest of the graph and thus, unnecessary.
|
||||||
|
//
|
||||||
|
// FIXME: only emit the edges of universal regions that existential regions can reach.
|
||||||
|
for region in universal_regions.universal_regions_iter() {
|
||||||
|
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
|
||||||
|
source: region,
|
||||||
|
from: current_point,
|
||||||
|
target: region,
|
||||||
|
to: next_point,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(next_live_regions) = live_regions.row(next_point) else {
|
||||||
|
// There are no constraints to add: there are no live regions at the next point.
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
for region in next_live_regions.iter() {
|
||||||
|
// `region` could be live at the current point, and is live at the next point: add a
|
||||||
|
// constraint between them, according to variance.
|
||||||
|
if let Some(&direction) = live_region_variances.get(®ion) {
|
||||||
|
add_liveness_constraint(
|
||||||
|
region,
|
||||||
|
current_point,
|
||||||
|
next_point,
|
||||||
|
direction,
|
||||||
|
localized_outlives_constraints,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Note: there currently are cases related to promoted and const generics, where we
|
||||||
|
// don't yet have variance information (possibly about temporary regions created when
|
||||||
|
// typeck sanitizes the promoteds). Until that is done, we conservatively fallback to
|
||||||
|
// maximizing reachability by adding a bidirectional edge here. This will not limit
|
||||||
|
// traversal whatsoever, and thus propagate liveness when needed.
|
||||||
|
//
|
||||||
|
// FIXME: add the missing variance information and remove this fallback bidirectional
|
||||||
|
// edge.
|
||||||
|
let fallback = ConstraintDirection::Bidirectional;
|
||||||
|
add_liveness_constraint(
|
||||||
|
region,
|
||||||
|
current_point,
|
||||||
|
next_point,
|
||||||
|
fallback,
|
||||||
|
localized_outlives_constraints,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds `LocalizedOutlivesConstraint`s between two connected points, according to the given edge
|
||||||
|
/// direction.
|
||||||
|
fn add_liveness_constraint(
|
||||||
|
region: RegionVid,
|
||||||
|
current_point: PointIndex,
|
||||||
|
next_point: PointIndex,
|
||||||
|
direction: ConstraintDirection,
|
||||||
|
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
|
||||||
|
) {
|
||||||
|
match direction {
|
||||||
|
ConstraintDirection::Forward => {
|
||||||
|
// Covariant cases: loans flow in the regular direction, from the current point to the
|
||||||
|
// next point.
|
||||||
|
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
|
||||||
|
source: region,
|
||||||
|
from: current_point,
|
||||||
|
target: region,
|
||||||
|
to: next_point,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ConstraintDirection::Backward => {
|
||||||
|
// Contravariant cases: loans flow in the inverse direction, from the next point to the
|
||||||
|
// current point.
|
||||||
|
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
|
||||||
|
source: region,
|
||||||
|
from: next_point,
|
||||||
|
target: region,
|
||||||
|
to: current_point,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ConstraintDirection::Bidirectional => {
|
||||||
|
// For invariant cases, loans can flow in both directions: we add both edges.
|
||||||
|
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
|
||||||
|
source: region,
|
||||||
|
from: current_point,
|
||||||
|
target: region,
|
||||||
|
to: next_point,
|
||||||
|
});
|
||||||
|
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
|
||||||
|
source: region,
|
||||||
|
from: next_point,
|
||||||
|
target: region,
|
||||||
|
to: current_point,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Extracts variances for regions contained within types. Follows the same structure as
|
/// Extracts variances for regions contained within types. Follows the same structure as
|
||||||
/// `rustc_infer`'s `Generalizer`: we try to relate a type with itself to track and extract the
|
/// `rustc_infer`'s `Generalizer`: we try to relate a type with itself to track and extract the
|
||||||
/// variances of regions.
|
/// variances of regions.
|
||||||
|
|
|
||||||
160
compiler/rustc_borrowck/src/polonius/loan_liveness.rs
Normal file
160
compiler/rustc_borrowck/src/polonius/loan_liveness.rs
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||||
|
use rustc_middle::ty::RegionVid;
|
||||||
|
use rustc_mir_dataflow::points::PointIndex;
|
||||||
|
|
||||||
|
use super::{LiveLoans, LocalizedOutlivesConstraintSet};
|
||||||
|
use crate::BorrowSet;
|
||||||
|
use crate::constraints::OutlivesConstraint;
|
||||||
|
use crate::region_infer::values::LivenessValues;
|
||||||
|
use crate::type_check::Locations;
|
||||||
|
|
||||||
|
/// Compute loan reachability to approximately trace loan liveness throughout the CFG, by
|
||||||
|
/// traversing the full graph of constraints that combines:
|
||||||
|
/// - the localized constraints (the physical edges),
|
||||||
|
/// - with the constraints that hold at all points (the logical edges).
|
||||||
|
pub(super) fn compute_loan_liveness<'tcx>(
|
||||||
|
liveness: &LivenessValues,
|
||||||
|
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
||||||
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
|
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||||
|
) -> LiveLoans {
|
||||||
|
let mut live_loans = LiveLoans::new(borrow_set.len());
|
||||||
|
|
||||||
|
// Create the full graph with the physical edges we've localized earlier, and the logical edges
|
||||||
|
// of constraints that hold at all points.
|
||||||
|
let logical_constraints =
|
||||||
|
outlives_constraints.filter(|c| matches!(c.locations, Locations::All(_)));
|
||||||
|
let graph = LocalizedConstraintGraph::new(&localized_outlives_constraints, logical_constraints);
|
||||||
|
let mut visited = FxHashSet::default();
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
|
// Compute reachability per loan by traversing each loan's subgraph starting from where it is
|
||||||
|
// introduced.
|
||||||
|
for (loan_idx, loan) in borrow_set.iter_enumerated() {
|
||||||
|
visited.clear();
|
||||||
|
stack.clear();
|
||||||
|
|
||||||
|
let start_node = LocalizedNode {
|
||||||
|
region: loan.region,
|
||||||
|
point: liveness.point_from_location(loan.reserve_location),
|
||||||
|
};
|
||||||
|
stack.push(start_node);
|
||||||
|
|
||||||
|
while let Some(node) = stack.pop() {
|
||||||
|
if !visited.insert(node) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record the loan as being live on entry to this point if it reaches a live region
|
||||||
|
// there.
|
||||||
|
//
|
||||||
|
// This is an approximation of liveness (which is the thing we want), in that we're
|
||||||
|
// using a single notion of reachability to represent what used to be _two_ different
|
||||||
|
// transitive closures. It didn't seem impactful when coming up with the single-graph
|
||||||
|
// and reachability through space (regions) + time (CFG) concepts, but in practice the
|
||||||
|
// combination of time-traveling with kills is more impactful than initially
|
||||||
|
// anticipated.
|
||||||
|
//
|
||||||
|
// Kills should prevent a loan from reaching its successor points in the CFG, but not
|
||||||
|
// while time-traveling: we're not actually at that CFG point, but looking for
|
||||||
|
// predecessor regions that contain the loan. One of the two TCs we had pushed the
|
||||||
|
// transitive subset edges to each point instead of having backward edges, and the
|
||||||
|
// problem didn't exist before. In the abstract, naive reachability is not enough to
|
||||||
|
// model this, we'd need a slightly different solution. For example, maybe with a
|
||||||
|
// two-step traversal:
|
||||||
|
// - at each point we first traverse the subgraph (and possibly time-travel) looking for
|
||||||
|
// exit nodes while ignoring kills,
|
||||||
|
// - and then when we're back at the current point, we continue normally.
|
||||||
|
//
|
||||||
|
// Another (less annoying) subtlety is that kills and the loan use-map are
|
||||||
|
// flow-insensitive. Kills can actually appear in places before a loan is introduced, or
|
||||||
|
// at a location that is actually unreachable in the CFG from the introduction point,
|
||||||
|
// and these can also be encountered during time-traveling.
|
||||||
|
//
|
||||||
|
// The simplest change that made sense to "fix" the issues above is taking into
|
||||||
|
// account kills that are:
|
||||||
|
// - reachable from the introduction point
|
||||||
|
// - encountered during forward traversal. Note that this is not transitive like the
|
||||||
|
// two-step traversal described above: only kills encountered on exit via a backward
|
||||||
|
// edge are ignored.
|
||||||
|
//
|
||||||
|
// This version of the analysis, however, is enough in practice to pass the tests that
|
||||||
|
// we care about and NLLs reject, without regressions on crater, and is an actionable
|
||||||
|
// subset of the full analysis. It also naturally points to areas of improvement that we
|
||||||
|
// wish to explore later, namely handling kills appropriately during traversal, instead
|
||||||
|
// of continuing traversal to all the reachable nodes.
|
||||||
|
//
|
||||||
|
// FIXME: analyze potential unsoundness, possibly in concert with a borrowck
|
||||||
|
// implementation in a-mir-formality, fuzzing, or manually crafting counter-examples.
|
||||||
|
|
||||||
|
if liveness.is_live_at(node.region, liveness.location_from_point(node.point)) {
|
||||||
|
live_loans.insert(node.point, loan_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
for succ in graph.outgoing_edges(node) {
|
||||||
|
stack.push(succ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
live_loans
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The localized constraint graph indexes the physical and logical edges to compute a given node's
|
||||||
|
/// successors during traversal.
|
||||||
|
struct LocalizedConstraintGraph {
|
||||||
|
/// The actual, physical, edges we have recorded for a given node.
|
||||||
|
edges: FxHashMap<LocalizedNode, FxIndexSet<LocalizedNode>>,
|
||||||
|
|
||||||
|
/// The logical edges representing the outlives constraints that hold at all points in the CFG,
|
||||||
|
/// which we don't localize to avoid creating a lot of unnecessary edges in the graph. Some CFGs
|
||||||
|
/// can be big, and we don't need to create such a physical edge for every point in the CFG.
|
||||||
|
logical_edges: FxHashMap<RegionVid, FxIndexSet<RegionVid>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A node in the graph to be traversed, one of the two vertices of a localized outlives constraint.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
struct LocalizedNode {
|
||||||
|
region: RegionVid,
|
||||||
|
point: PointIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalizedConstraintGraph {
|
||||||
|
/// Traverses the constraints and returns the indexed graph of edges per node.
|
||||||
|
fn new<'tcx>(
|
||||||
|
constraints: &LocalizedOutlivesConstraintSet,
|
||||||
|
logical_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
||||||
|
) -> Self {
|
||||||
|
let mut edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
|
||||||
|
for constraint in &constraints.outlives {
|
||||||
|
let source = LocalizedNode { region: constraint.source, point: constraint.from };
|
||||||
|
let target = LocalizedNode { region: constraint.target, point: constraint.to };
|
||||||
|
edges.entry(source).or_default().insert(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut logical_edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
|
||||||
|
for constraint in logical_constraints {
|
||||||
|
logical_edges.entry(constraint.sup).or_default().insert(constraint.sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalizedConstraintGraph { edges, logical_edges }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the outgoing edges of a given node, not its transitive closure.
|
||||||
|
fn outgoing_edges(&self, node: LocalizedNode) -> impl Iterator<Item = LocalizedNode> {
|
||||||
|
// The outgoing edges are:
|
||||||
|
// - the physical edges present at this node,
|
||||||
|
// - the materialized logical edges that exist virtually at all points for this node's
|
||||||
|
// region, localized at this point.
|
||||||
|
let physical_edges =
|
||||||
|
self.edges.get(&node).into_iter().flat_map(|targets| targets.iter().copied());
|
||||||
|
let materialized_edges =
|
||||||
|
self.logical_edges.get(&node.region).into_iter().flat_map(move |targets| {
|
||||||
|
targets
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(move |target| LocalizedNode { point: node.point, region: target })
|
||||||
|
});
|
||||||
|
physical_edges.chain(materialized_edges)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,37 +32,47 @@
|
||||||
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/22/polonius-part-1/>
|
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/22/polonius-part-1/>
|
||||||
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/29/polonius-part-2/>
|
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/29/polonius-part-2/>
|
||||||
//!
|
//!
|
||||||
|
//!
|
||||||
|
//! Data flows like this:
|
||||||
|
//! 1) during MIR typeck, record liveness data needed later: live region variances, as well as the
|
||||||
|
//! usual NLL liveness data (just computed on more locals). That's the [PoloniusLivenessContext].
|
||||||
|
//! 2) once that is done, variance data is transferred, and the NLL region liveness is converted to
|
||||||
|
//! the polonius shape. That's the main [PoloniusContext].
|
||||||
|
//! 3) during region inference, that data and the NLL outlives constraints are used to create the
|
||||||
|
//! localized outlives constraints, as described above. That's the [PoloniusDiagnosticsContext].
|
||||||
|
//! 4) transfer this back to the main borrowck procedure: it handles computing errors and
|
||||||
|
//! diagnostics, debugging and MIR dumping concerns.
|
||||||
|
|
||||||
mod constraints;
|
mod constraints;
|
||||||
mod dump;
|
mod dump;
|
||||||
pub(crate) mod legacy;
|
pub(crate) mod legacy;
|
||||||
mod liveness_constraints;
|
mod liveness_constraints;
|
||||||
|
mod loan_liveness;
|
||||||
|
mod typeck_constraints;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_index::bit_set::SparseBitMatrix;
|
use rustc_index::bit_set::SparseBitMatrix;
|
||||||
|
use rustc_index::interval::SparseIntervalMatrix;
|
||||||
use rustc_middle::mir::{Body, Local};
|
use rustc_middle::mir::{Body, Local};
|
||||||
use rustc_middle::ty::RegionVid;
|
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||||
use rustc_mir_dataflow::points::PointIndex;
|
use rustc_mir_dataflow::points::PointIndex;
|
||||||
|
|
||||||
pub(self) use self::constraints::*;
|
pub(crate) use self::constraints::*;
|
||||||
pub(crate) use self::dump::dump_polonius_mir;
|
pub(crate) use self::dump::dump_polonius_mir;
|
||||||
|
use self::liveness_constraints::create_liveness_constraints;
|
||||||
|
use self::loan_liveness::compute_loan_liveness;
|
||||||
|
use self::typeck_constraints::convert_typeck_constraints;
|
||||||
use crate::dataflow::BorrowIndex;
|
use crate::dataflow::BorrowIndex;
|
||||||
use crate::region_infer::values::LivenessValues;
|
|
||||||
use crate::{BorrowSet, RegionInferenceContext};
|
use crate::{BorrowSet, RegionInferenceContext};
|
||||||
|
|
||||||
pub(crate) type LiveLoans = SparseBitMatrix<PointIndex, BorrowIndex>;
|
pub(crate) type LiveLoans = SparseBitMatrix<PointIndex, BorrowIndex>;
|
||||||
|
|
||||||
/// This struct holds the necessary
|
/// This struct holds the liveness data created during MIR typeck, and which will be used later in
|
||||||
/// - liveness data, created during MIR typeck, and which will be used to lazily compute the
|
/// the process, to compute the polonius localized constraints.
|
||||||
/// polonius localized constraints, during NLL region inference as well as MIR dumping,
|
|
||||||
/// - data needed by the borrowck error computation and diagnostics.
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct PoloniusContext {
|
pub(crate) struct PoloniusLivenessContext {
|
||||||
/// The graph from which we extract the localized outlives constraints.
|
|
||||||
graph: Option<LocalizedConstraintGraph>,
|
|
||||||
|
|
||||||
/// The expected edge direction per live region: the kind of directed edge we'll create as
|
/// The expected edge direction per live region: the kind of directed edge we'll create as
|
||||||
/// liveness constraints depends on the variance of types with respect to each contained region.
|
/// liveness constraints depends on the variance of types with respect to each contained region.
|
||||||
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
|
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
|
||||||
|
|
@ -74,6 +84,27 @@ pub(crate) struct PoloniusContext {
|
||||||
pub(crate) boring_nll_locals: FxHashSet<Local>,
|
pub(crate) boring_nll_locals: FxHashSet<Local>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This struct holds the data needed to create the Polonius localized constraints. Its data is
|
||||||
|
/// transferred and converted from the [PoloniusLivenessContext] at the end of MIR typeck.
|
||||||
|
pub(crate) struct PoloniusContext {
|
||||||
|
/// The liveness data we recorded during MIR typeck.
|
||||||
|
liveness_context: PoloniusLivenessContext,
|
||||||
|
|
||||||
|
/// The set of regions that are live at a given point in the CFG, used to create localized
|
||||||
|
/// outlives constraints between regions that are live at connected points in the CFG.
|
||||||
|
live_regions: SparseBitMatrix<PointIndex, RegionVid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This struct holds the data needed by the borrowck error computation and diagnostics. Its data is
|
||||||
|
/// computed from the [PoloniusContext] when computing NLL regions.
|
||||||
|
pub(crate) struct PoloniusDiagnosticsContext {
|
||||||
|
/// The localized outlives constraints that were computed in the main analysis.
|
||||||
|
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
|
||||||
|
|
||||||
|
/// The liveness data computed during MIR typeck: [PoloniusLivenessContext::boring_nll_locals].
|
||||||
|
pub(crate) boring_nll_locals: FxHashSet<Local>,
|
||||||
|
}
|
||||||
|
|
||||||
/// The direction a constraint can flow into. Used to create liveness constraints according to
|
/// The direction a constraint can flow into. Used to create liveness constraints according to
|
||||||
/// variance.
|
/// variance.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
|
@ -89,6 +120,26 @@ enum ConstraintDirection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PoloniusContext {
|
impl PoloniusContext {
|
||||||
|
/// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
|
||||||
|
/// need to transpose the "points where each region is live" matrix to a "live regions per point"
|
||||||
|
/// matrix.
|
||||||
|
// FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
|
||||||
|
// borrowck.
|
||||||
|
pub(crate) fn create_from_liveness(
|
||||||
|
liveness_context: PoloniusLivenessContext,
|
||||||
|
num_regions: usize,
|
||||||
|
points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
|
||||||
|
) -> PoloniusContext {
|
||||||
|
let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
|
||||||
|
for region in points_per_live_region.rows() {
|
||||||
|
for point in points_per_live_region.row(region).unwrap().iter() {
|
||||||
|
live_regions_per_point.insert(point, region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PoloniusContext { live_regions: live_regions_per_point, liveness_context }
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes live loans using the set of loans model for `-Zpolonius=next`.
|
/// Computes live loans using the set of loans model for `-Zpolonius=next`.
|
||||||
///
|
///
|
||||||
/// First, creates a constraint graph combining regions and CFG points, by:
|
/// First, creates a constraint graph combining regions and CFG points, by:
|
||||||
|
|
@ -100,90 +151,44 @@ impl PoloniusContext {
|
||||||
///
|
///
|
||||||
/// The constraint data will be used to compute errors and diagnostics.
|
/// The constraint data will be used to compute errors and diagnostics.
|
||||||
pub(crate) fn compute_loan_liveness<'tcx>(
|
pub(crate) fn compute_loan_liveness<'tcx>(
|
||||||
&mut self,
|
self,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
regioncx: &mut RegionInferenceContext<'tcx>,
|
regioncx: &mut RegionInferenceContext<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
) {
|
) -> PoloniusDiagnosticsContext {
|
||||||
let liveness = regioncx.liveness_constraints();
|
let PoloniusLivenessContext { live_region_variances, boring_nll_locals } =
|
||||||
|
self.liveness_context;
|
||||||
|
|
||||||
// We don't need to prepare the graph (index NLL constraints, etc.) if we have no loans to
|
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
|
||||||
// trace throughout localized constraints.
|
convert_typeck_constraints(
|
||||||
if borrow_set.len() > 0 {
|
tcx,
|
||||||
// From the outlives constraints, liveness, and variances, we can compute reachability
|
|
||||||
// on the lazy localized constraint graph to trace the liveness of loans, for the next
|
|
||||||
// step in the chain (the NLL loan scope and active loans computations).
|
|
||||||
let graph = LocalizedConstraintGraph::new(liveness, regioncx.outlives_constraints());
|
|
||||||
|
|
||||||
let mut live_loans = LiveLoans::new(borrow_set.len());
|
|
||||||
let mut visitor = LoanLivenessVisitor { liveness, live_loans: &mut live_loans };
|
|
||||||
graph.traverse(
|
|
||||||
body,
|
body,
|
||||||
liveness,
|
regioncx.liveness_constraints(),
|
||||||
&self.live_region_variances,
|
regioncx.outlives_constraints(),
|
||||||
regioncx.universal_regions(),
|
regioncx.universal_regions(),
|
||||||
|
&mut localized_outlives_constraints,
|
||||||
|
);
|
||||||
|
|
||||||
|
create_liveness_constraints(
|
||||||
|
body,
|
||||||
|
regioncx.liveness_constraints(),
|
||||||
|
&self.live_regions,
|
||||||
|
&live_region_variances,
|
||||||
|
regioncx.universal_regions(),
|
||||||
|
&mut localized_outlives_constraints,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now that we have a complete graph, we can compute reachability to trace the liveness of
|
||||||
|
// loans for the next step in the chain, the NLL loan scope and active loans computations.
|
||||||
|
let live_loans = compute_loan_liveness(
|
||||||
|
regioncx.liveness_constraints(),
|
||||||
|
regioncx.outlives_constraints(),
|
||||||
borrow_set,
|
borrow_set,
|
||||||
&mut visitor,
|
&localized_outlives_constraints,
|
||||||
);
|
);
|
||||||
regioncx.record_live_loans(live_loans);
|
regioncx.record_live_loans(live_loans);
|
||||||
|
|
||||||
// The graph can be traversed again during MIR dumping, so we store it here.
|
PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals }
|
||||||
self.graph = Some(graph);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Visitor to record loan liveness when traversing the localized constraint graph.
|
|
||||||
struct LoanLivenessVisitor<'a> {
|
|
||||||
liveness: &'a LivenessValues,
|
|
||||||
live_loans: &'a mut LiveLoans,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LocalizedConstraintGraphVisitor for LoanLivenessVisitor<'_> {
|
|
||||||
fn on_node_traversed(&mut self, loan: BorrowIndex, node: LocalizedNode) {
|
|
||||||
// Record the loan as being live on entry to this point if it reaches a live region
|
|
||||||
// there.
|
|
||||||
//
|
|
||||||
// This is an approximation of liveness (which is the thing we want), in that we're
|
|
||||||
// using a single notion of reachability to represent what used to be _two_ different
|
|
||||||
// transitive closures. It didn't seem impactful when coming up with the single-graph
|
|
||||||
// and reachability through space (regions) + time (CFG) concepts, but in practice the
|
|
||||||
// combination of time-traveling with kills is more impactful than initially
|
|
||||||
// anticipated.
|
|
||||||
//
|
|
||||||
// Kills should prevent a loan from reaching its successor points in the CFG, but not
|
|
||||||
// while time-traveling: we're not actually at that CFG point, but looking for
|
|
||||||
// predecessor regions that contain the loan. One of the two TCs we had pushed the
|
|
||||||
// transitive subset edges to each point instead of having backward edges, and the
|
|
||||||
// problem didn't exist before. In the abstract, naive reachability is not enough to
|
|
||||||
// model this, we'd need a slightly different solution. For example, maybe with a
|
|
||||||
// two-step traversal:
|
|
||||||
// - at each point we first traverse the subgraph (and possibly time-travel) looking for
|
|
||||||
// exit nodes while ignoring kills,
|
|
||||||
// - and then when we're back at the current point, we continue normally.
|
|
||||||
//
|
|
||||||
// Another (less annoying) subtlety is that kills and the loan use-map are
|
|
||||||
// flow-insensitive. Kills can actually appear in places before a loan is introduced, or
|
|
||||||
// at a location that is actually unreachable in the CFG from the introduction point,
|
|
||||||
// and these can also be encountered during time-traveling.
|
|
||||||
//
|
|
||||||
// The simplest change that made sense to "fix" the issues above is taking into account
|
|
||||||
// kills that are:
|
|
||||||
// - reachable from the introduction point
|
|
||||||
// - encountered during forward traversal. Note that this is not transitive like the
|
|
||||||
// two-step traversal described above: only kills encountered on exit via a backward
|
|
||||||
// edge are ignored.
|
|
||||||
//
|
|
||||||
// This version of the analysis, however, is enough in practice to pass the tests that
|
|
||||||
// we care about and NLLs reject, without regressions on crater, and is an actionable
|
|
||||||
// subset of the full analysis. It also naturally points to areas of improvement that we
|
|
||||||
// wish to explore later, namely handling kills appropriately during traversal, instead
|
|
||||||
// of continuing traversal to all the reachable nodes.
|
|
||||||
//
|
|
||||||
// FIXME: analyze potential unsoundness, possibly in concert with a borrowck
|
|
||||||
// implementation in a-mir-formality, fuzzing, or manually crafting counter-examples.
|
|
||||||
if self.liveness.is_live_at_point(node.region, node.point) {
|
|
||||||
self.live_loans.insert(node.point, loan);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
218
compiler/rustc_borrowck/src/polonius/typeck_constraints.rs
Normal file
218
compiler/rustc_borrowck/src/polonius/typeck_constraints.rs
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_middle::mir::{Body, Location, Statement, StatementKind, Terminator, TerminatorKind};
|
||||||
|
use rustc_middle::ty::{TyCtxt, TypeVisitable};
|
||||||
|
use rustc_mir_dataflow::points::PointIndex;
|
||||||
|
|
||||||
|
use super::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
|
||||||
|
use crate::constraints::OutlivesConstraint;
|
||||||
|
use crate::region_infer::values::LivenessValues;
|
||||||
|
use crate::type_check::Locations;
|
||||||
|
use crate::universal_regions::UniversalRegions;
|
||||||
|
|
||||||
|
/// Propagate loans throughout the subset graph at a given point (with some subtleties around the
|
||||||
|
/// location where effects start to be visible).
|
||||||
|
pub(super) fn convert_typeck_constraints<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
body: &Body<'tcx>,
|
||||||
|
liveness: &LivenessValues,
|
||||||
|
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
||||||
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
|
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
|
||||||
|
) {
|
||||||
|
for outlives_constraint in outlives_constraints {
|
||||||
|
match outlives_constraint.locations {
|
||||||
|
Locations::All(_) => {
|
||||||
|
// We don't turn constraints holding at all points into physical edges at every
|
||||||
|
// point in the graph. They are encoded into *traversal* instead: a given node's
|
||||||
|
// successors will combine these logical edges with the regular, physical, localized
|
||||||
|
// edges.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Locations::Single(location) => {
|
||||||
|
// This constraint is marked as holding at one location, we localize it to that
|
||||||
|
// location or its successor, depending on the corresponding MIR
|
||||||
|
// statement/terminator. Unfortunately, they all show up from typeck as coming "on
|
||||||
|
// entry", so for now we modify them to take effects that should apply "on exit"
|
||||||
|
// into account.
|
||||||
|
//
|
||||||
|
// FIXME: this approach is subtle, complicated, and hard to test, so we should track
|
||||||
|
// this information better in MIR typeck instead, for example with a new `Locations`
|
||||||
|
// variant that contains which node is crossing over between entry and exit.
|
||||||
|
let point = liveness.point_from_location(location);
|
||||||
|
let localized_constraint = if let Some(stmt) =
|
||||||
|
body[location.block].statements.get(location.statement_index)
|
||||||
|
{
|
||||||
|
localize_statement_constraint(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
stmt,
|
||||||
|
&outlives_constraint,
|
||||||
|
point,
|
||||||
|
universal_regions,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
assert_eq!(location.statement_index, body[location.block].statements.len());
|
||||||
|
let terminator = body[location.block].terminator();
|
||||||
|
localize_terminator_constraint(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
terminator,
|
||||||
|
liveness,
|
||||||
|
&outlives_constraint,
|
||||||
|
point,
|
||||||
|
universal_regions,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
localized_outlives_constraints.push(localized_constraint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For a given outlives constraint arising from a MIR statement, localize the constraint with the
|
||||||
|
/// 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,
|
||||||
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
|
) -> LocalizedOutlivesConstraint {
|
||||||
|
match &stmt.kind {
|
||||||
|
StatementKind::Assign(box (lhs, rhs)) => {
|
||||||
|
// To create localized outlives constraints without midpoints, we rely on the property
|
||||||
|
// that no input regions from the RHS of the assignment will flow into themselves: they
|
||||||
|
// should not appear in the output regions in the LHS. We believe this to be true by
|
||||||
|
// construction of the MIR, via temporaries, and assert it here.
|
||||||
|
//
|
||||||
|
// We think we don't need midpoints because:
|
||||||
|
// - every LHS Place has a unique set of regions that don't appear elsewhere
|
||||||
|
// - this implies that for them to be part of the RHS, the same Place must be read and
|
||||||
|
// written
|
||||||
|
// - and that should be impossible in MIR
|
||||||
|
//
|
||||||
|
// When we have a more complete implementation in the future, tested with crater, etc,
|
||||||
|
// we can remove this assertion. It's a debug assert because it can be expensive.
|
||||||
|
debug_assert!(
|
||||||
|
{
|
||||||
|
let mut lhs_regions = FxHashSet::default();
|
||||||
|
tcx.for_each_free_region(lhs, |region| {
|
||||||
|
let region = universal_regions.to_region_vid(region);
|
||||||
|
lhs_regions.insert(region);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut rhs_regions = FxHashSet::default();
|
||||||
|
tcx.for_each_free_region(rhs, |region| {
|
||||||
|
let region = universal_regions.to_region_vid(region);
|
||||||
|
rhs_regions.insert(region);
|
||||||
|
});
|
||||||
|
|
||||||
|
// The intersection between LHS and RHS regions should be empty.
|
||||||
|
lhs_regions.is_disjoint(&rhs_regions)
|
||||||
|
},
|
||||||
|
"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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the
|
||||||
|
/// needed CFG `from`-`to` inter-block nodes.
|
||||||
|
fn localize_terminator_constraint<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
body: &Body<'tcx>,
|
||||||
|
terminator: &Terminator<'tcx>,
|
||||||
|
liveness: &LivenessValues,
|
||||||
|
outlives_constraint: &OutlivesConstraint<'tcx>,
|
||||||
|
current_point: PointIndex,
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
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);
|
||||||
|
compute_constraint_direction(
|
||||||
|
tcx,
|
||||||
|
outlives_constraint,
|
||||||
|
&destination_ty,
|
||||||
|
current_point,
|
||||||
|
successor_point,
|
||||||
|
universal_regions,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Typeck constraints guide loans between regions at the current point, so we do that in
|
||||||
|
// the general case, and liveness will take care of making them flow to the terminator's
|
||||||
|
// successors.
|
||||||
|
LocalizedOutlivesConstraint {
|
||||||
|
source: outlives_constraint.sup,
|
||||||
|
from: current_point,
|
||||||
|
target: outlives_constraint.sub,
|
||||||
|
to: current_point,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For a given outlives constraint and CFG edge, returns the localized constraint with the
|
||||||
|
/// appropriate `from`-`to` direction. This is computed according to whether the constraint flows to
|
||||||
|
/// or from a free region in the given `value`, some kind of result for an effectful operation, like
|
||||||
|
/// the LHS of an assignment.
|
||||||
|
fn compute_constraint_direction<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
outlives_constraint: &OutlivesConstraint<'tcx>,
|
||||||
|
value: &impl TypeVisitable<TyCtxt<'tcx>>,
|
||||||
|
current_point: PointIndex,
|
||||||
|
successor_point: PointIndex,
|
||||||
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
|
) -> LocalizedOutlivesConstraint {
|
||||||
|
let mut to = current_point;
|
||||||
|
let mut from = current_point;
|
||||||
|
tcx.for_each_free_region(value, |region| {
|
||||||
|
let region = universal_regions.to_region_vid(region);
|
||||||
|
if region == outlives_constraint.sub {
|
||||||
|
// This constraint flows into the result, its effects start becoming visible on exit.
|
||||||
|
to = successor_point;
|
||||||
|
} else if region == outlives_constraint.sup {
|
||||||
|
// This constraint flows from the result, its effects start becoming visible on exit.
|
||||||
|
from = successor_point;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
LocalizedOutlivesConstraint {
|
||||||
|
source: outlives_constraint.sup,
|
||||||
|
from,
|
||||||
|
target: outlives_constraint.sub,
|
||||||
|
to,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ fn render_region_vid<'tcx>(
|
||||||
format!(" (for<{}>)", tcx.item_name(def_id))
|
format!(" (for<{}>)", tcx.item_name(def_id))
|
||||||
}
|
}
|
||||||
ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(),
|
ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(),
|
||||||
ty::BoundRegionKind::NamedForPrinting(_) => {
|
ty::BoundRegionKind::NamedAnon(_) => {
|
||||||
bug!("only used for pretty printing")
|
bug!("only used for pretty printing")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1379,11 +1379,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
.elements_contained_in(longer_fr_scc)
|
.elements_contained_in(longer_fr_scc)
|
||||||
.find(|e| *e != RegionElement::PlaceholderRegion(placeholder))
|
.find(|e| *e != RegionElement::PlaceholderRegion(placeholder))
|
||||||
{
|
{
|
||||||
let illegally_outlived_r = self.region_from_element(longer_fr, &error_element);
|
|
||||||
// Stop after the first error, it gets too noisy otherwise, and does not provide more information.
|
// Stop after the first error, it gets too noisy otherwise, and does not provide more information.
|
||||||
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesIllegalRegion {
|
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
|
||||||
longer_fr,
|
longer_fr,
|
||||||
illegally_outlived_r,
|
error_element,
|
||||||
|
placeholder,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
debug!("check_bound_universal_region: all bounds satisfied");
|
debug!("check_bound_universal_region: all bounds satisfied");
|
||||||
|
|
@ -1572,7 +1572,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the region outlived by `longer_fr` and live at `element`.
|
/// Get the region outlived by `longer_fr` and live at `element`.
|
||||||
fn region_from_element(
|
pub(crate) fn region_from_element(
|
||||||
&self,
|
&self,
|
||||||
longer_fr: RegionVid,
|
longer_fr: RegionVid,
|
||||||
element: &RegionElement<'tcx>,
|
element: &RegionElement<'tcx>,
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,13 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use super::reverse_sccs::ReverseSccGraph;
|
use super::reverse_sccs::ReverseSccGraph;
|
||||||
|
use crate::BorrowckInferCtxt;
|
||||||
use crate::consumers::RegionInferenceContext;
|
use crate::consumers::RegionInferenceContext;
|
||||||
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
|
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
|
||||||
use crate::type_check::canonical::fully_perform_op_raw;
|
use crate::type_check::canonical::fully_perform_op_raw;
|
||||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||||
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||||
use crate::universal_regions::{RegionClassification, UniversalRegions};
|
use crate::universal_regions::{RegionClassification, UniversalRegions};
|
||||||
use crate::{BorrowckInferCtxt, CollectRegionConstraintsResult};
|
|
||||||
|
|
||||||
mod member_constraints;
|
mod member_constraints;
|
||||||
mod region_ctxt;
|
mod region_ctxt;
|
||||||
|
|
@ -126,31 +126,6 @@ fn nll_var_to_universal_region<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Record info needed to report the same name error later.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub(crate) struct UnexpectedHiddenRegion<'tcx> {
|
|
||||||
// The def_id of the body where this error occurs.
|
|
||||||
// Needed to handle region vars with their corresponding `infcx`.
|
|
||||||
def_id: LocalDefId,
|
|
||||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
|
||||||
hidden_type: ProvisionalHiddenType<'tcx>,
|
|
||||||
member_region: Region<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> UnexpectedHiddenRegion<'tcx> {
|
|
||||||
pub(crate) fn to_error(self) -> (LocalDefId, DeferredOpaqueTypeError<'tcx>) {
|
|
||||||
let UnexpectedHiddenRegion { def_id, opaque_type_key, hidden_type, member_region } = self;
|
|
||||||
(
|
|
||||||
def_id,
|
|
||||||
DeferredOpaqueTypeError::UnexpectedHiddenRegion {
|
|
||||||
opaque_type_key,
|
|
||||||
hidden_type,
|
|
||||||
member_region,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Collect all defining uses of opaque types inside of this typeck root. This
|
/// Collect all defining uses of opaque types inside of this typeck root. This
|
||||||
/// expects the hidden type to be mapped to the definition parameters of the opaque
|
/// expects the hidden type to be mapped to the definition parameters of the opaque
|
||||||
/// and errors if we end up with distinct hidden types.
|
/// and errors if we end up with distinct hidden types.
|
||||||
|
|
@ -201,13 +176,11 @@ struct DefiningUse<'tcx> {
|
||||||
/// It also means that this whole function is not really soundness critical as we
|
/// It also means that this whole function is not really soundness critical as we
|
||||||
/// recheck all uses of the opaques regardless.
|
/// recheck all uses of the opaques regardless.
|
||||||
pub(crate) fn compute_definition_site_hidden_types<'tcx>(
|
pub(crate) fn compute_definition_site_hidden_types<'tcx>(
|
||||||
def_id: LocalDefId,
|
|
||||||
infcx: &BorrowckInferCtxt<'tcx>,
|
infcx: &BorrowckInferCtxt<'tcx>,
|
||||||
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
|
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
|
||||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||||
location_map: Rc<DenseLocationMap>,
|
location_map: Rc<DenseLocationMap>,
|
||||||
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
||||||
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
|
|
||||||
opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
|
opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
|
||||||
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
|
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
|
|
@ -231,10 +204,8 @@ pub(crate) fn compute_definition_site_hidden_types<'tcx>(
|
||||||
// up equal to one of their choice regions and compute the actual hidden type of
|
// up equal to one of their choice regions and compute the actual hidden type of
|
||||||
// the opaque type definition. This is stored in the `root_cx`.
|
// the opaque type definition. This is stored in the `root_cx`.
|
||||||
compute_definition_site_hidden_types_from_defining_uses(
|
compute_definition_site_hidden_types_from_defining_uses(
|
||||||
def_id,
|
|
||||||
&rcx,
|
&rcx,
|
||||||
hidden_types,
|
hidden_types,
|
||||||
unconstrained_hidden_type_errors,
|
|
||||||
&defining_uses,
|
&defining_uses,
|
||||||
&mut errors,
|
&mut errors,
|
||||||
);
|
);
|
||||||
|
|
@ -303,10 +274,8 @@ fn collect_defining_uses<'tcx>(
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(rcx, hidden_types, defining_uses, errors))]
|
#[instrument(level = "debug", skip(rcx, hidden_types, defining_uses, errors))]
|
||||||
fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
||||||
def_id: LocalDefId,
|
|
||||||
rcx: &RegionCtxt<'_, 'tcx>,
|
rcx: &RegionCtxt<'_, 'tcx>,
|
||||||
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
||||||
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
|
|
||||||
defining_uses: &[DefiningUse<'tcx>],
|
defining_uses: &[DefiningUse<'tcx>],
|
||||||
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
|
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -324,18 +293,6 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
||||||
Ok(hidden_type) => hidden_type,
|
Ok(hidden_type) => hidden_type,
|
||||||
Err(r) => {
|
Err(r) => {
|
||||||
debug!("UnexpectedHiddenRegion: {:?}", r);
|
debug!("UnexpectedHiddenRegion: {:?}", r);
|
||||||
// If we're using the next solver, the unconstrained region may be resolved by a
|
|
||||||
// fully defining use from another body.
|
|
||||||
// So we don't generate error eagerly here.
|
|
||||||
if rcx.infcx.tcx.use_typing_mode_borrowck() {
|
|
||||||
unconstrained_hidden_type_errors.push(UnexpectedHiddenRegion {
|
|
||||||
def_id,
|
|
||||||
hidden_type,
|
|
||||||
opaque_type_key,
|
|
||||||
member_region: ty::Region::new_var(tcx, r),
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
|
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
|
||||||
hidden_type,
|
hidden_type,
|
||||||
opaque_type_key,
|
opaque_type_key,
|
||||||
|
|
@ -347,7 +304,6 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
||||||
);
|
);
|
||||||
ty::ProvisionalHiddenType::new_error(tcx, guar)
|
ty::ProvisionalHiddenType::new_error(tcx, guar)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Now that we mapped the member regions to their final value,
|
// Now that we mapped the member regions to their final value,
|
||||||
|
|
@ -614,40 +570,6 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
|
||||||
errors
|
errors
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We handle `UnexpectedHiddenRegion` error lazily in the next solver as
|
|
||||||
/// there may be a fully defining use in another body.
|
|
||||||
///
|
|
||||||
/// In case such a defining use does not exist, we register an error here.
|
|
||||||
pub(crate) fn handle_unconstrained_hidden_type_errors<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
|
||||||
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
|
|
||||||
collect_region_constraints_results: &mut FxIndexMap<
|
|
||||||
LocalDefId,
|
|
||||||
CollectRegionConstraintsResult<'tcx>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
let mut unconstrained_hidden_type_errors = std::mem::take(unconstrained_hidden_type_errors);
|
|
||||||
unconstrained_hidden_type_errors
|
|
||||||
.retain(|unconstrained| !hidden_types.contains_key(&unconstrained.opaque_type_key.def_id));
|
|
||||||
|
|
||||||
unconstrained_hidden_type_errors.iter().for_each(|t| {
|
|
||||||
tcx.dcx()
|
|
||||||
.span_delayed_bug(t.hidden_type.span, "opaque type with non-universal region args");
|
|
||||||
});
|
|
||||||
|
|
||||||
// `UnexpectedHiddenRegion` error contains region var which only makes sense in the
|
|
||||||
// corresponding `infcx`.
|
|
||||||
// So we need to insert the error to the body where it originates from.
|
|
||||||
for error in unconstrained_hidden_type_errors {
|
|
||||||
let (def_id, error) = error.to_error();
|
|
||||||
let Some(result) = collect_region_constraints_results.get_mut(&def_id) else {
|
|
||||||
unreachable!("the body should depend on opaques type if it has opaque use");
|
|
||||||
};
|
|
||||||
result.deferred_opaque_type_errors.push(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types.
|
/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types.
|
||||||
/// We do not check these new uses so this could be unsound.
|
/// We do not check these new uses so this could be unsound.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ use rustc_middle::ty::{self, RegionVid};
|
||||||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::BorrowIndex;
|
|
||||||
use crate::polonius::LiveLoans;
|
use crate::polonius::LiveLoans;
|
||||||
|
use crate::{BorrowIndex, TyCtxt};
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
/// A single integer representing a `ty::Placeholder`.
|
/// A single integer representing a `ty::Placeholder`.
|
||||||
|
|
@ -131,17 +131,9 @@ impl LivenessValues {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether `region` is marked live at the given
|
/// Returns whether `region` is marked live at the given `location`.
|
||||||
/// [`location`][rustc_middle::mir::Location].
|
|
||||||
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
|
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
|
||||||
let point = self.location_map.point_from_location(location);
|
let point = self.location_map.point_from_location(location);
|
||||||
self.is_live_at_point(region, point)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether `region` is marked live at the given
|
|
||||||
/// [`point`][rustc_mir_dataflow::points::PointIndex].
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn is_live_at_point(&self, region: RegionVid, point: PointIndex) -> bool {
|
|
||||||
if let Some(points) = &self.points {
|
if let Some(points) = &self.points {
|
||||||
points.row(region).is_some_and(|r| r.contains(point))
|
points.row(region).is_some_and(|r| r.contains(point))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -428,18 +420,18 @@ impl ToElementIndex<'_> for RegionVid {
|
||||||
impl<'tcx> ToElementIndex<'tcx> for ty::PlaceholderRegion<'tcx> {
|
impl<'tcx> ToElementIndex<'tcx> for ty::PlaceholderRegion<'tcx> {
|
||||||
fn add_to_row<N: Idx>(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool
|
fn add_to_row<N: Idx>(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool
|
||||||
where
|
where
|
||||||
Self: Into<ty::PlaceholderRegion<'tcx>>,
|
Self: Into<ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
|
||||||
{
|
{
|
||||||
let placeholder: ty::PlaceholderRegion<'tcx> = self.into();
|
let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
|
||||||
let index = values.placeholder_indices.lookup_index(placeholder);
|
let index = values.placeholder_indices.lookup_index(placeholder);
|
||||||
values.placeholders.insert(row, index)
|
values.placeholders.insert(row, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contained_in_row<N: Idx>(self, values: &RegionValues<'tcx, N>, row: N) -> bool
|
fn contained_in_row<N: Idx>(self, values: &RegionValues<'tcx, N>, row: N) -> bool
|
||||||
where
|
where
|
||||||
Self: Into<ty::PlaceholderRegion<'tcx>>,
|
Self: Into<ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
|
||||||
{
|
{
|
||||||
let placeholder: ty::PlaceholderRegion<'tcx> = self.into();
|
let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
|
||||||
let index = values.placeholder_indices.lookup_index(placeholder);
|
let index = values.placeholder_indices.lookup_index(placeholder);
|
||||||
values.placeholders.contains(row, index)
|
values.placeholders.contains(row, index)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,8 @@ use smallvec::SmallVec;
|
||||||
use crate::consumers::BorrowckConsumer;
|
use crate::consumers::BorrowckConsumer;
|
||||||
use crate::nll::compute_closure_requirements_modulo_opaques;
|
use crate::nll::compute_closure_requirements_modulo_opaques;
|
||||||
use crate::region_infer::opaque_types::{
|
use crate::region_infer::opaque_types::{
|
||||||
UnexpectedHiddenRegion, apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
|
apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
|
||||||
compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
|
compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
|
||||||
handle_unconstrained_hidden_type_errors,
|
|
||||||
};
|
};
|
||||||
use crate::type_check::{Locations, constraint_conversion};
|
use crate::type_check::{Locations, constraint_conversion};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -27,12 +26,7 @@ use crate::{
|
||||||
pub(super) struct BorrowCheckRootCtxt<'tcx> {
|
pub(super) struct BorrowCheckRootCtxt<'tcx> {
|
||||||
pub tcx: TyCtxt<'tcx>,
|
pub tcx: TyCtxt<'tcx>,
|
||||||
root_def_id: LocalDefId,
|
root_def_id: LocalDefId,
|
||||||
/// This contains fully resolved hidden types or `ty::Error`.
|
|
||||||
hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
||||||
/// This contains unconstrained regions in hidden types.
|
|
||||||
/// Only used for deferred error reporting. See
|
|
||||||
/// [`crate::region_infer::opaque_types::handle_unconstrained_hidden_type_errors`]
|
|
||||||
unconstrained_hidden_type_errors: Vec<UnexpectedHiddenRegion<'tcx>>,
|
|
||||||
/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
|
/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
|
||||||
/// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
|
/// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
|
||||||
/// their parents.
|
/// their parents.
|
||||||
|
|
@ -55,7 +49,6 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
||||||
tcx,
|
tcx,
|
||||||
root_def_id,
|
root_def_id,
|
||||||
hidden_types: Default::default(),
|
hidden_types: Default::default(),
|
||||||
unconstrained_hidden_type_errors: Default::default(),
|
|
||||||
collect_region_constraints_results: Default::default(),
|
collect_region_constraints_results: Default::default(),
|
||||||
propagated_borrowck_results: Default::default(),
|
propagated_borrowck_results: Default::default(),
|
||||||
tainted_by_errors: None,
|
tainted_by_errors: None,
|
||||||
|
|
@ -91,32 +84,23 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
||||||
|
|
||||||
fn handle_opaque_type_uses(&mut self) {
|
fn handle_opaque_type_uses(&mut self) {
|
||||||
let mut per_body_info = Vec::new();
|
let mut per_body_info = Vec::new();
|
||||||
for (def_id, input) in &mut self.collect_region_constraints_results {
|
for input in self.collect_region_constraints_results.values_mut() {
|
||||||
let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
|
let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
|
||||||
&input.infcx,
|
&input.infcx,
|
||||||
&input.universal_region_relations,
|
&input.universal_region_relations,
|
||||||
&mut input.constraints,
|
&mut input.constraints,
|
||||||
);
|
);
|
||||||
input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
|
input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
|
||||||
*def_id,
|
|
||||||
&input.infcx,
|
&input.infcx,
|
||||||
&input.universal_region_relations,
|
&input.universal_region_relations,
|
||||||
&input.constraints,
|
&input.constraints,
|
||||||
Rc::clone(&input.location_map),
|
Rc::clone(&input.location_map),
|
||||||
&mut self.hidden_types,
|
&mut self.hidden_types,
|
||||||
&mut self.unconstrained_hidden_type_errors,
|
|
||||||
&opaque_types,
|
&opaque_types,
|
||||||
);
|
);
|
||||||
per_body_info.push((num_entries, opaque_types));
|
per_body_info.push((num_entries, opaque_types));
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_unconstrained_hidden_type_errors(
|
|
||||||
self.tcx,
|
|
||||||
&mut self.hidden_types,
|
|
||||||
&mut self.unconstrained_hidden_type_errors,
|
|
||||||
&mut self.collect_region_constraints_results,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (input, (opaque_types_storage_num_entries, opaque_types)) in
|
for (input, (opaque_types_storage_num_entries, opaque_types)) in
|
||||||
self.collect_region_constraints_results.values_mut().zip(per_body_info)
|
self.collect_region_constraints_results.values_mut().zip(per_body_info)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,16 @@ use rustc_span::Span;
|
||||||
use crate::diagnostics::RegionName;
|
use crate::diagnostics::RegionName;
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("cannot move a value of type `{$ty}`", code = E0161)]
|
#[diag(borrowck_move_unsized, code = E0161)]
|
||||||
pub(crate) struct MoveUnsized<'tcx> {
|
pub(crate) struct MoveUnsized<'tcx> {
|
||||||
pub ty: Ty<'tcx>,
|
pub ty: Ty<'tcx>,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("the size of `{$ty}` cannot be statically determined")]
|
#[label]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("higher-ranked lifetime error")]
|
#[diag(borrowck_higher_ranked_lifetime_error)]
|
||||||
pub(crate) struct HigherRankedLifetimeError {
|
pub(crate) struct HigherRankedLifetimeError {
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub cause: Option<HigherRankedErrorCause>,
|
pub cause: Option<HigherRankedErrorCause>,
|
||||||
|
|
@ -26,21 +26,21 @@ pub(crate) struct HigherRankedLifetimeError {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum HigherRankedErrorCause {
|
pub(crate) enum HigherRankedErrorCause {
|
||||||
#[note("could not prove `{$predicate}`")]
|
#[note(borrowck_could_not_prove)]
|
||||||
CouldNotProve { predicate: String },
|
CouldNotProve { predicate: String },
|
||||||
#[note("could not normalize `{$value}`")]
|
#[note(borrowck_could_not_normalize)]
|
||||||
CouldNotNormalize { value: String },
|
CouldNotNormalize { value: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("higher-ranked subtype error")]
|
#[diag(borrowck_higher_ranked_subtype_error)]
|
||||||
pub(crate) struct HigherRankedSubtypeError {
|
pub(crate) struct HigherRankedSubtypeError {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("`{$kind}` does not live long enough")]
|
#[diag(borrowck_generic_does_not_live_long_enough)]
|
||||||
pub(crate) struct GenericDoesNotLiveLongEnough {
|
pub(crate) struct GenericDoesNotLiveLongEnough {
|
||||||
pub kind: String,
|
pub kind: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
|
|
@ -48,20 +48,15 @@ pub(crate) struct GenericDoesNotLiveLongEnough {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag("variable does not need to be mutable")]
|
#[diag(borrowck_var_does_not_need_mut)]
|
||||||
pub(crate) struct VarNeedNotMut {
|
pub(crate) struct VarNeedNotMut {
|
||||||
#[suggestion(
|
#[suggestion(style = "short", applicability = "machine-applicable", code = "")]
|
||||||
"remove this `mut`",
|
|
||||||
style = "short",
|
|
||||||
applicability = "machine-applicable",
|
|
||||||
code = ""
|
|
||||||
)]
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("captured variable cannot escape `FnMut` closure body")]
|
#[diag(borrowck_var_cannot_escape_closure)]
|
||||||
#[note("`FnMut` closures only have access to their captured variables while they are executing...")]
|
#[note]
|
||||||
#[note("...therefore, they cannot allow references to captured variables to escape")]
|
#[note(borrowck_cannot_escape)]
|
||||||
pub(crate) struct FnMutError {
|
pub(crate) struct FnMutError {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -71,17 +66,17 @@ pub(crate) struct FnMutError {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum VarHereDenote {
|
pub(crate) enum VarHereDenote {
|
||||||
#[label("variable captured here")]
|
#[label(borrowck_var_here_captured)]
|
||||||
Captured {
|
Captured {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[label("variable defined here")]
|
#[label(borrowck_var_here_defined)]
|
||||||
Defined {
|
Defined {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[label("inferred to be a `FnMut` closure")]
|
#[label(borrowck_closure_inferred_mut)]
|
||||||
FnMutInferred {
|
FnMutInferred {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -90,21 +85,17 @@ pub(crate) enum VarHereDenote {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum FnMutReturnTypeErr {
|
pub(crate) enum FnMutReturnTypeErr {
|
||||||
#[label(
|
#[label(borrowck_returned_closure_escaped)]
|
||||||
"returns a closure that contains a reference to a captured variable, which then escapes the closure body"
|
|
||||||
)]
|
|
||||||
ReturnClosure {
|
ReturnClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_returned_async_block_escaped)]
|
||||||
"returns an `async` block that contains a reference to a captured variable, which then escapes the closure body"
|
|
||||||
)]
|
|
||||||
ReturnAsyncBlock {
|
ReturnAsyncBlock {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[label("returns a reference to a captured variable which escapes the closure body")]
|
#[label(borrowck_returned_ref_escaped)]
|
||||||
ReturnRef {
|
ReturnRef {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -112,7 +103,7 @@ pub(crate) enum FnMutReturnTypeErr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("lifetime may not live long enough")]
|
#[diag(borrowck_lifetime_constraints_error)]
|
||||||
pub(crate) struct LifetimeOutliveErr {
|
pub(crate) struct LifetimeOutliveErr {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -120,9 +111,7 @@ pub(crate) struct LifetimeOutliveErr {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
||||||
#[label(
|
#[label(borrowck_returned_lifetime_wrong)]
|
||||||
"{$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`"
|
|
||||||
)]
|
|
||||||
WrongReturn {
|
WrongReturn {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -130,9 +119,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
||||||
outlived_fr_name: RegionName,
|
outlived_fr_name: RegionName,
|
||||||
fr_name: &'a RegionName,
|
fr_name: &'a RegionName,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_returned_lifetime_short)]
|
||||||
"{$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`"
|
|
||||||
)]
|
|
||||||
ShortReturn {
|
ShortReturn {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
@ -144,7 +131,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum RequireStaticErr {
|
pub(crate) enum RequireStaticErr {
|
||||||
#[note("the used `impl` has a `'static` requirement")]
|
#[note(borrowck_used_impl_require_static)]
|
||||||
UsedImpl {
|
UsedImpl {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
multi_span: MultiSpan,
|
multi_span: MultiSpan,
|
||||||
|
|
@ -153,42 +140,42 @@ pub(crate) enum RequireStaticErr {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum CaptureVarPathUseCause {
|
pub(crate) enum CaptureVarPathUseCause {
|
||||||
#[label("borrow occurs due to use in coroutine")]
|
#[label(borrowck_borrow_due_to_use_coroutine)]
|
||||||
BorrowInCoroutine {
|
BorrowInCoroutine {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
},
|
},
|
||||||
#[label("use occurs due to use in coroutine")]
|
#[label(borrowck_use_due_to_use_coroutine)]
|
||||||
UseInCoroutine {
|
UseInCoroutine {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
},
|
},
|
||||||
#[label("assign occurs due to use in coroutine")]
|
#[label(borrowck_assign_due_to_use_coroutine)]
|
||||||
AssignInCoroutine {
|
AssignInCoroutine {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
},
|
},
|
||||||
#[label("assign to part occurs due to use in coroutine")]
|
#[label(borrowck_assign_part_due_to_use_coroutine)]
|
||||||
AssignPartInCoroutine {
|
AssignPartInCoroutine {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
},
|
},
|
||||||
#[label("borrow occurs due to use in closure")]
|
#[label(borrowck_borrow_due_to_use_closure)]
|
||||||
BorrowInClosure {
|
BorrowInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
},
|
},
|
||||||
#[label("use occurs due to use in closure")]
|
#[label(borrowck_use_due_to_use_closure)]
|
||||||
UseInClosure {
|
UseInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
},
|
},
|
||||||
#[label("assignment occurs due to use in closure")]
|
#[label(borrowck_assign_due_to_use_closure)]
|
||||||
AssignInClosure {
|
AssignInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
},
|
},
|
||||||
#[label("assignment to part occurs due to use in closure")]
|
#[label(borrowck_assign_part_due_to_use_closure)]
|
||||||
AssignPartInClosure {
|
AssignPartInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
|
|
@ -197,17 +184,17 @@ pub(crate) enum CaptureVarPathUseCause {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum CaptureVarKind {
|
pub(crate) enum CaptureVarKind {
|
||||||
#[label("capture is immutable because of use here")]
|
#[label(borrowck_capture_immute)]
|
||||||
Immut {
|
Immut {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
kind_span: Span,
|
kind_span: Span,
|
||||||
},
|
},
|
||||||
#[label("capture is mutable because of use here")]
|
#[label(borrowck_capture_mut)]
|
||||||
Mut {
|
Mut {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
kind_span: Span,
|
kind_span: Span,
|
||||||
},
|
},
|
||||||
#[label("capture is moved because of use here")]
|
#[label(borrowck_capture_move)]
|
||||||
Move {
|
Move {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
kind_span: Span,
|
kind_span: Span,
|
||||||
|
|
@ -216,97 +203,77 @@ pub(crate) enum CaptureVarKind {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum CaptureVarCause {
|
pub(crate) enum CaptureVarCause {
|
||||||
#[label(
|
#[label(borrowck_var_borrow_by_use_place_in_coroutine)]
|
||||||
"{$is_single_var ->
|
|
||||||
*[true] borrow occurs
|
|
||||||
[false] borrows occur
|
|
||||||
} due to use of {$place} in coroutine"
|
|
||||||
)]
|
|
||||||
BorrowUsePlaceCoroutine {
|
BorrowUsePlaceCoroutine {
|
||||||
is_single_var: bool,
|
is_single_var: bool,
|
||||||
place: String,
|
place: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_var_borrow_by_use_place_in_closure)]
|
||||||
"{$is_single_var ->
|
|
||||||
*[true] borrow occurs
|
|
||||||
[false] borrows occur
|
|
||||||
} due to use of {$place} in closure"
|
|
||||||
)]
|
|
||||||
BorrowUsePlaceClosure {
|
BorrowUsePlaceClosure {
|
||||||
is_single_var: bool,
|
is_single_var: bool,
|
||||||
place: String,
|
place: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("borrow occurs due to use in coroutine")]
|
#[label(borrowck_var_borrow_by_use_in_coroutine)]
|
||||||
BorrowUseInCoroutine {
|
BorrowUseInCoroutine {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("borrow occurs due to use in closure")]
|
#[label(borrowck_var_borrow_by_use_in_closure)]
|
||||||
BorrowUseInClosure {
|
BorrowUseInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("move occurs due to use in coroutine")]
|
#[label(borrowck_var_move_by_use_in_coroutine)]
|
||||||
MoveUseInCoroutine {
|
MoveUseInCoroutine {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("move occurs due to use in closure")]
|
#[label(borrowck_var_move_by_use_in_closure)]
|
||||||
MoveUseInClosure {
|
MoveUseInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("first borrow occurs due to use of {$place} in coroutine")]
|
#[label(borrowck_var_first_borrow_by_use_place_in_coroutine)]
|
||||||
FirstBorrowUsePlaceCoroutine {
|
FirstBorrowUsePlaceCoroutine {
|
||||||
place: String,
|
place: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("first borrow occurs due to use of {$place} in closure")]
|
#[label(borrowck_var_first_borrow_by_use_place_in_closure)]
|
||||||
FirstBorrowUsePlaceClosure {
|
FirstBorrowUsePlaceClosure {
|
||||||
place: String,
|
place: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("second borrow occurs due to use of {$place} in coroutine")]
|
#[label(borrowck_var_second_borrow_by_use_place_in_coroutine)]
|
||||||
SecondBorrowUsePlaceCoroutine {
|
SecondBorrowUsePlaceCoroutine {
|
||||||
place: String,
|
place: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("second borrow occurs due to use of {$place} in closure")]
|
#[label(borrowck_var_second_borrow_by_use_place_in_closure)]
|
||||||
SecondBorrowUsePlaceClosure {
|
SecondBorrowUsePlaceClosure {
|
||||||
place: String,
|
place: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label("mutable borrow occurs due to use of {$place} in closure")]
|
#[label(borrowck_var_mutable_borrow_by_use_place_in_closure)]
|
||||||
MutableBorrowUsePlaceClosure {
|
MutableBorrowUsePlaceClosure {
|
||||||
place: String,
|
place: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_partial_var_move_by_use_in_coroutine)]
|
||||||
"variable {$is_partial ->
|
|
||||||
[true] partially moved
|
|
||||||
*[false] moved
|
|
||||||
} due to use in coroutine"
|
|
||||||
)]
|
|
||||||
PartialMoveUseInCoroutine {
|
PartialMoveUseInCoroutine {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
is_partial: bool,
|
is_partial: bool,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_partial_var_move_by_use_in_closure)]
|
||||||
"variable {$is_partial ->
|
|
||||||
[true] partially moved
|
|
||||||
*[false] moved
|
|
||||||
} due to use in closure"
|
|
||||||
)]
|
|
||||||
PartialMoveUseInClosure {
|
PartialMoveUseInClosure {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
|
|
@ -315,57 +282,34 @@ pub(crate) enum CaptureVarCause {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("cannot move out of {$place ->
|
#[diag(borrowck_cannot_move_when_borrowed, code = E0505)]
|
||||||
[value] value
|
|
||||||
*[other] {$place}
|
|
||||||
} because it is borrowed", code = E0505)]
|
|
||||||
pub(crate) struct MoveBorrow<'a> {
|
pub(crate) struct MoveBorrow<'a> {
|
||||||
pub place: &'a str,
|
pub place: &'a str,
|
||||||
pub borrow_place: &'a str,
|
pub borrow_place: &'a str,
|
||||||
pub value_place: &'a str,
|
pub value_place: &'a str,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label(
|
#[label(borrowck_move_label)]
|
||||||
"move out of {$value_place ->
|
|
||||||
[value] value
|
|
||||||
*[other] {$value_place}
|
|
||||||
} occurs here"
|
|
||||||
)]
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[label(
|
#[label]
|
||||||
"borrow of {$borrow_place ->
|
|
||||||
[value] value
|
|
||||||
*[other] {$borrow_place}
|
|
||||||
} occurs here"
|
|
||||||
)]
|
|
||||||
pub borrow_span: Span,
|
pub borrow_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("opaque type used twice with different lifetimes")]
|
#[diag(borrowck_opaque_type_lifetime_mismatch)]
|
||||||
pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> {
|
pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> {
|
||||||
pub arg: GenericArg<'tcx>,
|
pub arg: GenericArg<'tcx>,
|
||||||
pub prev: GenericArg<'tcx>,
|
pub prev: GenericArg<'tcx>,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label("lifetime `{$arg}` used here")]
|
#[label]
|
||||||
#[note(
|
#[note]
|
||||||
"if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types"
|
|
||||||
)]
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[label("lifetime `{$prev}` previously used here")]
|
#[label(borrowck_prev_lifetime_label)]
|
||||||
pub prev_span: Span,
|
pub prev_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum CaptureReasonLabel<'a> {
|
pub(crate) enum CaptureReasonLabel<'a> {
|
||||||
#[label(
|
#[label(borrowck_moved_due_to_call)]
|
||||||
"{$place_name} {$is_partial ->
|
|
||||||
[true] partially moved
|
|
||||||
*[false] moved
|
|
||||||
} due to this {$is_loop_message ->
|
|
||||||
[true] call, in previous iteration of loop
|
|
||||||
*[false] call
|
|
||||||
}"
|
|
||||||
)]
|
|
||||||
Call {
|
Call {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
fn_call_span: Span,
|
fn_call_span: Span,
|
||||||
|
|
@ -373,15 +317,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
||||||
is_partial: bool,
|
is_partial: bool,
|
||||||
is_loop_message: bool,
|
is_loop_message: bool,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_moved_due_to_usage_in_operator)]
|
||||||
"{$place_name} {$is_partial ->
|
|
||||||
[true] partially moved
|
|
||||||
*[false] moved
|
|
||||||
} due to usage in {$is_loop_message ->
|
|
||||||
[true] operator, in previous iteration of loop
|
|
||||||
*[false] operator
|
|
||||||
}"
|
|
||||||
)]
|
|
||||||
OperatorUse {
|
OperatorUse {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
fn_call_span: Span,
|
fn_call_span: Span,
|
||||||
|
|
@ -389,15 +325,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
||||||
is_partial: bool,
|
is_partial: bool,
|
||||||
is_loop_message: bool,
|
is_loop_message: bool,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_moved_due_to_implicit_into_iter_call)]
|
||||||
"{$place_name} {$is_partial ->
|
|
||||||
[true] partially moved
|
|
||||||
*[false] moved
|
|
||||||
} due to this implicit call to {$is_loop_message ->
|
|
||||||
[true] `.into_iter()`, in previous iteration of loop
|
|
||||||
*[false] `.into_iter()`
|
|
||||||
}"
|
|
||||||
)]
|
|
||||||
ImplicitCall {
|
ImplicitCall {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
fn_call_span: Span,
|
fn_call_span: Span,
|
||||||
|
|
@ -405,15 +333,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
||||||
is_partial: bool,
|
is_partial: bool,
|
||||||
is_loop_message: bool,
|
is_loop_message: bool,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_moved_due_to_method_call)]
|
||||||
"{$place_name} {$is_partial ->
|
|
||||||
[true] partially moved
|
|
||||||
*[false] moved
|
|
||||||
} due to this method {$is_loop_message ->
|
|
||||||
[true] call, in previous iteration of loop
|
|
||||||
*[false] call
|
|
||||||
}"
|
|
||||||
)]
|
|
||||||
MethodCall {
|
MethodCall {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
fn_call_span: Span,
|
fn_call_span: Span,
|
||||||
|
|
@ -421,15 +341,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
||||||
is_partial: bool,
|
is_partial: bool,
|
||||||
is_loop_message: bool,
|
is_loop_message: bool,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_moved_due_to_await)]
|
||||||
"{$place_name} {$is_partial ->
|
|
||||||
[true] partially moved
|
|
||||||
*[false] moved
|
|
||||||
} due to this {$is_loop_message ->
|
|
||||||
[true] await, in previous iteration of loop
|
|
||||||
*[false] await
|
|
||||||
}"
|
|
||||||
)]
|
|
||||||
Await {
|
Await {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
fn_call_span: Span,
|
fn_call_span: Span,
|
||||||
|
|
@ -437,18 +349,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
||||||
is_partial: bool,
|
is_partial: bool,
|
||||||
is_loop_message: bool,
|
is_loop_message: bool,
|
||||||
},
|
},
|
||||||
#[label(
|
#[label(borrowck_value_moved_here)]
|
||||||
"value {$is_partial ->
|
|
||||||
[true] partially moved
|
|
||||||
*[false] moved
|
|
||||||
} {$is_move_msg ->
|
|
||||||
[true] into closure here
|
|
||||||
*[false] here
|
|
||||||
}{$is_loop_message ->
|
|
||||||
[true] , in previous iteration of loop
|
|
||||||
*[false] {\"\"}
|
|
||||||
}"
|
|
||||||
)]
|
|
||||||
MovedHere {
|
MovedHere {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
move_span: Span,
|
move_span: Span,
|
||||||
|
|
@ -456,7 +357,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
||||||
is_move_msg: bool,
|
is_move_msg: bool,
|
||||||
is_loop_message: bool,
|
is_loop_message: bool,
|
||||||
},
|
},
|
||||||
#[label("help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents")]
|
#[label(borrowck_consider_borrow_type_contents)]
|
||||||
BorrowContent {
|
BorrowContent {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
|
|
@ -465,22 +366,22 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum CaptureReasonNote {
|
pub(crate) enum CaptureReasonNote {
|
||||||
#[note("this value implements `FnOnce`, which causes it to be moved when called")]
|
#[note(borrowck_moved_a_fn_once_in_call)]
|
||||||
FnOnceMoveInCall {
|
FnOnceMoveInCall {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
},
|
},
|
||||||
#[note("calling this operator moves the value")]
|
#[note(borrowck_calling_operator_moves)]
|
||||||
UnOpMoveByOperator {
|
UnOpMoveByOperator {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[note("calling this operator moves the left-hand side")]
|
#[note(borrowck_calling_operator_moves_lhs)]
|
||||||
LhsMoveByOperator {
|
LhsMoveByOperator {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[note("`{$func}` takes ownership of the receiver `self`, which moves {$place_name}")]
|
#[note(borrowck_func_take_self_moved_place)]
|
||||||
FuncTakeSelf {
|
FuncTakeSelf {
|
||||||
func: String,
|
func: String,
|
||||||
place_name: String,
|
place_name: String,
|
||||||
|
|
@ -492,7 +393,7 @@ pub(crate) enum CaptureReasonNote {
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum CaptureReasonSuggest<'tcx> {
|
pub(crate) enum CaptureReasonSuggest<'tcx> {
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
"consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop",
|
borrowck_suggest_iterate_over_slice,
|
||||||
applicability = "maybe-incorrect",
|
applicability = "maybe-incorrect",
|
||||||
code = "&",
|
code = "&",
|
||||||
style = "verbose"
|
style = "verbose"
|
||||||
|
|
@ -503,7 +404,7 @@ pub(crate) enum CaptureReasonSuggest<'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
"consider reborrowing the `Pin` instead of moving it",
|
borrowck_suggest_create_fresh_reborrow,
|
||||||
applicability = "maybe-incorrect",
|
applicability = "maybe-incorrect",
|
||||||
code = ".as_mut()",
|
code = ".as_mut()",
|
||||||
style = "verbose"
|
style = "verbose"
|
||||||
|
|
@ -516,18 +417,13 @@ pub(crate) enum CaptureReasonSuggest<'tcx> {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum CaptureArgLabel {
|
pub(crate) enum CaptureArgLabel {
|
||||||
#[label(
|
#[label(borrowck_value_capture_here)]
|
||||||
"value captured {$is_within ->
|
|
||||||
[true] here by coroutine
|
|
||||||
*[false] here
|
|
||||||
}"
|
|
||||||
)]
|
|
||||||
Capture {
|
Capture {
|
||||||
is_within: bool,
|
is_within: bool,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
args_span: Span,
|
args_span: Span,
|
||||||
},
|
},
|
||||||
#[label("{$place} is moved here")]
|
#[label(borrowck_move_out_place_here)]
|
||||||
MoveOutPlace {
|
MoveOutPlace {
|
||||||
place: String,
|
place: String,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
|
|
@ -537,17 +433,13 @@ pub(crate) enum CaptureArgLabel {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum OnClosureNote<'a> {
|
pub(crate) enum OnClosureNote<'a> {
|
||||||
#[note(
|
#[note(borrowck_closure_invoked_twice)]
|
||||||
"closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment"
|
|
||||||
)]
|
|
||||||
InvokedTwice {
|
InvokedTwice {
|
||||||
place_name: &'a str,
|
place_name: &'a str,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[note(
|
#[note(borrowck_closure_moved_twice)]
|
||||||
"closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment"
|
|
||||||
)]
|
|
||||||
MovedTwice {
|
MovedTwice {
|
||||||
place_name: &'a str,
|
place_name: &'a str,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
|
|
@ -557,12 +449,7 @@ pub(crate) enum OnClosureNote<'a> {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
||||||
#[label(
|
#[label(borrowck_ty_no_impl_copy)]
|
||||||
"{$is_partial_move ->
|
|
||||||
[true] partial move
|
|
||||||
*[false] move
|
|
||||||
} occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait"
|
|
||||||
)]
|
|
||||||
Label {
|
Label {
|
||||||
is_partial_move: bool,
|
is_partial_move: bool,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
|
@ -570,24 +457,12 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[note(
|
#[note(borrowck_ty_no_impl_copy)]
|
||||||
"{$is_partial_move ->
|
|
||||||
[true] partial move
|
|
||||||
*[false] move
|
|
||||||
} occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait"
|
|
||||||
)]
|
|
||||||
Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
|
Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(
|
#[diag(borrowck_simd_intrinsic_arg_const)]
|
||||||
"{$arg ->
|
|
||||||
[1] 1st
|
|
||||||
[2] 2nd
|
|
||||||
[3] 3rd
|
|
||||||
*[other] {$arg}th
|
|
||||||
} argument of `{$intrinsic}` is required to be a `const` item"
|
|
||||||
)]
|
|
||||||
pub(crate) struct SimdIntrinsicArgConst {
|
pub(crate) struct SimdIntrinsicArgConst {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -596,8 +471,8 @@ pub(crate) struct SimdIntrinsicArgConst {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag("relative drop order changing in Rust 2024")]
|
#[diag(borrowck_tail_expr_drop_order)]
|
||||||
pub(crate) struct TailExprDropOrder {
|
pub(crate) struct TailExprDropOrder {
|
||||||
#[label("this temporary value will be dropped at the end of the block")]
|
#[label]
|
||||||
pub borrowed: Span,
|
pub borrowed: Span,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -343,15 +343,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a hack. `body.local_decls` are not necessarily normalized in the old
|
// FIXME: Ideally MIR types are normalized, but this is not always true.
|
||||||
// solver due to not deeply normalizing in writeback. So we must re-normalize here.
|
let mir_ty = self.normalize(mir_ty, Locations::All(span));
|
||||||
//
|
|
||||||
// I am not sure of a test case where this actually matters. There is a similar
|
|
||||||
// hack in `equate_inputs_and_outputs` which does have associated test cases.
|
|
||||||
let mir_ty = match self.infcx.next_trait_solver() {
|
|
||||||
true => mir_ty,
|
|
||||||
false => self.normalize(mir_ty, Locations::All(span)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let cause = ObligationCause::dummy_with_span(span);
|
let cause = ObligationCause::dummy_with_span(span);
|
||||||
let param_env = self.infcx.param_env;
|
let param_env = self.infcx.param_env;
|
||||||
|
|
@ -360,10 +353,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
ConstraintCategory::Boring,
|
ConstraintCategory::Boring,
|
||||||
type_op::custom::CustomTypeOp::new(
|
type_op::custom::CustomTypeOp::new(
|
||||||
|ocx| {
|
|ocx| {
|
||||||
// The `AscribeUserType` query would normally emit a wf
|
|
||||||
// obligation for the unnormalized user_ty here. This is
|
|
||||||
// where the "incorrectly skips the WF checks we normally do"
|
|
||||||
// happens
|
|
||||||
let user_ty = ocx.normalize(&cause, param_env, user_ty);
|
let user_ty = ocx.normalize(&cause, param_env, user_ty);
|
||||||
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
|
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
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