Compare commits
33 commits
main
...
automation
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
953d410e5e | ||
|
|
6de57ea1ec | ||
|
|
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 79066 additions and 110792 deletions
1
.github/ISSUE_TEMPLATE/ice.md
vendored
1
.github/ISSUE_TEMPLATE/ice.md
vendored
|
|
@ -2,7 +2,6 @@
|
|||
name: Internal Compiler Error
|
||||
about: Create a report for an internal compiler error in rustc.
|
||||
labels: C-bug, I-ICE, T-compiler
|
||||
title: "[ICE]: "
|
||||
---
|
||||
<!--
|
||||
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
||||
|
|
|
|||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
|
@ -165,6 +165,9 @@ jobs:
|
|||
- name: install sccache
|
||||
run: src/ci/scripts/install-sccache.sh
|
||||
|
||||
- name: select Xcode
|
||||
run: src/ci/scripts/select-xcode.sh
|
||||
|
||||
- name: install clang
|
||||
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 default $TOOLCHAIN
|
||||
|
||||
- name: cargo update
|
||||
run: ./src/tools/update-lockfile.sh
|
||||
|
||||
- name: cargo update compiler & tools
|
||||
# Remove first line that always just says "Updating crates.io index"
|
||||
run: |
|
||||
echo -e "\ncompiler & tools dependencies:" >> cargo_update.log
|
||||
cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||
- name: cargo update library
|
||||
run: |
|
||||
echo -e "\nlibrary dependencies:" >> cargo_update.log
|
||||
cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||
- name: cargo update rustbook
|
||||
run: |
|
||||
echo -e "\nrustbook dependencies:" >> cargo_update.log
|
||||
cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
|
||||
- name: upload Cargo.lock artifact for use in PR
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
|
|||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -25,7 +25,7 @@
|
|||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
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
|
||||
[submodule "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
|
||||
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
|
||||
|
||||
|
|
|
|||
254
Cargo.lock
254
Cargo.lock
|
|
@ -184,9 +184,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
|||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.15.4"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08e1676b346cadfec169374f949d7490fd80a24193d37d2afce0c047cf695e57"
|
||||
checksum = "bb7125972258312e79827b60c9eb93938334100245081cf701a2dee981b17427"
|
||||
dependencies = [
|
||||
"askama_macros",
|
||||
"itoa",
|
||||
|
|
@ -197,9 +197,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.15.4"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7661ff56517787343f376f75db037426facd7c8d3049cef8911f1e75016f3a37"
|
||||
checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
|
|
@ -214,18 +214,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "askama_macros"
|
||||
version = "0.15.4"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "713ee4dbfd1eb719c2dab859465b01fa1d21cb566684614a713a6b7a99a4e47b"
|
||||
checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.15.4"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d62d674238a526418b30c0def480d5beadb9d8964e7f38d635b03bf639c704c"
|
||||
checksum = "f3c63392767bb2df6aa65a6e1e3b80fd89bb7af6d58359b924c0695620f1512e"
|
||||
dependencies = [
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
|
|
@ -580,9 +580,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.54"
|
||||
version = "4.5.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
|
||||
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -600,9 +600,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.54"
|
||||
version = "4.5.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
|
||||
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -630,7 +630,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.95"
|
||||
version = "0.1.94"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama",
|
||||
|
|
@ -657,7 +657,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.95"
|
||||
version = "0.1.94"
|
||||
dependencies = [
|
||||
"clippy_utils",
|
||||
"itertools",
|
||||
|
|
@ -681,7 +681,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.95"
|
||||
version = "0.1.94"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.18.1",
|
||||
|
|
@ -713,7 +713,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.95"
|
||||
version = "0.1.94"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"itertools",
|
||||
|
|
@ -857,7 +857,7 @@ dependencies = [
|
|||
"tracing-subscriber",
|
||||
"unified-diff",
|
||||
"walkdir",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1117,7 +1117,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.95"
|
||||
version = "0.1.94"
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
|
|
@ -1298,9 +1298,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ena"
|
||||
version = "0.14.4"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1"
|
||||
checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
|
@ -1670,12 +1670,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"foldhash 0.2.0",
|
||||
]
|
||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
|
@ -1953,12 +1950,12 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.13.0"
|
||||
version = "2.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.16.1",
|
||||
"hashbrown 0.16.0",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
|
@ -2038,7 +2035,7 @@ dependencies = [
|
|||
"serde",
|
||||
"tempfile",
|
||||
"uuid",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2652,9 +2649,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
|
@ -2667,9 +2664,9 @@ checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
|||
|
||||
[[package]]
|
||||
name = "objc2-io-kit"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
|
||||
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
|
|
@ -3337,7 +3334,6 @@ dependencies = [
|
|||
"rustdoc-json-types",
|
||||
"serde_json",
|
||||
"similar",
|
||||
"tempfile",
|
||||
"wasmparser 0.236.1",
|
||||
]
|
||||
|
||||
|
|
@ -3356,9 +3352,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.27"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
|
|
@ -3490,6 +3486,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -3514,6 +3511,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_macros",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -3539,9 +3537,9 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
|
|
@ -3572,6 +3570,7 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_graphviz",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
|
|
@ -3599,6 +3598,7 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
|
|
@ -3632,6 +3632,7 @@ dependencies = [
|
|||
"rustc_codegen_ssa",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -3640,6 +3641,7 @@ dependencies = [
|
|||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_sanitizers",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -3668,6 +3670,7 @@ dependencies = [
|
|||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -3677,6 +3680,7 @@ dependencies = [
|
|||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -3686,10 +3690,11 @@ dependencies = [
|
|||
"serde_json",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"thin-vec",
|
||||
"thorin-dwp",
|
||||
"tracing",
|
||||
"wasm-encoder 0.219.2",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3702,6 +3707,7 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -3724,7 +3730,7 @@ dependencies = [
|
|||
"either",
|
||||
"elsa",
|
||||
"ena",
|
||||
"hashbrown 0.16.1",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"jobserver",
|
||||
"libc",
|
||||
|
|
@ -3746,7 +3752,7 @@ dependencies = [
|
|||
"tempfile",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3761,41 +3767,56 @@ dependencies = [
|
|||
name = "rustc_driver_impl"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"ctrlc",
|
||||
"jiff",
|
||||
"libc",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_lowering",
|
||||
"rustc_ast_passes",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_borrowck",
|
||||
"rustc_builtin_macros",
|
||||
"rustc_codegen_ssa",
|
||||
"rustc_const_eval",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir_analysis",
|
||||
"rustc_hir_pretty",
|
||||
"rustc_hir_typeck",
|
||||
"rustc_incremental",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_interface",
|
||||
"rustc_lexer",
|
||||
"rustc_lint",
|
||||
"rustc_log",
|
||||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_mir_build",
|
||||
"rustc_mir_dataflow",
|
||||
"rustc_mir_transform",
|
||||
"rustc_monomorphize",
|
||||
"rustc_parse",
|
||||
"rustc_passes",
|
||||
"rustc_pattern_analysis",
|
||||
"rustc_privacy",
|
||||
"rustc_public",
|
||||
"rustc_query_system",
|
||||
"rustc_resolve",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"rustc_ty_utils",
|
||||
"serde_json",
|
||||
"shlex",
|
||||
"tracing",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3835,8 +3856,10 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_error_messages",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hashes",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
|
|
@ -3845,7 +3868,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"termize",
|
||||
"tracing",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3859,6 +3882,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
|
|
@ -3886,6 +3910,19 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rustc_fs_util"
|
||||
version = "0.0.0"
|
||||
|
|
@ -3940,6 +3977,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -3986,6 +4024,7 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_hir_analysis",
|
||||
"rustc_hir_pretty",
|
||||
|
|
@ -4007,8 +4046,10 @@ name = "rustc_incremental"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand 0.9.2",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_graphviz",
|
||||
"rustc_hashes",
|
||||
|
|
@ -4018,6 +4059,7 @@ dependencies = [
|
|||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -4046,6 +4088,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -4076,6 +4119,7 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hir",
|
||||
"rustc_hir_analysis",
|
||||
|
|
@ -4092,6 +4136,7 @@ dependencies = [
|
|||
"rustc_passes",
|
||||
"rustc_privacy",
|
||||
"rustc_query_impl",
|
||||
"rustc_query_system",
|
||||
"rustc_resolve",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -4120,13 +4165,13 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"rustc_abi",
|
||||
"rustc_apfloat",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -4178,8 +4223,6 @@ dependencies = [
|
|||
name = "rustc_macros"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
|
|
@ -4201,6 +4244,7 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
|
|
@ -4224,7 +4268,6 @@ dependencies = [
|
|||
"bitflags",
|
||||
"either",
|
||||
"gsgdt",
|
||||
"parking_lot",
|
||||
"polonius-engine",
|
||||
"rustc_abi",
|
||||
"rustc_apfloat",
|
||||
|
|
@ -4235,6 +4278,7 @@ dependencies = [
|
|||
"rustc_error_messages",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_graphviz",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -4242,6 +4286,7 @@ dependencies = [
|
|||
"rustc_index",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -4264,6 +4309,7 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -4284,10 +4330,11 @@ dependencies = [
|
|||
"polonius-engine",
|
||||
"regex",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_graphviz",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
|
|
@ -4301,6 +4348,7 @@ name = "rustc_mir_transform"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"hashbrown 0.15.5",
|
||||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
|
|
@ -4308,6 +4356,7 @@ dependencies = [
|
|||
"rustc_const_eval",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -4329,6 +4378,7 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -4365,6 +4415,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
|
|
@ -4397,6 +4448,7 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -4419,6 +4471,7 @@ dependencies = [
|
|||
"rustc_arena",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -4438,6 +4491,7 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
|
|
@ -4490,18 +4544,38 @@ name = "rustc_query_impl"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"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_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_thread_pool",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -4520,11 +4594,13 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"smallvec",
|
||||
|
|
@ -4572,6 +4648,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -4582,7 +4659,7 @@ dependencies = [
|
|||
"rustc_target",
|
||||
"termize",
|
||||
"tracing",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4678,6 +4755,7 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_infer",
|
||||
"rustc_macros",
|
||||
|
|
@ -4726,6 +4804,7 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
|
|
@ -5354,14 +5433,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.38.2"
|
||||
version = "0.37.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efc19935b4b66baa6f654ac7924c192f55b175c00a7ab72410fc24284dacda8"
|
||||
checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-kit",
|
||||
"windows 0.62.2",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5538,7 +5617,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"build_helper",
|
||||
"cargo_metadata 0.21.0",
|
||||
"clap",
|
||||
"fluent-syntax",
|
||||
"globset",
|
||||
"ignore",
|
||||
"miropt-test-tools",
|
||||
|
|
@ -6314,34 +6393,22 @@ version = "0.61.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
||||
dependencies = [
|
||||
"windows-collections 0.2.0",
|
||||
"windows-collections",
|
||||
"windows-core 0.61.2",
|
||||
"windows-future 0.2.1",
|
||||
"windows-future",
|
||||
"windows-link 0.1.3",
|
||||
"windows-numerics 0.2.0",
|
||||
]
|
||||
|
||||
[[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",
|
||||
"windows-numerics",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.66.0"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81b7ec123a4eadd44d1f44f76804316b477b2537abed9a2ab950b3c54afa1fcf"
|
||||
checksum = "9b4e97b01190d32f268a2dfbd3f006f77840633746707fbe40bcee588108a231"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"windows-threading 0.2.1",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6353,15 +6420,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "windows-core"
|
||||
version = "0.61.2"
|
||||
|
|
@ -6396,18 +6454,7 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
|||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-link 0.1.3",
|
||||
"windows-threading 0.1.0",
|
||||
]
|
||||
|
||||
[[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",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6454,16 +6501,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
|
|
@ -6569,15 +6606,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ itself back on after some time).
|
|||
|
||||
### 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 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)
|
||||
==========================
|
||||
|
||||
|
|
@ -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
|
||||
- [Use equality instead of subtyping when resolving type dependent paths.](https://github.com/rust-lang/rust/pull/129073)
|
||||
- Linking on macOS now correctly includes Rust's default deployment target. Due to a linker bug, you might have to pass `MACOSX_DEPLOYMENT_TARGET` or fix your `#[link]` attributes to point to the correct frameworks. See <https://github.com/rust-lang/rust/pull/129369>.
|
||||
- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it 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.
|
||||
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.
|
||||
|
|
@ -1731,7 +1611,7 @@ Cargo
|
|||
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.
|
||||
- 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.
|
||||
- [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
|
||||
|
|
@ -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
|
||||
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)
|
||||
===========================
|
||||
|
|
@ -4519,7 +4399,7 @@ Compatibility Notes
|
|||
saturating to `0` instead][89926]. In the real world the panic happened mostly
|
||||
on platforms with buggy monotonic clock implementations rather than catching
|
||||
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
|
||||
the Linux kernel to version 3.2, and for glibc to version 2.17. We'd love
|
||||
your feedback in [PR #95026][95026].
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ path = [
|
|||
]
|
||||
precedence = "override"
|
||||
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]]
|
||||
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
|
||||
#![expect(unused_crate_dependencies)]
|
||||
|
||||
use std::process::ExitCode;
|
||||
|
||||
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
||||
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
||||
// mechanism. However, for complicated reasons (see
|
||||
|
|
@ -40,6 +38,6 @@ use std::process::ExitCode;
|
|||
#[cfg(feature = "jemalloc")]
|
||||
use tikv_jemalloc_sys as _;
|
||||
|
||||
fn main() -> ExitCode {
|
||||
fn main() {
|
||||
rustc_driver::main()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ impl Reg {
|
|||
|
||||
reg_ctor!(f32, Float, 32);
|
||||
reg_ctor!(f64, Float, 64);
|
||||
reg_ctor!(f128, Float, 128);
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ pub enum CanonAbi {
|
|||
C,
|
||||
Rust,
|
||||
RustCold,
|
||||
RustPreserveNone,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define.
|
||||
Custom,
|
||||
|
|
@ -55,7 +54,7 @@ pub enum CanonAbi {
|
|||
impl CanonAbi {
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
match self {
|
||||
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
|
||||
CanonAbi::Rust | CanonAbi::RustCold => true,
|
||||
CanonAbi::C
|
||||
| CanonAbi::Custom
|
||||
| CanonAbi::Arm(_)
|
||||
|
|
@ -75,7 +74,6 @@ impl fmt::Display for CanonAbi {
|
|||
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||
CanonAbi::Rust => ExternAbi::Rust,
|
||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
|
||||
CanonAbi::Custom => ExternAbi::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||
|
|
|
|||
|
|
@ -42,13 +42,6 @@ pub enum ExternAbi {
|
|||
/// in a platform-agnostic way.
|
||||
RustInvalid,
|
||||
|
||||
/// Preserves no registers.
|
||||
///
|
||||
/// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
|
||||
/// and may fall-back to a more conservative calling convention if the backend does not support
|
||||
/// forcing callers to save all registers.
|
||||
RustPreserveNone,
|
||||
|
||||
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
|
||||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
|
@ -170,7 +163,6 @@ abi_impls! {
|
|||
RustCall =><= "rust-call",
|
||||
RustCold =><= "rust-cold",
|
||||
RustInvalid =><= "rust-invalid",
|
||||
RustPreserveNone =><= "rust-preserve-none",
|
||||
Stdcall { unwind: false } =><= "stdcall",
|
||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||
System { unwind: false } =><= "system",
|
||||
|
|
@ -251,7 +243,7 @@ impl ExternAbi {
|
|||
/// - are subject to change between compiler versions
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
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*
|
||||
|
|
@ -323,8 +315,7 @@ impl ExternAbi {
|
|||
| Self::Thiscall { .. }
|
||||
| Self::Vectorcall { .. }
|
||||
| Self::SysV64 { .. }
|
||||
| Self::Win64 { .. }
|
||||
| Self::RustPreserveNone => true,
|
||||
| Self::Win64 { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
use std::str::FromStr;
|
||||
|
||||
use rustc_data_structures::assert_matches;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
|
|
|
|||
|
|
@ -290,19 +290,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
/// function call isn't allowed (a.k.a. `va_list`).
|
||||
///
|
||||
/// This function handles transparent types automatically.
|
||||
pub fn pass_indirectly_in_non_rustic_abis<C>(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
|
||||
pub fn pass_indirectly_in_non_rustic_abis<C>(mut self, cx: &C) -> bool
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
|
|
@ -312,7 +300,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
self = field;
|
||||
}
|
||||
|
||||
self
|
||||
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
|
||||
}
|
||||
|
||||
/// Finds the one field that is not a 1-ZST.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![cfg_attr(all(feature = "nightly", bootstrap, test), feature(assert_matches))]
|
||||
#![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(step_trait))]
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#![cfg_attr(test, feature(test))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![doc(test(no_crate_inject, attr(deny(warnings), allow(internal_features))))]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(never_type)]
|
||||
|
|
@ -25,7 +26,7 @@ use std::cell::{Cell, RefCell};
|
|||
use std::marker::PhantomData;
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::{cmp, hint, slice};
|
||||
use std::{cmp, intrinsics, slice};
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
@ -171,22 +172,8 @@ impl<T> TypedArena<T> {
|
|||
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]
|
||||
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!(len != 0);
|
||||
|
||||
|
|
@ -221,7 +208,7 @@ impl<T> TypedArena<T> {
|
|||
&self,
|
||||
iter: impl IntoIterator<Item = Result<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
|
||||
// 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.
|
||||
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.
|
||||
let start_ptr = self.alloc_raw_slice(len);
|
||||
Ok(unsafe {
|
||||
let start_ptr = self.alloc_raw_slice(len);
|
||||
// Initialize the newly-allocated storage without panicking.
|
||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
// Prevent the stale values in the vec from being dropped.
|
||||
vec.set_len(0);
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
})
|
||||
|
|
@ -451,7 +432,7 @@ impl DroplessArena {
|
|||
let bytes = align_up(layout.size(), 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) {
|
||||
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
|
||||
/// reference to it. Will panic if passed an empty string.
|
||||
///
|
||||
|
|
@ -590,7 +584,7 @@ impl DroplessArena {
|
|||
&self,
|
||||
iter: impl IntoIterator<Item = Result<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.
|
||||
assert!(size_of::<T>() != 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -656,7 +656,11 @@ impl Pat {
|
|||
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
|
||||
// assuming `T0` to `Tn` are all syntactically valid as types.
|
||||
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)
|
||||
}
|
||||
_ => return None,
|
||||
|
|
@ -3131,16 +3135,8 @@ pub enum Const {
|
|||
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
||||
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),
|
||||
/// `final`; per RFC 3678, only trait items may be *explicitly* marked final.
|
||||
Final(Span),
|
||||
Final,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
|
|
@ -3630,7 +3626,6 @@ impl Item {
|
|||
pub fn opt_generics(&self) -> Option<&Generics> {
|
||||
match &self.kind {
|
||||
ItemKind::ExternCrate(..)
|
||||
| ItemKind::ConstBlock(_)
|
||||
| ItemKind::Use(_)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(_)
|
||||
|
|
@ -3877,55 +3872,27 @@ pub struct ConstItem {
|
|||
pub ident: Ident,
|
||||
pub generics: Generics,
|
||||
pub ty: Box<Ty>,
|
||||
pub rhs_kind: ConstItemRhsKind,
|
||||
pub rhs: Option<ConstItemRhs>,
|
||||
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub enum ConstItemRhsKind {
|
||||
Body { rhs: Option<Box<Expr>> },
|
||||
TypeConst { rhs: Option<AnonConst> },
|
||||
pub enum ConstItemRhs {
|
||||
TypeConst(AnonConst),
|
||||
Body(Box<Expr>),
|
||||
}
|
||||
|
||||
impl ConstItemRhsKind {
|
||||
pub fn new_body(rhs: Box<Expr>) -> Self {
|
||||
Self::Body { rhs: Some(rhs) }
|
||||
impl ConstItemRhs {
|
||||
pub fn span(&self) -> Span {
|
||||
self.expr().span
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
Some(self.expr()?.span)
|
||||
}
|
||||
|
||||
pub fn expr(&self) -> Option<&Expr> {
|
||||
pub fn expr(&self) -> &Expr {
|
||||
match self {
|
||||
Self::Body { rhs: Some(body) } => Some(&body),
|
||||
Self::TypeConst { rhs: Some(anon) } => Some(&anon.value),
|
||||
_ => None,
|
||||
ConstItemRhs::TypeConst(anon_const) => &anon_const.value,
|
||||
ConstItemRhs::Body(expr) => expr,
|
||||
}
|
||||
}
|
||||
|
||||
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`.
|
||||
|
|
@ -3947,11 +3914,6 @@ pub enum ItemKind {
|
|||
///
|
||||
/// E.g., `const FOO: i32 = 42;`.
|
||||
Const(Box<ConstItem>),
|
||||
/// A module-level const block.
|
||||
/// Equivalent to `const _: () = const { ... };`.
|
||||
///
|
||||
/// E.g., `const { assert!(true) }`.
|
||||
ConstBlock(ConstBlockItem),
|
||||
/// A function declaration (`fn`).
|
||||
///
|
||||
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
|
||||
|
|
@ -4028,8 +3990,6 @@ impl ItemKind {
|
|||
| ItemKind::MacroDef(ident, _)
|
||||
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
|
||||
|
||||
ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT),
|
||||
|
||||
ItemKind::Use(_)
|
||||
| ItemKind::ForeignMod(_)
|
||||
| ItemKind::GlobalAsm(_)
|
||||
|
|
@ -4043,9 +4003,9 @@ impl ItemKind {
|
|||
pub fn article(&self) -> &'static str {
|
||||
use ItemKind::*;
|
||||
match self {
|
||||
Use(..) | Static(..) | Const(..) | ConstBlock(..) | Fn(..) | Mod(..)
|
||||
| GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..)
|
||||
| MacroDef(..) | Delegation(..) | DelegationMac(..) => "a",
|
||||
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
|
||||
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
|
||||
| Delegation(..) | DelegationMac(..) => "a",
|
||||
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
|
||||
}
|
||||
}
|
||||
|
|
@ -4056,7 +4016,6 @@ impl ItemKind {
|
|||
ItemKind::Use(..) => "`use` import",
|
||||
ItemKind::Static(..) => "static item",
|
||||
ItemKind::Const(..) => "constant item",
|
||||
ItemKind::ConstBlock(..) => "const block",
|
||||
ItemKind::Fn(..) => "function",
|
||||
ItemKind::Mod(..) => "module",
|
||||
ItemKind::ForeignMod(..) => "extern block",
|
||||
|
|
@ -4086,18 +4045,7 @@ impl ItemKind {
|
|||
| Self::Trait(box Trait { generics, .. })
|
||||
| Self::TraitAlias(box TraitAlias { generics, .. })
|
||||
| Self::Impl(Impl { generics, .. }) => Some(generics),
|
||||
|
||||
Self::ExternCrate(..)
|
||||
| Self::Use(..)
|
||||
| Self::Static(..)
|
||||
| Self::ConstBlock(..)
|
||||
| Self::Mod(..)
|
||||
| Self::ForeignMod(..)
|
||||
| Self::GlobalAsm(..)
|
||||
| Self::MacCall(..)
|
||||
| Self::MacroDef(..)
|
||||
| Self::Delegation(..)
|
||||
| Self::DelegationMac(..) => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4148,7 +4096,7 @@ impl AssocItemKind {
|
|||
| Self::Fn(box Fn { defaultness, .. })
|
||||
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
||||
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
||||
Defaultness::Implicit
|
||||
Defaultness::Final
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
//! This API is completely unstable and subject to change.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(array_windows))]
|
||||
#![doc(test(attr(deny(warnings), allow(internal_features))))]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
|||
|
|
@ -625,12 +625,12 @@ impl TokenKind {
|
|||
}
|
||||
|
||||
impl Token {
|
||||
pub const fn new(kind: TokenKind, span: Span) -> Self {
|
||||
pub fn new(kind: TokenKind, span: Span) -> Self {
|
||||
Token { kind, span }
|
||||
}
|
||||
|
||||
/// Some token that will be thrown away later.
|
||||
pub const fn dummy() -> Self {
|
||||
pub fn dummy() -> Self {
|
||||
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![] },
|
||||
));
|
||||
} else if let Some(delim) = kind.close_delim() {
|
||||
// If there's no matching opening delimiter, the token stream is malformed,
|
||||
// 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 frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
|
||||
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
|
||||
assert!(
|
||||
open_delim.eq_ignoring_invisible_origin(&delim),
|
||||
|
|
|
|||
|
|
@ -425,9 +425,8 @@ macro_rules! common_visitor_and_walkers {
|
|||
ByRef,
|
||||
Closure,
|
||||
Const,
|
||||
ConstBlockItem,
|
||||
ConstItem,
|
||||
ConstItemRhsKind,
|
||||
ConstItemRhs,
|
||||
Defaultness,
|
||||
Delegation,
|
||||
DelegationMac,
|
||||
|
|
@ -826,8 +825,6 @@ macro_rules! common_visitor_and_walkers {
|
|||
visit_visitable!($($mut)? vis, use_tree),
|
||||
ItemKind::Static(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::ConstBlock(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::Const(item) =>
|
||||
visit_visitable!($($mut)? vis, item),
|
||||
ItemKind::Mod(safety, ident, mod_kind) =>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
|||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
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_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_errors::msg;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_session::parse::feature_err;
|
||||
|
|
@ -20,7 +19,8 @@ use super::errors::{
|
|||
RegisterConflict,
|
||||
};
|
||||
use crate::{
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt,
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
|
||||
ResolverAstLoweringExt, fluent_generated as fluent,
|
||||
};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
|
@ -51,8 +51,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| asm::InlineAsmArch::LoongArch32
|
||||
| asm::InlineAsmArch::LoongArch64
|
||||
| asm::InlineAsmArch::S390x
|
||||
| asm::InlineAsmArch::PowerPC
|
||||
| asm::InlineAsmArch::PowerPC64
|
||||
);
|
||||
if !is_stable
|
||||
&& !self.tcx.features().asm_experimental_arch()
|
||||
|
|
@ -67,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&self.tcx.sess,
|
||||
sym::asm_experimental_arch,
|
||||
sp,
|
||||
msg!("inline assembly is not stable yet on this architecture"),
|
||||
fluent::ast_lowering_unstable_inline_assembly,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -84,7 +82,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&self.tcx.sess,
|
||||
sym::asm_unwind,
|
||||
sp,
|
||||
msg!("the `may_unwind` option is unstable"),
|
||||
fluent::ast_lowering_unstable_may_unwind,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -499,7 +497,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
sess,
|
||||
sym::asm_goto_with_outputs,
|
||||
*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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,21 +152,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) -> DelegationResults<'hir> {
|
||||
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 = if let Some(delegation_info) =
|
||||
self.resolver.delegation_infos.get(&self.local_def_id(item_id))
|
||||
{
|
||||
self.get_delegation_ids(delegation_info.resolution_node, span)
|
||||
} else {
|
||||
return self.generate_delegation_error(
|
||||
self.dcx().span_delayed_bug(
|
||||
span,
|
||||
format!("LoweringContext: the delegation {:?} is unresolved", item_id),
|
||||
),
|
||||
span,
|
||||
delegation,
|
||||
);
|
||||
};
|
||||
let ids = self.get_delegation_ids(
|
||||
self.resolver.delegation_infos[&self.local_def_id(item_id)].resolution_node,
|
||||
span,
|
||||
);
|
||||
|
||||
match ids {
|
||||
Ok(ids) => {
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
|
|||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
#[label("only `Fn` traits may use parentheses")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<UseAngleBrackets>,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[suggestion_part(code = "<")]
|
||||
pub open_param: Span,
|
||||
|
|
@ -23,11 +23,11 @@ pub(crate) struct UseAngleBrackets {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("invalid ABI: found `{$abi}`", code = E0703)]
|
||||
#[note("invoke `{$command}` for a full list of supported calling conventions")]
|
||||
#[diag(ast_lowering_invalid_abi, code = E0703)]
|
||||
#[note]
|
||||
pub(crate) struct InvalidAbi {
|
||||
#[primary_span]
|
||||
#[label("invalid ABI")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub abi: Symbol,
|
||||
pub command: String,
|
||||
|
|
@ -36,16 +36,16 @@ pub(crate) struct InvalidAbi {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("default fields are not supported in tuple structs")]
|
||||
#[diag(ast_lowering_default_field_in_tuple)]
|
||||
pub(crate) struct TupleStructWithDefault {
|
||||
#[primary_span]
|
||||
#[label("default fields are only supported on structs")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
"there's a similarly named valid ABI `{$suggestion}`",
|
||||
ast_lowering_invalid_abi_suggestion,
|
||||
code = "\"{suggestion}\"",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
|
|
@ -57,7 +57,7 @@ pub(crate) struct InvalidAbiSuggestion {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("parenthesized generic arguments cannot be used in associated type constraints")]
|
||||
#[diag(ast_lowering_assoc_ty_parentheses)]
|
||||
pub(crate) struct AssocTyParentheses {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -67,12 +67,12 @@ pub(crate) struct AssocTyParentheses {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum AssocTyParenthesesSub {
|
||||
#[multipart_suggestion("remove these parentheses")]
|
||||
#[multipart_suggestion(ast_lowering_remove_parentheses)]
|
||||
Empty {
|
||||
#[suggestion_part(code = "")]
|
||||
parentheses_span: Span,
|
||||
},
|
||||
#[multipart_suggestion("use angle brackets instead")]
|
||||
#[multipart_suggestion(ast_lowering_use_angle_brackets)]
|
||||
NotEmpty {
|
||||
#[suggestion_part(code = "<")]
|
||||
open_param: Span,
|
||||
|
|
@ -82,8 +82,8 @@ pub(crate) enum AssocTyParenthesesSub {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`impl Trait` is not allowed in {$position}", code = E0562)]
|
||||
#[note("`impl Trait` is only allowed in arguments and return types of functions and methods")]
|
||||
#[diag(ast_lowering_misplaced_impl_trait, code = E0562)]
|
||||
#[note]
|
||||
pub(crate) struct MisplacedImplTrait<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -91,106 +91,97 @@ pub(crate) struct MisplacedImplTrait<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("associated type bounds are not allowed in `dyn` types")]
|
||||
#[diag(ast_lowering_assoc_ty_binding_in_dyn)]
|
||||
pub(crate) struct MisplacedAssocTyBinding {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(
|
||||
"use `impl Trait` to introduce a type instead",
|
||||
code = " = impl",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
)]
|
||||
#[suggestion(code = " = impl", applicability = "maybe-incorrect", style = "verbose")]
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
#[label("`_` not allowed here")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
#[label("only allowed inside `async` functions and blocks")]
|
||||
#[label]
|
||||
pub await_kw_span: Span,
|
||||
#[label("this is not `async`")]
|
||||
#[label(ast_lowering_this_not_async)]
|
||||
pub item_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("closures cannot be static", code = E0697)]
|
||||
#[diag(ast_lowering_closure_cannot_be_static, code = E0697)]
|
||||
pub(crate) struct ClosureCannotBeStatic {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("functional record updates are not allowed in destructuring assignments")]
|
||||
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||
pub(crate) struct FunctionalRecordUpdateDestructuringAssignment {
|
||||
#[primary_span]
|
||||
#[suggestion(
|
||||
"consider removing the trailing pattern",
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`async` coroutines are not yet supported", code = E0727)]
|
||||
#[diag(ast_lowering_async_coroutines_not_supported, code = E0727)]
|
||||
pub(crate) struct AsyncCoroutinesNotSupported {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("the `att_syntax` option is only supported on x86")]
|
||||
#[diag(ast_lowering_att_syntax_only_x86)]
|
||||
pub(crate) struct AttSyntaxOnlyX86 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`{$prev_name}` ABI specified multiple times")]
|
||||
#[diag(ast_lowering_abi_specified_multiple_times)]
|
||||
pub(crate) struct AbiSpecifiedMultipleTimes {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
pub prev_name: Symbol,
|
||||
#[label("previously specified here")]
|
||||
#[label]
|
||||
pub prev_span: Span,
|
||||
#[note("these ABIs are equivalent on the current target")]
|
||||
#[note]
|
||||
pub equivalent: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`clobber_abi` is not supported on this target")]
|
||||
#[diag(ast_lowering_clobber_abi_not_supported)]
|
||||
pub(crate) struct ClobberAbiNotSupported {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[note("the following ABIs are supported on this target: {$supported_abis}")]
|
||||
#[diag("invalid ABI for `clobber_abi`")]
|
||||
#[note]
|
||||
#[diag(ast_lowering_invalid_abi_clobber_abi)]
|
||||
pub(crate) struct InvalidAbiClobberAbi {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
|
|
@ -198,7 +189,7 @@ pub(crate) struct InvalidAbiClobberAbi {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("invalid register `{$reg}`: {$error}")]
|
||||
#[diag(ast_lowering_invalid_register)]
|
||||
pub(crate) struct InvalidRegister<'a> {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
|
|
@ -207,10 +198,8 @@ pub(crate) struct InvalidRegister<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[note(
|
||||
"the following register classes are supported on this target: {$supported_register_classes}"
|
||||
)]
|
||||
#[diag("invalid register class `{$reg_class}`: unknown register class")]
|
||||
#[note]
|
||||
#[diag(ast_lowering_invalid_register_class)]
|
||||
pub(crate) struct InvalidRegisterClass {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
|
|
@ -219,12 +208,12 @@ pub(crate) struct InvalidRegisterClass {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("invalid asm template modifier for this register class")]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)]
|
||||
pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
||||
#[primary_span]
|
||||
#[label("template modifier")]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
pub placeholder_span: Span,
|
||||
#[label("argument")]
|
||||
#[label(ast_lowering_argument)]
|
||||
pub op_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: InvalidAsmTemplateModifierRegClassSub,
|
||||
|
|
@ -232,48 +221,44 @@ pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvalidAsmTemplateModifierRegClassSub {
|
||||
#[note(
|
||||
"the `{$class_name}` register class supports the following template modifiers: {$modifiers}"
|
||||
)]
|
||||
#[note(ast_lowering_support_modifiers)]
|
||||
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 },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("asm template modifiers are not allowed for `const` arguments")]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_const)]
|
||||
pub(crate) struct InvalidAsmTemplateModifierConst {
|
||||
#[primary_span]
|
||||
#[label("template modifier")]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
pub placeholder_span: Span,
|
||||
#[label("argument")]
|
||||
#[label(ast_lowering_argument)]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("asm template modifiers are not allowed for `sym` arguments")]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_sym)]
|
||||
pub(crate) struct InvalidAsmTemplateModifierSym {
|
||||
#[primary_span]
|
||||
#[label("template modifier")]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
pub placeholder_span: Span,
|
||||
#[label("argument")]
|
||||
#[label(ast_lowering_argument)]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("asm template modifiers are not allowed for `label` arguments")]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_label)]
|
||||
pub(crate) struct InvalidAsmTemplateModifierLabel {
|
||||
#[primary_span]
|
||||
#[label("template modifier")]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
pub placeholder_span: Span,
|
||||
#[label("argument")]
|
||||
#[label(ast_lowering_argument)]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"register class `{$reg_class_name}` can only be used as a clobber, not as an input or output"
|
||||
)]
|
||||
#[diag(ast_lowering_register_class_only_clobber)]
|
||||
pub(crate) struct RegisterClassOnlyClobber {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
|
|
@ -281,7 +266,7 @@ pub(crate) struct RegisterClassOnlyClobber {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
|
|
@ -289,27 +274,27 @@ pub(crate) struct RegisterClassOnlyClobberStable {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("register `{$reg1_name}` conflicts with register `{$reg2_name}`")]
|
||||
#[diag(ast_lowering_register_conflict)]
|
||||
pub(crate) struct RegisterConflict<'a> {
|
||||
#[primary_span]
|
||||
#[label("register `{$reg1_name}`")]
|
||||
#[label(ast_lowering_register1)]
|
||||
pub op_span1: Span,
|
||||
#[label("register `{$reg2_name}`")]
|
||||
#[label(ast_lowering_register2)]
|
||||
pub op_span2: Span,
|
||||
pub reg1_name: &'a str,
|
||||
pub reg2_name: &'a str,
|
||||
#[help("use `lateout` instead of `out` to avoid conflict")]
|
||||
#[help]
|
||||
pub in_out: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[help("remove this and bind each tuple field independently")]
|
||||
#[diag("`{$ident_name} @` is not allowed in a {$ctx}")]
|
||||
#[help]
|
||||
#[diag(ast_lowering_sub_tuple_binding)]
|
||||
pub(crate) struct SubTupleBinding<'a> {
|
||||
#[primary_span]
|
||||
#[label("this is only allowed in slice patterns")]
|
||||
#[label]
|
||||
#[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",
|
||||
code = "..",
|
||||
applicability = "maybe-incorrect"
|
||||
|
|
@ -321,67 +306,63 @@ pub(crate) struct SubTupleBinding<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`..` can only be used once per {$ctx} pattern")]
|
||||
#[diag(ast_lowering_extra_double_dot)]
|
||||
pub(crate) struct ExtraDoubleDot<'a> {
|
||||
#[primary_span]
|
||||
#[label("can only be used once per {$ctx} pattern")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label("previously used here")]
|
||||
#[label(ast_lowering_previously_used_here)]
|
||||
pub prev_span: Span,
|
||||
pub ctx: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[note("only allowed in tuple, tuple struct, and slice patterns")]
|
||||
#[diag("`..` patterns are not allowed here")]
|
||||
#[note]
|
||||
#[diag(ast_lowering_misplaced_double_dot)]
|
||||
pub(crate) struct MisplacedDoubleDot {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`match` arm with no body")]
|
||||
#[diag(ast_lowering_match_arm_with_no_body)]
|
||||
pub(crate) struct MatchArmWithNoBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(
|
||||
"add a body after the pattern",
|
||||
code = " => todo!(),",
|
||||
applicability = "has-placeholders"
|
||||
)]
|
||||
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("a never pattern is always unreachable")]
|
||||
#[diag(ast_lowering_never_pattern_with_body)]
|
||||
pub(crate) struct NeverPatternWithBody {
|
||||
#[primary_span]
|
||||
#[label("this will never be executed")]
|
||||
#[suggestion("remove this expression", code = "", applicability = "maybe-incorrect")]
|
||||
#[label]
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("a guard on a never pattern will never be run")]
|
||||
#[diag(ast_lowering_never_pattern_with_guard)]
|
||||
pub(crate) struct NeverPatternWithGuard {
|
||||
#[primary_span]
|
||||
#[suggestion("remove this guard", code = "", applicability = "maybe-incorrect")]
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("arbitrary expressions aren't allowed in patterns")]
|
||||
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
|
||||
pub(crate) struct ArbitraryExpressionInPattern {
|
||||
#[primary_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,
|
||||
#[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,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("inclusive range with no end")]
|
||||
#[diag(ast_lowering_inclusive_range_with_no_end)]
|
||||
pub(crate) struct InclusiveRangeWithNoEnd {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -389,7 +370,7 @@ pub(crate) struct InclusiveRangeWithNoEnd {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
"use the right argument notation and remove the return type",
|
||||
ast_lowering_bad_return_type_notation_output_suggestion,
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
|
|
@ -403,36 +384,26 @@ pub(crate) struct RTNSuggestion {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum BadReturnTypeNotation {
|
||||
#[diag("argument types not allowed with return type notation")]
|
||||
#[diag(ast_lowering_bad_return_type_notation_inputs)]
|
||||
Inputs {
|
||||
#[primary_span]
|
||||
#[suggestion(
|
||||
"remove the input types",
|
||||
code = "(..)",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
#[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
|
||||
span: Span,
|
||||
},
|
||||
#[diag("return type not allowed with return type notation")]
|
||||
#[diag(ast_lowering_bad_return_type_notation_output)]
|
||||
Output {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
suggestion: RTNSuggestion,
|
||||
},
|
||||
#[diag("return type notation arguments must be elided with `..`")]
|
||||
#[diag(ast_lowering_bad_return_type_notation_needs_dots)]
|
||||
NeedsDots {
|
||||
#[primary_span]
|
||||
#[suggestion(
|
||||
"use the correct syntax by adding `..` to the arguments",
|
||||
code = "(..)",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
#[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
|
||||
span: Span,
|
||||
},
|
||||
#[diag("return type notation not allowed in this position yet")]
|
||||
#[diag(ast_lowering_bad_return_type_notation_position)]
|
||||
Position {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -440,14 +411,14 @@ pub(crate) enum BadReturnTypeNotation {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`async` bound modifier only allowed on trait, not `{$descr}`")]
|
||||
#[diag(ast_lowering_async_bound_not_on_trait)]
|
||||
pub(crate) struct AsyncBoundNotOnTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -455,37 +426,30 @@ pub(crate) struct AsyncBoundNotOnTrait {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`yield` can only be used in `#[coroutine]` closures, or `gen` blocks")]
|
||||
#[diag(ast_lowering_yield_in_closure)]
|
||||
pub(crate) struct YieldInClosure {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(
|
||||
"use `#[coroutine]` to make this closure a coroutine",
|
||||
code = "#[coroutine] ",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
)]
|
||||
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items"
|
||||
)]
|
||||
#[diag(ast_lowering_invalid_legacy_const_generic_arg)]
|
||||
pub(crate) struct InvalidLegacyConstGenericArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -495,7 +459,7 @@ pub(crate) struct InvalidLegacyConstGenericArg {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
"try using a const generic argument instead",
|
||||
ast_lowering_invalid_legacy_const_generic_arg_suggestion,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub(crate) struct UseConstGenericArg {
|
||||
|
|
@ -508,21 +472,21 @@ pub(crate) struct UseConstGenericArg {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unions cannot have default field values")]
|
||||
#[diag(ast_lowering_union_default_field_values)]
|
||||
pub(crate) struct UnionWithDefault {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("failed to resolve delegation callee")]
|
||||
#[diag(ast_lowering_delegation_unresolved_callee)]
|
||||
pub(crate) struct UnresolvedDelegationCallee {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("encountered a cycle during delegation signature resolution")]
|
||||
#[diag(ast_lowering_delegation_cycle_in_signature_resolution)]
|
||||
pub(crate) struct CycleInDelegationSignatureResolution {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use std::sync::Arc;
|
|||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::msg;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -29,7 +28,9 @@ use super::{
|
|||
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
||||
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope};
|
||||
use crate::{
|
||||
AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope, fluent_generated,
|
||||
};
|
||||
|
||||
struct WillCreateDefIdsVisitor {}
|
||||
|
||||
|
|
@ -966,14 +967,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
||||
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 => {}`
|
||||
let pending_arm = {
|
||||
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
|
||||
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 = {
|
||||
|
|
@ -1027,7 +1028,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
|
||||
// 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>) { ... }`
|
||||
let into_future_expr = match await_kind {
|
||||
|
|
@ -1702,7 +1703,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&self.tcx.sess,
|
||||
sym::yield_expr,
|
||||
span,
|
||||
msg!("yield syntax is experimental"),
|
||||
fluent_generated::ast_lowering_yield,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -1817,7 +1818,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let break_expr =
|
||||
self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
|
||||
let pat = self.pat_none(for_span);
|
||||
self.arm(pat, break_expr, for_span)
|
||||
self.arm(pat, break_expr)
|
||||
};
|
||||
|
||||
// Some(<pat>) => <body>,
|
||||
|
|
@ -1826,7 +1827,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let body_block =
|
||||
self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
|
||||
let body_expr = self.arena.alloc(self.expr_block(body_block));
|
||||
self.arm(some_pat, body_expr, for_span)
|
||||
self.arm(some_pat, body_expr)
|
||||
};
|
||||
|
||||
// `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 });
|
||||
|
||||
// `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 {
|
||||
ForLoopKind::For => {
|
||||
|
|
@ -1930,7 +1931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::LangItem::IntoAsyncIterIntoIter,
|
||||
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(
|
||||
for_span,
|
||||
iter,
|
||||
|
|
@ -1997,7 +1998,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
|
||||
self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);
|
||||
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) =>
|
||||
|
|
@ -2040,7 +2041,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression);
|
||||
|
||||
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(
|
||||
|
|
@ -2368,13 +2369,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut self,
|
||||
pat: &'hir hir::Pat<'hir>,
|
||||
expr: &'hir hir::Expr<'hir>,
|
||||
span: Span,
|
||||
) -> hir::Arm<'hir> {
|
||||
hir::Arm {
|
||||
hir_id: self.next_id(),
|
||||
pat,
|
||||
guard: None,
|
||||
span: self.lower_span(span),
|
||||
span: self.lower_span(expr.span),
|
||||
body: expr,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
| ItemKind::Use(..)
|
||||
| ItemKind::Static(..)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::ConstBlock(..)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(..)
|
||||
| ItemKind::GlobalAsm(..)
|
||||
|
|
@ -283,13 +282,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_define_opaque(hir_id, define_opaque);
|
||||
hir::ItemKind::Static(*m, ident, ty, body_id)
|
||||
}
|
||||
ItemKind::Const(box ConstItem {
|
||||
defaultness: _,
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind,
|
||||
define_opaque,
|
||||
ItemKind::Const(box ast::ConstItem {
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let (generics, (ty, rhs)) = self.lower_generics(
|
||||
|
|
@ -301,26 +295,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ty,
|
||||
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)
|
||||
},
|
||||
);
|
||||
self.lower_define_opaque(hir_id, &define_opaque);
|
||||
hir::ItemKind::Const(ident, generics, ty, rhs)
|
||||
}
|
||||
ItemKind::ConstBlock(ConstBlockItem { span, id, block }) => hir::ItemKind::Const(
|
||||
self.lower_ident(ConstBlockItem::IDENT),
|
||||
hir::Generics::empty(),
|
||||
self.arena.alloc(self.ty_tup(DUMMY_SP, &[])),
|
||||
hir::ConstItemRhs::Body({
|
||||
let body = hir::Expr {
|
||||
hir_id: self.lower_node_id(*id),
|
||||
kind: hir::ExprKind::Block(self.lower_block(block, false), None),
|
||||
span: self.lower_span(*span),
|
||||
};
|
||||
self.record_body(&[], body)
|
||||
}),
|
||||
),
|
||||
ItemKind::Fn(box Fn {
|
||||
sig: FnSig { decl, header, span: fn_sig_span },
|
||||
ident,
|
||||
|
|
@ -827,10 +808,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir_id,
|
||||
def_id: self.local_def_id(v.id),
|
||||
data: self.lower_variant_data(hir_id, item_kind, &v.data),
|
||||
disr_expr: v
|
||||
.disr_expr
|
||||
.as_ref()
|
||||
.map(|e| self.lower_anon_const_to_anon_const(e, e.value.span)),
|
||||
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
|
||||
ident: self.lower_ident(v.ident),
|
||||
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)),
|
||||
},
|
||||
vis_span: self.lower_span(f.vis.span),
|
||||
default: f
|
||||
.default
|
||||
.as_ref()
|
||||
.map(|v| self.lower_anon_const_to_anon_const(v, v.value.span)),
|
||||
default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)),
|
||||
ty,
|
||||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||
}
|
||||
|
|
@ -939,14 +914,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
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 {
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind,
|
||||
define_opaque,
|
||||
..
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
}) => {
|
||||
let (generics, kind) = self.lower_generics(
|
||||
generics,
|
||||
|
|
@ -957,18 +927,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
// Trait associated consts don't need an expression/body.
|
||||
let rhs = if rhs_kind.has_expr() {
|
||||
Some(this.lower_const_item_rhs(rhs_kind, i.span))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
hir::TraitItemKind::Const(ty, rhs, rhs_kind.is_type_const().into())
|
||||
let rhs = rhs
|
||||
.as_ref()
|
||||
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
|
||||
hir::TraitItemKind::Const(ty, rhs)
|
||||
},
|
||||
);
|
||||
|
||||
if define_opaque.is_some() {
|
||||
if rhs_kind.has_expr() {
|
||||
if rhs.is_some() {
|
||||
self.lower_define_opaque(hir_id, &define_opaque);
|
||||
} else {
|
||||
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 {
|
||||
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 {
|
||||
owner_id: trait_item_def_id,
|
||||
ident: self.lower_ident(ident),
|
||||
generics,
|
||||
kind,
|
||||
span: self.lower_span(i.span),
|
||||
defaultness,
|
||||
defaultness: hir::Defaultness::Default { has_value: has_default },
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
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
|
||||
// to not cause an assertion failure inside the `lower_defaultness` function.
|
||||
let has_val = true;
|
||||
let (defaultness, defaultness_span) =
|
||||
self.lower_defaultness(defaultness, has_val, || hir::Defaultness::Final);
|
||||
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
|
||||
let modifiers = TraitBoundModifiers {
|
||||
constness: BoundConstness::Never,
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
|
|
@ -1156,8 +1118,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) -> &'hir hir::ImplItem<'hir> {
|
||||
// Since `default impl` is not yet implemented, this is always true in impls.
|
||||
let has_value = true;
|
||||
let (defaultness, _) =
|
||||
self.lower_defaultness(i.kind.defaultness(), has_value, || hir::Defaultness::Final);
|
||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
let attrs = self.lower_attrs(
|
||||
hir_id,
|
||||
|
|
@ -1168,12 +1129,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let (ident, (generics, kind)) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem {
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind,
|
||||
define_opaque,
|
||||
..
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
}) => (
|
||||
*ident,
|
||||
self.lower_generics(
|
||||
|
|
@ -1186,7 +1142,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
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)
|
||||
},
|
||||
),
|
||||
|
|
@ -1310,14 +1266,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&self,
|
||||
d: Defaultness,
|
||||
has_value: bool,
|
||||
implicit: impl FnOnce() -> hir::Defaultness,
|
||||
) -> (hir::Defaultness, Option<Span>) {
|
||||
match d {
|
||||
Defaultness::Implicit => (implicit(), None),
|
||||
Defaultness::Default(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
|
||||
// this as a special case.
|
||||
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()
|
||||
{
|
||||
let span = this.lower_span(span);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ mod pat;
|
|||
mod path;
|
||||
pub mod stability;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
struct LoweringContext<'a, 'hir> {
|
||||
tcx: TyCtxt<'hir>,
|
||||
resolver: &'a mut ResolverAstLowering,
|
||||
|
|
@ -878,7 +880,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
|
||||
}
|
||||
LifetimeRes::Static { .. } | LifetimeRes::Error(..) => return None,
|
||||
LifetimeRes::Static { .. } | LifetimeRes::Error => return None,
|
||||
res => panic!(
|
||||
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
||||
res, ident, ident.span
|
||||
|
|
@ -1931,29 +1933,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
source: LifetimeSource,
|
||||
syntax: LifetimeSyntax,
|
||||
) -> &'hir hir::Lifetime {
|
||||
let res = if let Some(res) = self.resolver.get_lifetime_res(id) {
|
||||
match res {
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeKind::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => {
|
||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
hir::LifetimeKind::Infer
|
||||
}
|
||||
LifetimeRes::Static { .. } => {
|
||||
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||
hir::LifetimeKind::Static
|
||||
}
|
||||
LifetimeRes::Error(guar) => hir::LifetimeKind::Error(guar),
|
||||
LifetimeRes::ElidedAnchor { .. } => {
|
||||
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
||||
}
|
||||
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
|
||||
let res = match res {
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeKind::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => {
|
||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
hir::LifetimeKind::Infer
|
||||
}
|
||||
LifetimeRes::Static { .. } => {
|
||||
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||
hir::LifetimeKind::Static
|
||||
}
|
||||
LifetimeRes::Error => hir::LifetimeKind::Error,
|
||||
LifetimeRes::ElidedAnchor { .. } => {
|
||||
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
||||
}
|
||||
} else {
|
||||
hir::LifetimeKind::Error(self.dcx().span_delayed_bug(ident.span, "unresolved lifetime"))
|
||||
};
|
||||
|
||||
debug!(?res);
|
||||
|
|
@ -2017,13 +2016,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// AST resolution emitted an error on those parameters, so we lower them using
|
||||
// `ParamName::Error`.
|
||||
let ident = self.lower_ident(param.ident);
|
||||
let param_name = if let Some(LifetimeRes::Error(..)) =
|
||||
self.resolver.get_lifetime_res(param.id)
|
||||
{
|
||||
ParamName::Error(ident)
|
||||
} else {
|
||||
ParamName::Plain(ident)
|
||||
};
|
||||
let param_name =
|
||||
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
|
||||
ParamName::Error(ident)
|
||||
} else {
|
||||
ParamName::Plain(ident)
|
||||
};
|
||||
let kind =
|
||||
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
|
||||
|
||||
|
|
@ -2378,20 +2376,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
fn lower_const_item_rhs(
|
||||
&mut self,
|
||||
rhs_kind: &ConstItemRhsKind,
|
||||
attrs: &[hir::Attribute],
|
||||
rhs: Option<&ConstItemRhs>,
|
||||
span: Span,
|
||||
) -> hir::ConstItemRhs<'hir> {
|
||||
match rhs_kind {
|
||||
ConstItemRhsKind::Body { rhs: Some(body) } => {
|
||||
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) } => {
|
||||
match rhs {
|
||||
Some(ConstItemRhs::TypeConst(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 {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Error(
|
||||
|
|
@ -2401,6 +2394,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
};
|
||||
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 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)
|
||||
}));
|
||||
|
||||
|
|
@ -2442,7 +2447,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
ExprKind::Tup(exprs) => {
|
||||
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)
|
||||
}));
|
||||
|
||||
|
|
@ -2482,7 +2496,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// then go unused as the `Target::ExprField` is not actually
|
||||
// corresponding to `Node::ExprField`.
|
||||
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
|
||||
let expr = self.lower_expr_to_const_arg_direct(&f.expr);
|
||||
|
||||
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 {
|
||||
hir_id,
|
||||
|
|
@ -2500,7 +2523,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
ExprKind::Array(elements) => {
|
||||
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
|
||||
let const_arg = self.lower_expr_to_const_arg_direct(element);
|
||||
let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(element)
|
||||
};
|
||||
&*self.arena.alloc(const_arg)
|
||||
}));
|
||||
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
|
||||
|
|
@ -2530,7 +2559,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| ExprKind::Call(..)
|
||||
| ExprKind::Tup(..)
|
||||
| ExprKind::Array(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
)
|
||||
{
|
||||
return self.lower_expr_to_const_arg_direct(expr);
|
||||
|
|
@ -2544,27 +2572,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
ConstArg {
|
||||
hir_id: self.lower_node_id(expr.id),
|
||||
kind: hir::ConstArgKind::Literal { lit: literal.node, negated: false },
|
||||
kind: hir::ConstArgKind::Literal(literal.node),
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
|
@ -2575,15 +2586,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
anon: &AnonConst,
|
||||
) -> &'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))]
|
||||
fn lower_anon_const_to_const_arg(
|
||||
&mut self,
|
||||
anon: &AnonConst,
|
||||
span: Span,
|
||||
) -> hir::ConstArg<'hir> {
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// We cannot change parsing depending on feature gates available,
|
||||
|
|
@ -2594,7 +2601,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
if tcx.features().min_generic_const_args() {
|
||||
return match anon.mgca_disambiguation {
|
||||
MgcaDisambiguation::AnonConst => {
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon, span);
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
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 {
|
||||
hir_id: self.next_id(),
|
||||
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
|
||||
/// [`Self::lower_anon_const_to_const_arg`].
|
||||
fn lower_anon_const_to_anon_const(
|
||||
&mut self,
|
||||
c: &AnonConst,
|
||||
span: Span,
|
||||
) -> &'hir hir::AnonConst {
|
||||
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
|
||||
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
|
||||
let def_id = this.local_def_id(c.id);
|
||||
let hir_id = this.lower_node_id(c.id);
|
||||
|
|
@ -2662,7 +2665,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
def_id,
|
||||
hir_id,
|
||||
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) {
|
||||
match extern_abi_enabled(features, span, abi) {
|
||||
Ok(_) => (),
|
||||
|
|
@ -95,11 +96,6 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
ExternAbi::RustCold => {
|
||||
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
|
||||
}
|
||||
ExternAbi::RustPreserveNone => Err(UnstableAbi {
|
||||
abi,
|
||||
feature: sym::rust_preserve_none_cc,
|
||||
explain: GateReason::Experimental,
|
||||
}),
|
||||
ExternAbi::RustInvalid => {
|
||||
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
|||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
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> {
|
||||
sess: &'a Session,
|
||||
features: &'a Features,
|
||||
|
|
@ -422,7 +400,6 @@ impl<'a> AstValidator<'a> {
|
|||
CanonAbi::C
|
||||
| CanonAbi::Rust
|
||||
| CanonAbi::RustCold
|
||||
| CanonAbi::RustPreserveNone
|
||||
| CanonAbi::Arm(_)
|
||||
| CanonAbi::X86(_) => { /* nothing to check */ }
|
||||
|
||||
|
|
@ -585,32 +562,10 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_defaultness(
|
||||
&self,
|
||||
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);
|
||||
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 });
|
||||
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||
if let Defaultness::Default(def_span) = defaultness {
|
||||
let span = self.sess.source_map().guess_head_span(span);
|
||||
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -742,11 +697,13 @@ impl<'a> AstValidator<'a> {
|
|||
unreachable!("C variable argument list cannot be used in closures")
|
||||
};
|
||||
|
||||
if let Const::Yes(_) = sig.header.constness
|
||||
&& !self.features.enabled(sym::const_c_variadic)
|
||||
{
|
||||
let msg = format!("c-variadic const function definitions are unstable");
|
||||
feature_err(&self.sess, sym::const_c_variadic, sig.span, msg).emit();
|
||||
// C-variadics are not yet implemented in const evaluation.
|
||||
if let Const::Yes(const_span) = sig.header.constness {
|
||||
self.dcx().emit_err(errors::ConstAndCVariadic {
|
||||
spans: vec![const_span, variadic_param.span],
|
||||
const_span,
|
||||
variadic_span: variadic_param.span,
|
||||
});
|
||||
}
|
||||
|
||||
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.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
|
||||
for EiiImpl { eii_macro_path, .. } in eii_impls {
|
||||
self.visit_path(eii_macro_path);
|
||||
|
|
@ -1403,9 +1360,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
});
|
||||
}
|
||||
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
|
||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||
if !rhs_kind.has_expr() {
|
||||
ItemKind::Const(box ConstItem { defaultness, ident, rhs, .. }) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
if rhs.is_none() {
|
||||
self.dcx().emit_err(errors::ConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
|
|
@ -1442,7 +1399,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
ItemKind::TyAlias(
|
||||
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() {
|
||||
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
||||
span: item.span,
|
||||
|
|
@ -1472,7 +1429,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
match &fi.kind {
|
||||
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_headerless(sig.header);
|
||||
self.check_foreign_item_ascii_only(*ident);
|
||||
|
|
@ -1492,7 +1449,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
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_type_no_bounds(bounds, "`extern` blocks");
|
||||
self.check_foreign_ty_genericless(generics, after_where_clause);
|
||||
|
|
@ -1751,29 +1708,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_nomangle_item_asciionly(ident, item.span);
|
||||
}
|
||||
|
||||
let defaultness = item.kind.defaultness();
|
||||
self.check_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 ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
|
||||
self.check_defaultness(item.span, item.kind.defaultness());
|
||||
}
|
||||
|
||||
if let AssocCtxt::Impl { .. } = ctxt {
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(box ConstItem { rhs_kind, .. }) => {
|
||||
if !rhs_kind.has_expr() {
|
||||
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
AssocItemKind::Const(box ConstItem { rhs: None, .. }) => {
|
||||
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||
if body.is_none() && !self.is_sdylib_interface {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,5 @@
|
|||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
|
||||
use rustc_errors::msg;
|
||||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::{feature_err, feature_warn};
|
||||
|
|
@ -14,11 +13,15 @@ use crate::errors;
|
|||
macro_rules! gate {
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
|
||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
|
||||
}
|
||||
}};
|
||||
|
|
@ -28,11 +31,13 @@ macro_rules! gate {
|
|||
macro_rules! gate_alt {
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
|
||||
if !$has_feature && !$span.allows_unstable($name) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
||||
if !$has_feature && !$span.allows_unstable($name) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
|
||||
for note in $notes {
|
||||
diag.note(*note);
|
||||
|
|
@ -125,7 +130,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
|||
&self,
|
||||
non_lifetime_binders,
|
||||
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.
|
||||
|
|
@ -249,14 +254,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => {
|
||||
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) {
|
||||
match e.kind {
|
||||
ast::ExprKind::TryBlock(_, None) => {
|
||||
// `try { ... }` is old and is only gated post-expansion here.
|
||||
gate!(&self, try_blocks, e.span, "`try` expression is experimental");
|
||||
}
|
||||
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 {
|
||||
kind: token::LitKind::Float | token::LitKind::Integer,
|
||||
|
|
@ -426,20 +427,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
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,
|
||||
};
|
||||
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) {
|
||||
maybe_stage_features(sess, features, krate);
|
||||
check_incompatible_features(sess, features);
|
||||
check_dependent_features(sess, features);
|
||||
check_new_solver_banned_features(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.yield_expr() && !span.allows_unstable(sym::yield_expr))
|
||||
{
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
// Emit yield_expr as the error, since that will be sufficient. You can think of it
|
||||
// as coroutines and gen_blocks imply yield_expr.
|
||||
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
|
||||
|
|
@ -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 are unstable"
|
||||
);
|
||||
gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental");
|
||||
gate_all!(yeet_expr, "`do yeet` expression is experimental");
|
||||
gate_all!(const_closures, "const closures are experimental");
|
||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||
|
|
@ -537,6 +523,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
if !visitor.features.min_generic_const_args()
|
||||
&& !span.allows_unstable(sym::min_generic_const_args)
|
||||
{
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
feature_err(
|
||||
&visitor.sess,
|
||||
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!(return_type_notation, "return type notation 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!(frontmatter, "frontmatters are 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 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)
|
||||
&& snippet == "!"
|
||||
{
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
|
||||
.emit();
|
||||
} 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) {
|
||||
if !sess.opts.unstable_opts.next_solver.globally {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
// tidy-alphabetical-start
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub mod ast_validation;
|
||||
mod errors;
|
||||
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) {
|
||||
self.word(lifetime.ident.name.to_string());
|
||||
self.ann_post(lifetime.ident)
|
||||
self.print_name(lifetime.ident.name)
|
||||
}
|
||||
|
||||
fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ impl<'a> State<'a> {
|
|||
expr.as_deref(),
|
||||
vis,
|
||||
*safety,
|
||||
ast::Defaultness::Implicit,
|
||||
ast::Defaultness::Final,
|
||||
define_opaque.as_deref(),
|
||||
),
|
||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||
|
|
@ -201,27 +201,16 @@ impl<'a> State<'a> {
|
|||
body.as_deref(),
|
||||
&item.vis,
|
||||
ast::Safety::Default,
|
||||
ast::Defaultness::Implicit,
|
||||
ast::Defaultness::Final,
|
||||
define_opaque.as_deref(),
|
||||
);
|
||||
}
|
||||
ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("const");
|
||||
self.nbsp();
|
||||
{
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_block_with_attrs(block, &[], cb, ib);
|
||||
}
|
||||
self.end(ib);
|
||||
}
|
||||
ast::ItemKind::Const(box ast::ConstItem {
|
||||
defaultness,
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind,
|
||||
rhs,
|
||||
define_opaque,
|
||||
}) => {
|
||||
self.print_item_const(
|
||||
|
|
@ -229,7 +218,7 @@ impl<'a> State<'a> {
|
|||
None,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind.expr(),
|
||||
rhs.as_ref().map(|ct| ct.expr()),
|
||||
&item.vis,
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
|
|
@ -573,7 +562,7 @@ impl<'a> State<'a> {
|
|||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind,
|
||||
rhs,
|
||||
define_opaque,
|
||||
}) => {
|
||||
self.print_item_const(
|
||||
|
|
@ -581,7 +570,7 @@ impl<'a> State<'a> {
|
|||
None,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind.expr(),
|
||||
rhs.as_ref().map(|ct| ct.expr()),
|
||||
vis,
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ edition = "2024"
|
|||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
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;
|
||||
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);
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
|
||||
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];
|
||||
type Item = Symbol;
|
||||
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(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ use std::convert::identity;
|
|||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::tokenstream::DelimSpan;
|
||||
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::{
|
||||
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
|
||||
};
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
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_session::Session;
|
||||
use rustc_session::config::ExpectedValues;
|
||||
|
|
@ -25,7 +25,7 @@ use crate::session_diagnostics::{
|
|||
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
|
||||
ParsedDescription,
|
||||
};
|
||||
use crate::{AttributeParser, parse_version, session_diagnostics};
|
||||
use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics};
|
||||
|
||||
pub const CFG_TEMPLATE: AttributeTemplate = template!(
|
||||
List: &["predicate"],
|
||||
|
|
@ -141,7 +141,7 @@ fn parse_cfg_entry_target<S: Stage>(
|
|||
cx.sess(),
|
||||
sym::cfg_target_compact,
|
||||
meta_span,
|
||||
msg!("compact `cfg(target(..))` is experimental and subject to change"),
|
||||
fluent_generated::attr_parsing_unstable_cfg_target_compact,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -360,10 +360,7 @@ fn parse_cfg_attr_internal<'a>(
|
|||
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
|
||||
// Parse cfg predicate
|
||||
let pred_start = parser.token.span;
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
parser,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
)?;
|
||||
let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?;
|
||||
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
||||
|
||||
let cfg_predicate = AttributeParser::parse_single_args(
|
||||
|
|
@ -378,7 +375,7 @@ fn parse_cfg_attr_internal<'a>(
|
|||
CRATE_NODE_ID,
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&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) {
|
||||
let (cfg, feature, has_feature) = gated_cfg;
|
||||
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
|
||||
|
|
|
|||
|
|
@ -1,35 +1,22 @@
|
|||
use rustc_ast::token::Token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrStyle, NodeId, token};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_hir::{AttrPath, Target};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{Parser, Recovery};
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
||||
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CfgSelectPredicate {
|
||||
Cfg(CfgEntry),
|
||||
Wildcard(Token),
|
||||
}
|
||||
|
||||
impl CfgSelectPredicate {
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
CfgSelectPredicate::Cfg(cfg_entry) => cfg_entry.span(),
|
||||
CfgSelectPredicate::Wildcard(token) => token.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CfgSelectBranches {
|
||||
/// All the conditional branches.
|
||||
|
|
@ -91,11 +78,8 @@ pub fn parse_cfg_select(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
p,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
sess,
|
||||
|
|
@ -110,7 +94,7 @@ pub fn parse_cfg_select(
|
|||
// Doesn't matter what the target actually is here.
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&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)
|
||||
}
|
||||
|
||||
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 });
|
||||
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 });
|
||||
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 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;
|
||||
}
|
||||
|
||||
Some(AttributeKind::RustcConfusables {
|
||||
Some(AttributeKind::Confusables {
|
||||
symbols: self.confusables,
|
||||
first_span: self.first_span.unwrap(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_hir::attrs::WindowsSubsystemKind;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pub(crate) struct NoMainParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
|
||||
const PATH: &[Symbol] = &[sym::no_main];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcCoherenceIsCoreParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
|
||||
|
|
@ -238,66 +175,3 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
|||
Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct PanicRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::panic_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct NeedsPanicRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct ProfilerRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::profiler_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
|
||||
}
|
||||
|
||||
pub(crate) struct NoBuiltinsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
|
||||
const PATH: &[Symbol] = &[sym::no_builtins];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
|
||||
}
|
||||
|
||||
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::{RustcVersion, VERSION_PLACEHOLDER};
|
||||
|
||||
use super::prelude::*;
|
||||
use super::util::parse_version;
|
||||
|
|
@ -144,8 +143,6 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
|||
DeprecatedSince::Future
|
||||
} else if !is_rustc {
|
||||
DeprecatedSince::NonStandard(since)
|
||||
} else if since.as_str() == VERSION_PLACEHOLDER {
|
||||
DeprecatedSince::RustcVersion(RustcVersion::CURRENT)
|
||||
} else if let Some(version) = parse_version(since) {
|
||||
DeprecatedSince::RustcVersion(version)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ impl<S: Stage> SingleAttributeParser<S> for DummyParser {
|
|||
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
|
||||
|
||||
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;
|
||||
|
||||
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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
@ -67,7 +67,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
|||
pub(crate) struct 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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use rustc_errors::msg;
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
|
||||
use rustc_hir::attrs::*;
|
||||
|
|
@ -11,11 +10,12 @@ use rustc_target::spec::{Arch, BinaryFormat};
|
|||
use super::prelude::*;
|
||||
use super::util::parse_single_integer;
|
||||
use crate::attributes::cfg::parse_cfg_entry;
|
||||
use crate::fluent_generated;
|
||||
use crate::session_diagnostics::{
|
||||
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
|
||||
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
|
||||
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
|
||||
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
|
||||
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86,
|
||||
IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
|
||||
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
|
||||
WholeArchiveNeedsStatic,
|
||||
};
|
||||
|
||||
pub(crate) struct LinkNameParser;
|
||||
|
|
@ -141,6 +141,8 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
|||
|
||||
macro report_unstable_modifier($feature: ident) {
|
||||
if !features.$feature() {
|
||||
// FIXME: make this translatable
|
||||
#[expect(rustc::untranslatable_diagnostic)]
|
||||
feature_err(
|
||||
sess,
|
||||
sym::$feature,
|
||||
|
|
@ -165,14 +167,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
|||
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),
|
||||
|
||||
(
|
||||
|
|
@ -198,7 +192,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
|||
span,
|
||||
&[
|
||||
sym::bundle,
|
||||
sym::export_symbols,
|
||||
sym::verbatim,
|
||||
sym::whole_dash_archive,
|
||||
sym::as_dash_needed,
|
||||
|
|
@ -294,9 +287,7 @@ impl LinkParser {
|
|||
};
|
||||
|
||||
let link_kind = match link_kind {
|
||||
kw::Static => {
|
||||
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
|
||||
}
|
||||
kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
|
||||
sym::dylib => NativeLibKind::Dylib { as_needed: None },
|
||||
sym::framework => {
|
||||
if !sess.target.is_like_darwin {
|
||||
|
|
@ -316,7 +307,7 @@ impl LinkParser {
|
|||
sess,
|
||||
sym::raw_dylib_elf,
|
||||
nv.value_span,
|
||||
msg!("link kind `raw-dylib` is unstable on ELF platforms"),
|
||||
fluent_generated::attr_parsing_raw_dylib_elf_unstable,
|
||||
)
|
||||
.emit();
|
||||
} else {
|
||||
|
|
@ -331,7 +322,7 @@ impl LinkParser {
|
|||
sess,
|
||||
sym::link_arg_attribute,
|
||||
nv.value_span,
|
||||
msg!("link kind `link-arg` is unstable"),
|
||||
fluent_generated::attr_parsing_link_arg_unstable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -396,7 +387,13 @@ impl LinkParser {
|
|||
return true;
|
||||
};
|
||||
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();
|
||||
true
|
||||
|
|
@ -534,7 +531,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
|
|||
Allow(Target::Static),
|
||||
Allow(Target::ForeignStatic),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
|
||||
}
|
||||
|
||||
pub(crate) struct LinkOrdinalParser;
|
||||
|
|
@ -661,21 +658,3 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
|||
Some(AttributeKind::Linkage(linkage, cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct NeedsAllocatorParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
|
||||
const PATH: &[Symbol] = &[sym::needs_allocator];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
|
||||
}
|
||||
|
||||
pub(crate) struct CompilerBuiltinsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
|
||||
const PATH: &[Symbol] = &[sym::compiler_builtins];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser {
|
|||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAsPtr;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr;
|
||||
}
|
||||
|
||||
pub(crate) struct PubTransparentParser;
|
||||
|
|
@ -23,7 +23,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser {
|
|||
Allow(Target::Enum),
|
||||
Allow(Target::Union),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent;
|
||||
}
|
||||
|
||||
pub(crate) struct PassByValueParser;
|
||||
|
|
@ -35,7 +35,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser {
|
|||
Allow(Target::Enum),
|
||||
Allow(Target::TyAlias),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassByValue;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcShouldNotBeCalledOnConstItems;
|
||||
|
|
|
|||
|
|
@ -206,12 +206,3 @@ impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
|
|||
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 prototype;
|
||||
pub(crate) mod repr;
|
||||
pub(crate) mod rustc_allocator;
|
||||
pub(crate) mod rustc_dump;
|
||||
pub(crate) mod rustc_internal;
|
||||
pub(crate) mod semantics;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS;
|
||||
|
||||
use super::prelude::*;
|
||||
|
||||
const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
|
||||
|
|
@ -129,13 +126,6 @@ fn parse_derive_like<S: Stage>(
|
|||
cx.expected_identifier(ident.span);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
|
|||
pub(crate) struct AlignParser(Option<(Align, Span)>);
|
||||
|
||||
impl AlignParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_align];
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_align];
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
|
||||
|
||||
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);
|
||||
|
||||
impl AlignStaticParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_align_static];
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_align_static];
|
||||
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
||||
|
||||
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::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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcDumpDefParentsParser;
|
||||
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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcDumpItemBoundsParser;
|
||||
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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcDumpPredicatesParser;
|
||||
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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
@ -49,9 +49,9 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
|
|||
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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
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> {
|
||||
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::Method(MethodKind::Inherent)),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConstStabilityIndirect;
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -244,20 +244,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
|||
this.promotable = true;
|
||||
}),
|
||||
];
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
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),
|
||||
]);
|
||||
const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
|
||||
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.promotable {
|
||||
|
|
@ -271,7 +258,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
|||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
Some(AttributeKind::RustcSkipDuringMethodDispatch {
|
||||
array,
|
||||
boxed_slice,
|
||||
span: cx.attr_span,
|
||||
})
|
||||
Some(AttributeKind::SkipDuringMethodDispatch { 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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
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
|
||||
|
|
@ -86,15 +91,15 @@ impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
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;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
|
||||
pub(crate) struct DoNotImplementViaObjectParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDynIncompatibleTrait;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
|
||||
}
|
||||
|
||||
// Specialization
|
||||
|
|
@ -104,7 +109,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for SpecializationTraitParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
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;
|
||||
|
|
@ -112,7 +117,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for UnsafeSpecializationMarkerParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcUnsafeSpecializationMarker;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker;
|
||||
}
|
||||
|
||||
// Coherence
|
||||
|
|
@ -122,7 +127,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for CoinductiveParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_coinductive];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
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;
|
||||
|
|
@ -131,7 +136,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
|
|||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ use super::prelude::*;
|
|||
|
||||
pub(crate) struct TransparencyParser;
|
||||
|
||||
// FIXME(jdonszelmann): make these proper diagnostics
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
|
|
@ -32,6 +35,6 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
}
|
||||
None => None,
|
||||
}
|
||||
.map(AttributeKind::RustcMacroTransparency)
|
||||
.map(AttributeKind::MacroTransparency)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
|
|
@ -11,48 +10,85 @@ use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
|
|||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_hir::{AttrPath, HirId};
|
||||
use rustc_parse::parser::Recovery;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
|
||||
use crate::AttributeParser;
|
||||
// Glob imports to avoid big, bitrotty import lists
|
||||
use crate::attributes::allow_unstable::*;
|
||||
use crate::attributes::body::*;
|
||||
use crate::attributes::cfi_encoding::*;
|
||||
use crate::attributes::codegen_attrs::*;
|
||||
use crate::attributes::confusables::*;
|
||||
use crate::attributes::crate_level::*;
|
||||
use crate::attributes::debugger::*;
|
||||
use crate::attributes::deprecation::*;
|
||||
use crate::attributes::do_not_recommend::*;
|
||||
use crate::attributes::doc::*;
|
||||
use crate::attributes::dummy::*;
|
||||
use crate::attributes::inline::*;
|
||||
use crate::attributes::instruction_set::*;
|
||||
use crate::attributes::link_attrs::*;
|
||||
use crate::attributes::lint_helpers::*;
|
||||
use crate::attributes::loop_match::*;
|
||||
use crate::attributes::macro_attrs::*;
|
||||
use crate::attributes::must_not_suspend::*;
|
||||
use crate::attributes::must_use::*;
|
||||
use crate::attributes::no_implicit_prelude::*;
|
||||
use crate::attributes::no_link::*;
|
||||
use crate::attributes::non_exhaustive::*;
|
||||
use crate::attributes::allow_unstable::{
|
||||
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
|
||||
};
|
||||
use crate::attributes::body::CoroutineParser;
|
||||
use crate::attributes::cfi_encoding::CfiEncodingParser;
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser,
|
||||
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
|
||||
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
|
||||
ThreadLocalParser, TrackCallerParser, UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::crate_level::{
|
||||
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
|
||||
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
|
||||
WindowsSubsystemParser,
|
||||
};
|
||||
use crate::attributes::debugger::DebuggerViualizerParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::do_not_recommend::DoNotRecommendParser;
|
||||
use crate::attributes::doc::DocParser;
|
||||
use crate::attributes::dummy::DummyParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
use crate::attributes::instruction_set::InstructionSetParser;
|
||||
use crate::attributes::link_attrs::{
|
||||
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
|
||||
LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
|
||||
};
|
||||
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::pin_v2::*;
|
||||
use crate::attributes::proc_macro_attrs::*;
|
||||
use crate::attributes::prototype::*;
|
||||
use crate::attributes::repr::*;
|
||||
use crate::attributes::rustc_allocator::*;
|
||||
use crate::attributes::rustc_dump::*;
|
||||
use crate::attributes::rustc_internal::*;
|
||||
use crate::attributes::semantics::*;
|
||||
use crate::attributes::stability::*;
|
||||
use crate::attributes::test_attrs::*;
|
||||
use crate::attributes::traits::*;
|
||||
use crate::attributes::transparency::*;
|
||||
use crate::attributes::pin_v2::PinV2Parser;
|
||||
use crate::attributes::proc_macro_attrs::{
|
||||
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
|
||||
};
|
||||
use crate::attributes::prototype::CustomMirParser;
|
||||
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||
use crate::attributes::rustc_dump::{
|
||||
RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs,
|
||||
RustcDumpVtable,
|
||||
};
|
||||
use crate::attributes::rustc_internal::{
|
||||
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::parser::{ArgParser, RefPathParser};
|
||||
use crate::session_diagnostics::{
|
||||
|
|
@ -62,19 +98,19 @@ use crate::target_checking::AllowedTargets;
|
|||
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
||||
|
||||
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) template: AttributeTemplate,
|
||||
pub(super) accept_fn: AcceptFn<S>,
|
||||
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>;
|
||||
pub(crate) type FinalizeFn<S> =
|
||||
type FinalizeFn<S> =
|
||||
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
||||
|
||||
macro_rules! attribute_parsers {
|
||||
|
|
@ -102,7 +138,8 @@ macro_rules! attribute_parsers {
|
|||
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
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! {
|
||||
|
|
@ -110,29 +147,25 @@ macro_rules! attribute_parsers {
|
|||
};
|
||||
|
||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||
match accepters.entry(*path) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(GroupTypeInnerAccept {
|
||||
template: *template,
|
||||
accept_fn: Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
accept_fn(s, cx, args)
|
||||
})
|
||||
}),
|
||||
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"),
|
||||
}
|
||||
accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||
template: *template,
|
||||
accept_fn: Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
accept_fn(s, cx, args)
|
||||
})
|
||||
}),
|
||||
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
MacroUseParser,
|
||||
NakedParser,
|
||||
RustcCguTestAttributeParser,
|
||||
StabilityParser,
|
||||
UsedParser,
|
||||
// tidy-alphabetical-end
|
||||
|
|
@ -155,15 +187,10 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-start
|
||||
Combine<AllowConstFnUnstableParser>,
|
||||
Combine<AllowInternalUnstableParser>,
|
||||
Combine<CrateTypeParser>,
|
||||
Combine<DebuggerViualizerParser>,
|
||||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<LinkParser>,
|
||||
Combine<ReprParser>,
|
||||
Combine<RustcCleanParser>,
|
||||
Combine<RustcLayoutParser>,
|
||||
Combine<RustcMirParser>,
|
||||
Combine<RustcThenThisWouldNeedParser>,
|
||||
Combine<TargetFeatureParser>,
|
||||
Combine<UnstableFeatureBoundParser>,
|
||||
// tidy-alphabetical-end
|
||||
|
|
@ -181,7 +208,6 @@ attribute_parsers!(
|
|||
Single<IgnoreParser>,
|
||||
Single<InlineParser>,
|
||||
Single<InstructionSetParser>,
|
||||
Single<LangParser>,
|
||||
Single<LinkNameParser>,
|
||||
Single<LinkOrdinalParser>,
|
||||
Single<LinkSectionParser>,
|
||||
|
|
@ -193,35 +219,23 @@ attribute_parsers!(
|
|||
Single<ObjcClassParser>,
|
||||
Single<ObjcSelectorParser>,
|
||||
Single<OptimizeParser>,
|
||||
Single<PatchableFunctionEntryParser>,
|
||||
Single<PathAttributeParser>,
|
||||
Single<PatternComplexityLimitParser>,
|
||||
Single<ProcMacroDeriveParser>,
|
||||
Single<RecursionLimitParser>,
|
||||
Single<ReexportTestHarnessMainParser>,
|
||||
Single<RustcAbiParser>,
|
||||
Single<RustcAllocatorZeroedVariantParser>,
|
||||
Single<RustcBuiltinMacroParser>,
|
||||
Single<RustcDefPath>,
|
||||
Single<RustcDeprecatedSafe2024Parser>,
|
||||
Single<RustcDiagnosticItemParser>,
|
||||
Single<RustcForceInlineParser>,
|
||||
Single<RustcIfThisChangedParser>,
|
||||
Single<RustcLayoutScalarValidRangeEndParser>,
|
||||
Single<RustcLayoutScalarValidRangeStartParser>,
|
||||
Single<RustcLegacyConstGenericsParser>,
|
||||
Single<RustcLintOptDenyFieldAccessParser>,
|
||||
Single<RustcMustImplementOneOfParser>,
|
||||
Single<RustcNeverTypeOptionsParser>,
|
||||
Single<RustcReservationImplParser>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcScalableVectorParser>,
|
||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||
Single<RustcSymbolName>,
|
||||
Single<RustcTestMarkerParser>,
|
||||
Single<SanitizeParser>,
|
||||
Single<ShouldPanicParser>,
|
||||
Single<SkipDuringMethodDispatchParser>,
|
||||
Single<TestRunnerParser>,
|
||||
Single<TransparencyParser>,
|
||||
Single<TypeLengthLimitParser>,
|
||||
Single<WindowsSubsystemParser>,
|
||||
|
|
@ -231,13 +245,11 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
||||
Single<WithoutArgs<CoinductiveParser>>,
|
||||
Single<WithoutArgs<ColdParser>>,
|
||||
Single<WithoutArgs<CompilerBuiltinsParser>>,
|
||||
Single<WithoutArgs<ConstContinueParser>>,
|
||||
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
||||
Single<WithoutArgs<CoroutineParser>>,
|
||||
Single<WithoutArgs<DefaultLibAllocatorParser>>,
|
||||
Single<WithoutArgs<DenyExplicitImplParser>>,
|
||||
Single<WithoutArgs<DynIncompatibleTraitParser>>,
|
||||
Single<WithoutArgs<DoNotImplementViaObjectParser>>,
|
||||
Single<WithoutArgs<EiiForeignItemParser>>,
|
||||
Single<WithoutArgs<ExportStableParser>>,
|
||||
Single<WithoutArgs<FfiConstParser>>,
|
||||
|
|
@ -247,75 +259,40 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<MacroEscapeParser>>,
|
||||
Single<WithoutArgs<MarkerParser>>,
|
||||
Single<WithoutArgs<MayDangleParser>>,
|
||||
Single<WithoutArgs<NeedsAllocatorParser>>,
|
||||
Single<WithoutArgs<NeedsPanicRuntimeParser>>,
|
||||
Single<WithoutArgs<NoBuiltinsParser>>,
|
||||
Single<WithoutArgs<NoCoreParser>>,
|
||||
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
||||
Single<WithoutArgs<NoLinkParser>>,
|
||||
Single<WithoutArgs<NoMainParser>>,
|
||||
Single<WithoutArgs<NoMangleParser>>,
|
||||
Single<WithoutArgs<NoStdParser>>,
|
||||
Single<WithoutArgs<NonExhaustiveParser>>,
|
||||
Single<WithoutArgs<PanicHandlerParser>>,
|
||||
Single<WithoutArgs<PanicRuntimeParser>>,
|
||||
Single<WithoutArgs<ParenSugarParser>>,
|
||||
Single<WithoutArgs<PassByValueParser>>,
|
||||
Single<WithoutArgs<PinV2Parser>>,
|
||||
Single<WithoutArgs<PointeeParser>>,
|
||||
Single<WithoutArgs<PreludeImportParser>>,
|
||||
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
||||
Single<WithoutArgs<ProcMacroParser>>,
|
||||
Single<WithoutArgs<ProfilerRuntimeParser>>,
|
||||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorParser>>,
|
||||
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
|
||||
Single<WithoutArgs<RustcCaptureAnalysisParser>>,
|
||||
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
||||
Single<WithoutArgs<RustcConversionSuggestionParser>>,
|
||||
Single<WithoutArgs<RustcDeallocatorParser>>,
|
||||
Single<WithoutArgs<RustcDelayedBugFromInsideQueryParser>>,
|
||||
Single<WithoutArgs<RustcDoNotConstCheckParser>>,
|
||||
Single<WithoutArgs<RustcDumpDefParentsParser>>,
|
||||
Single<WithoutArgs<RustcDumpItemBoundsParser>>,
|
||||
Single<WithoutArgs<RustcDumpPredicatesParser>>,
|
||||
Single<WithoutArgs<RustcDumpUserArgsParser>>,
|
||||
Single<WithoutArgs<RustcDumpVtableParser>>,
|
||||
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
|
||||
Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
|
||||
Single<WithoutArgs<RustcDumpDefParents>>,
|
||||
Single<WithoutArgs<RustcDumpItemBounds>>,
|
||||
Single<WithoutArgs<RustcDumpPredicates>>,
|
||||
Single<WithoutArgs<RustcDumpUserArgs>>,
|
||||
Single<WithoutArgs<RustcDumpVtable>>,
|
||||
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
||||
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
|
||||
Single<WithoutArgs<RustcInsignificantDtorParser>>,
|
||||
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
|
||||
Single<WithoutArgs<RustcIntrinsicParser>>,
|
||||
Single<WithoutArgs<RustcLintDiagnosticsParser>>,
|
||||
Single<WithoutArgs<RustcLintOptTyParser>>,
|
||||
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
|
||||
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
|
||||
Single<WithoutArgs<RustcMainParser>>,
|
||||
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
|
||||
Single<WithoutArgs<RustcNoMirInlineParser>>,
|
||||
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
|
||||
Single<WithoutArgs<RustcNonnullOptimizationGuaranteedParser>>,
|
||||
Single<WithoutArgs<RustcNounwindParser>>,
|
||||
Single<WithoutArgs<RustcObjectLifetimeDefaultParser>>,
|
||||
Single<WithoutArgs<RustcOffloadKernelParser>>,
|
||||
Single<WithoutArgs<RustcOutlivesParser>>,
|
||||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||
Single<WithoutArgs<RustcPreserveUbChecksParser>>,
|
||||
Single<WithoutArgs<RustcProcMacroDeclsParser>>,
|
||||
Single<WithoutArgs<RustcReallocatorParser>>,
|
||||
Single<WithoutArgs<RustcRegionsParser>>,
|
||||
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
||||
Single<WithoutArgs<RustcStrictCoherenceParser>>,
|
||||
Single<WithoutArgs<RustcTrivialFieldReadsParser>>,
|
||||
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
|
||||
Single<WithoutArgs<RustcVarianceParser>>,
|
||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||
Single<WithoutArgs<StdInternalSymbolParser>>,
|
||||
Single<WithoutArgs<ThreadLocalParser>>,
|
||||
Single<WithoutArgs<TrackCallerParser>>,
|
||||
Single<WithoutArgs<TypeConstParser>>,
|
||||
Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
|
@ -381,7 +358,7 @@ impl Stage for Late {
|
|||
}
|
||||
|
||||
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) {
|
||||
if !matches!(
|
||||
self.stage.should_emit(),
|
||||
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||
) {
|
||||
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 {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_integer_literal_in_range(
|
||||
&self,
|
||||
span: Span,
|
||||
lower_bound: isize,
|
||||
upper_bound: isize,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
AttributeParseErrorReason::ExpectedIntegerLiteralInRange { lower_bound, upper_bound },
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
|
||||
let span = match args {
|
||||
ArgParser::NoArgs => span,
|
||||
|
|
@ -770,18 +730,9 @@ pub enum ShouldEmit {
|
|||
EarlyFatal { also_emit_lints: bool },
|
||||
/// The operation will emit errors and lints.
|
||||
/// This is usually what you need.
|
||||
ErrorsAndLints {
|
||||
/// Whether [`ArgParser`] will attempt to recover from errors.
|
||||
///
|
||||
/// 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`.
|
||||
ErrorsAndLints,
|
||||
/// The operation will emit *not* errors and lints.
|
||||
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
|
||||
Nothing,
|
||||
}
|
||||
|
||||
|
|
@ -790,7 +741,7 @@ impl ShouldEmit {
|
|||
match self {
|
||||
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
|
||||
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
|
||||
ShouldEmit::ErrorsAndLints { .. } => diag.emit(),
|
||||
ShouldEmit::ErrorsAndLints => diag.emit(),
|
||||
ShouldEmit::Nothing => diag.delay_as_bug(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_session::Session;
|
|||
use rustc_session::lint::{BuiltinLintDiag, LintId};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
||||
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
|
||||
use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
|
||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
||||
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
||||
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 early_parsed_state = EarlyParsedState::default();
|
||||
|
||||
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
|
||||
|
||||
for attr in attrs {
|
||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||
if let Some(expected) = self.parse_only {
|
||||
|
|
@ -327,7 +325,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
let parts =
|
||||
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(
|
||||
args,
|
||||
&parts,
|
||||
|
|
@ -368,26 +366,26 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span,
|
||||
inner_span: lower_span(n.item.span()),
|
||||
attr_style: attr.style,
|
||||
parsed_description: ParsedDescription::Attribute,
|
||||
template: &accept.template,
|
||||
attr_path: attr_path.clone(),
|
||||
};
|
||||
for accept in accepts {
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span,
|
||||
inner_span: lower_span(n.item.span()),
|
||||
attr_style: attr.style,
|
||||
parsed_description: ParsedDescription::Attribute,
|
||||
template: &accept.template,
|
||||
attr_path: attr_path.clone(),
|
||||
};
|
||||
|
||||
(accept.accept_fn)(&mut cx, &args);
|
||||
finalizers.push(&accept.finalizer);
|
||||
|
||||
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||
(accept.accept_fn)(&mut cx, &args);
|
||||
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If we're here, we must be compiling a tool attribute... Or someone
|
||||
|
|
@ -419,7 +417,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
}
|
||||
|
||||
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 {
|
||||
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
|
||||
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 interface::AttributeParser;
|
||||
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_hir::{self as hir, AttrPath};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr};
|
||||
use rustc_session::errors::create_lit_error;
|
||||
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
|
||||
use rustc_session::errors::{create_lit_error, report_lit_error};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
|
@ -113,29 +113,16 @@ impl ArgParser {
|
|||
Some(match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
AttrArgs::Delimited(args) => {
|
||||
// Diagnostic attributes can't error if they encounter non meta item syntax.
|
||||
// However, the current syntax for diagnostic attributes is meta item syntax.
|
||||
// Therefore we can substitute with a dummy value on invalid syntax.
|
||||
if matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
|
||||
match MetaItemListParser::new(
|
||||
&args.tokens,
|
||||
args.dspan.entire(),
|
||||
psess,
|
||||
ShouldEmit::ErrorsAndLints { 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 {
|
||||
sub_parsers: ThinVec::new(),
|
||||
span: args.dspan.entire(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
// The arguments of rustc_dummy and diagnostic::do_not_recommend are not validated
|
||||
// if the arguments are delimited.
|
||||
// See https://doc.rust-lang.org/reference/attributes/diagnostics.html#r-attributes.diagnostic.namespace.unknown-invalid-syntax
|
||||
if parts == &[sym::rustc_dummy]
|
||||
|| parts == &[sym::diagnostic, sym::do_not_recommend]
|
||||
{
|
||||
return Some(ArgParser::List(MetaItemListParser {
|
||||
sub_parsers: ThinVec::new(),
|
||||
span: args.dspan.entire(),
|
||||
}));
|
||||
}
|
||||
|
||||
if args.delim != Delimiter::Parenthesis {
|
||||
|
|
@ -154,9 +141,7 @@ impl ArgParser {
|
|||
}
|
||||
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
||||
eq_span: *eq_span,
|
||||
value: expr_to_lit(psess, &expr, expr.span, should_emit)
|
||||
.map_err(|e| should_emit.emit_err(e))
|
||||
.ok()??,
|
||||
value: expr_to_lit(psess, &expr, expr.span, should_emit)?,
|
||||
value_span: expr.span,
|
||||
}),
|
||||
})
|
||||
|
|
@ -351,56 +336,58 @@ impl NameValueParser {
|
|||
}
|
||||
}
|
||||
|
||||
fn expr_to_lit<'sess>(
|
||||
psess: &'sess ParseSess,
|
||||
fn expr_to_lit(
|
||||
psess: &ParseSess,
|
||||
expr: &Expr,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
) -> PResult<'sess, Option<MetaItemLit>> {
|
||||
) -> Option<MetaItemLit> {
|
||||
if let ExprKind::Lit(token_lit) = expr.kind {
|
||||
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
|
||||
match res {
|
||||
Ok(lit) => {
|
||||
if token_lit.suffix.is_some() {
|
||||
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
|
||||
should_emit.emit_err(
|
||||
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
None
|
||||
} else {
|
||||
if lit.kind.is_unsuffixed() {
|
||||
Ok(Some(lit))
|
||||
} else {
|
||||
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
|
||||
if !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
should_emit.emit_err(
|
||||
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
}
|
||||
|
||||
Some(lit)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let err = create_lit_error(psess, err, token_lit, expr.span);
|
||||
if matches!(
|
||||
should_emit,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
|
||||
) {
|
||||
Err(err)
|
||||
} else {
|
||||
let lit = MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::Err(err.emit()),
|
||||
span: expr.span,
|
||||
};
|
||||
Ok(Some(lit))
|
||||
}
|
||||
let guar = report_lit_error(psess, err, token_lit, expr.span);
|
||||
let lit = MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::Err(guar),
|
||||
span: expr.span,
|
||||
};
|
||||
Some(lit)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if matches!(should_emit, ShouldEmit::Nothing) {
|
||||
return Ok(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
// Example cases:
|
||||
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
|
||||
// - `#[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 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() {
|
||||
// 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 });
|
||||
if matches!(
|
||||
self.should_emit,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
|
||||
) {
|
||||
return Err(err);
|
||||
} else {
|
||||
self.should_emit.emit_err(err)
|
||||
};
|
||||
self.should_emit.emit_err(
|
||||
self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(lit)
|
||||
|
|
@ -575,10 +556,6 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
|||
should_emit: ShouldEmit,
|
||||
) -> PResult<'sess, MetaItemListParser> {
|
||||
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 };
|
||||
|
||||
// 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_target::spec::TargetTuple;
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("invalid predicate `{$predicate}`", code = E0537)]
|
||||
#[diag(attr_parsing_invalid_predicate, code = E0537)]
|
||||
pub(crate) struct InvalidPredicate {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -21,7 +23,7 @@ pub(crate) struct InvalidPredicate {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("{$attr_str} attribute cannot have empty value")]
|
||||
#[diag(attr_parsing_doc_alias_empty)]
|
||||
pub(crate) struct DocAliasEmpty<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -29,7 +31,7 @@ pub(crate) struct DocAliasEmpty<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("{$char_} character isn't allowed in {$attr_str}")]
|
||||
#[diag(attr_parsing_doc_alias_bad_char)]
|
||||
pub(crate) struct DocAliasBadChar<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -38,7 +40,7 @@ pub(crate) struct DocAliasBadChar<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("{$attr_str} cannot start or end with ' '")]
|
||||
#[diag(attr_parsing_doc_alias_start_end)]
|
||||
pub(crate) struct DocAliasStartEnd<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -46,16 +48,7 @@ pub(crate) struct DocAliasStartEnd<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[{$name})]` is missing a `{$field}` argument")]
|
||||
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")]
|
||||
#[diag(attr_parsing_doc_attr_not_crate_level)]
|
||||
pub(crate) struct DocAttrNotCrateLevel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -63,8 +56,8 @@ pub(crate) struct DocAttrNotCrateLevel {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("nonexistent keyword `{$keyword}` used in `#[doc(keyword = \"...\")]`")]
|
||||
#[help("only existing keywords are allowed in core/std")]
|
||||
#[diag(attr_parsing_doc_keyword_not_keyword)]
|
||||
#[help]
|
||||
pub(crate) struct DocKeywordNotKeyword {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -72,8 +65,8 @@ pub(crate) struct DocKeywordNotKeyword {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = \"...\")]`")]
|
||||
#[help("only existing builtin attributes are allowed in core/std")]
|
||||
#[diag(attr_parsing_doc_attribute_not_attribute)]
|
||||
#[help]
|
||||
pub(crate) struct DocAttributeNotAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -81,28 +74,28 @@ pub(crate) struct DocAttributeNotAttribute {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("missing 'since'", code = E0542)]
|
||||
#[diag(attr_parsing_missing_since, code = E0542)]
|
||||
pub(crate) struct MissingSince {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("missing 'note'", code = E0543)]
|
||||
#[diag(attr_parsing_missing_note, code = E0543)]
|
||||
pub(crate) struct MissingNote {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("multiple stability levels", code = E0544)]
|
||||
#[diag(attr_parsing_multiple_stability_levels, code = E0544)]
|
||||
pub(crate) struct MultipleStabilityLevels {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -115,31 +108,31 @@ pub(crate) struct InvalidIssueString {
|
|||
// translatable.
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvalidIssueStringCause {
|
||||
#[label("`issue` must not be \"0\", use \"none\" instead")]
|
||||
#[label(attr_parsing_must_not_be_zero)]
|
||||
MustNotBeZero {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label("cannot parse integer from empty string")]
|
||||
#[label(attr_parsing_empty)]
|
||||
Empty {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label("invalid digit found in string")]
|
||||
#[label(attr_parsing_invalid_digit)]
|
||||
InvalidDigit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label("number too large to fit in target type")]
|
||||
#[label(attr_parsing_pos_overflow)]
|
||||
PosOverflow {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label("number too small to fit in target type")]
|
||||
#[label(attr_parsing_neg_overflow)]
|
||||
NegOverflow {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -160,21 +153,21 @@ impl InvalidIssueStringCause {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("missing 'feature'", code = E0546)]
|
||||
#[diag(attr_parsing_missing_feature, code = E0546)]
|
||||
pub(crate) struct MissingFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("'feature' is not an identifier", code = E0546)]
|
||||
#[diag(attr_parsing_non_ident_feature, code = E0546)]
|
||||
pub(crate) struct NonIdentFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("missing 'issue'", code = E0547)]
|
||||
#[diag(attr_parsing_missing_issue, code = E0547)]
|
||||
pub(crate) struct MissingIssue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -183,20 +176,20 @@ pub(crate) struct MissingIssue {
|
|||
// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
|
||||
// It is more similar to `IncorrectReprFormatGeneric`.
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -205,7 +198,7 @@ pub(crate) struct InvalidReprHintNoParen {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -214,19 +207,15 @@ pub(crate) struct InvalidReprHintNoValue {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
#[suggestion(
|
||||
"supply an argument here",
|
||||
code = "align(...)",
|
||||
applicability = "has-placeholders"
|
||||
)]
|
||||
#[suggestion(code = "align(...)", applicability = "has-placeholders")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -236,21 +225,21 @@ pub(crate) struct InvalidReprGeneric<'a> {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("incorrect `repr({$repr_arg})` attribute format", code = E0693)]
|
||||
#[diag(attr_parsing_incorrect_repr_format_generic, code = E0693)]
|
||||
pub(crate) struct IncorrectReprFormatGeneric {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -264,7 +253,7 @@ pub(crate) struct IncorrectReprFormatGeneric {
|
|||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum IncorrectReprFormatGenericCause {
|
||||
#[suggestion(
|
||||
"use parentheses instead",
|
||||
attr_parsing_suggestion,
|
||||
code = "{name}({value})",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
|
|
@ -280,7 +269,7 @@ pub(crate) enum IncorrectReprFormatGenericCause {
|
|||
},
|
||||
|
||||
#[suggestion(
|
||||
"use parentheses instead",
|
||||
attr_parsing_suggestion,
|
||||
code = "{name}({value})",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
|
|
@ -309,48 +298,48 @@ impl IncorrectReprFormatGenericCause {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("suggestions on deprecated items are unstable")]
|
||||
#[diag(attr_parsing_deprecated_item_suggestion)]
|
||||
pub(crate) struct DeprecatedItemSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[help("add `#![feature(deprecated_suggestion)]` to the crate root")]
|
||||
#[help]
|
||||
pub is_nightly: bool,
|
||||
|
||||
#[note("see #94785 for more details")]
|
||||
#[note]
|
||||
pub details: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected single version literal")]
|
||||
#[diag(attr_parsing_expected_single_version_literal)]
|
||||
pub(crate) struct ExpectedSingleVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected a version literal")]
|
||||
#[diag(attr_parsing_expected_version_literal)]
|
||||
pub(crate) struct ExpectedVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`{$name}` expects a list of feature names")]
|
||||
#[diag(attr_parsing_expects_feature_list)]
|
||||
pub(crate) struct ExpectsFeatureList {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -359,7 +348,7 @@ pub(crate) struct ExpectsFeatureList {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`{$name}` expects feature names")]
|
||||
#[diag(attr_parsing_expects_features)]
|
||||
pub(crate) struct ExpectsFeatures {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -368,21 +357,21 @@ pub(crate) struct ExpectsFeatures {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("'since' must be a Rust version number, such as \"1.31.0\"")]
|
||||
#[diag(attr_parsing_invalid_since)]
|
||||
pub(crate) struct InvalidSince {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`soft` should not have any arguments")]
|
||||
#[diag(attr_parsing_soft_no_args)]
|
||||
pub(crate) struct SoftNoArgs {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown version literal format, assuming it refers to a future version")]
|
||||
#[diag(attr_parsing_unknown_version_literal)]
|
||||
pub(crate) struct UnknownVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -390,83 +379,78 @@ pub(crate) struct UnknownVersionLiteral {
|
|||
|
||||
// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated.
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("multiple `{$name}` attributes")]
|
||||
#[diag(attr_parsing_unused_multiple)]
|
||||
pub(crate) struct UnusedMultiple {
|
||||
#[primary_span]
|
||||
#[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub this: Span,
|
||||
#[note("attribute also specified here")]
|
||||
#[note]
|
||||
pub other: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`export_name` may not contain null characters", code = E0648)]
|
||||
#[diag(attr_parsing_null_on_export, code = E0648)]
|
||||
pub(crate) struct NullOnExport {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`objc::class!` may not contain null characters")]
|
||||
#[diag(attr_parsing_null_on_objc_class)]
|
||||
pub(crate) struct NullOnObjcClass {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`objc::selector!` may not contain null characters")]
|
||||
#[diag(attr_parsing_null_on_objc_selector)]
|
||||
pub(crate) struct NullOnObjcSelector {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`objc::class!` expected a string literal")]
|
||||
#[diag(attr_parsing_objc_class_expected_string_literal)]
|
||||
pub(crate) struct ObjcClassExpectedStringLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`objc::selector!` expected a string literal")]
|
||||
#[diag(attr_parsing_objc_selector_expected_string_literal)]
|
||||
pub(crate) struct ObjcSelectorExpectedStringLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected at least one confusable name")]
|
||||
#[diag(attr_parsing_empty_confusables)]
|
||||
pub(crate) struct EmptyConfusables {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[help("`#[{$name}]` can {$only}be applied to {$applied}")]
|
||||
#[diag("`#[{$name}]` attribute cannot be used on {$target}")]
|
||||
#[help]
|
||||
#[diag(attr_parsing_invalid_target)]
|
||||
pub(crate) struct InvalidTarget {
|
||||
#[primary_span]
|
||||
#[suggestion(
|
||||
"remove the attribute",
|
||||
code = "",
|
||||
applicability = "machine-applicable",
|
||||
style = "tool-only"
|
||||
)]
|
||||
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
|
||||
pub span: Span,
|
||||
pub name: AttrPath,
|
||||
pub target: &'static str,
|
||||
|
|
@ -475,7 +459,7 @@ pub(crate) struct InvalidTarget {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("invalid alignment value: {$error_part}", code = E0589)]
|
||||
#[diag(attr_parsing_invalid_alignment_value, code = E0589)]
|
||||
pub(crate) struct InvalidAlignmentValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -483,49 +467,43 @@ pub(crate) struct InvalidAlignmentValue {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("meta item in `repr` must be an identifier", code = E0565)]
|
||||
#[diag(attr_parsing_repr_ident, code = E0565)]
|
||||
pub(crate) struct ReprIdent {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unrecognized representation hint", code = E0552)]
|
||||
#[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>"
|
||||
)]
|
||||
#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
|
||||
#[help]
|
||||
#[note]
|
||||
pub(crate) struct UnrecognizedReprHint {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("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]`"
|
||||
)]
|
||||
#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)]
|
||||
#[help]
|
||||
pub(crate) struct UnstableFeatureBoundIncompatibleStability {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("attribute incompatible with `#[unsafe(naked)]`", code = E0736)]
|
||||
#[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)]
|
||||
pub(crate) struct NakedFunctionIncompatibleAttribute {
|
||||
#[primary_span]
|
||||
#[label("the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label("function marked with `#[unsafe(naked)]` here")]
|
||||
#[label(attr_parsing_naked_attribute)]
|
||||
pub naked_span: Span,
|
||||
pub attr: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("ordinal value in `link_ordinal` is too large: `{$ordinal}`")]
|
||||
#[note("the value may not exceed `u16::MAX`")]
|
||||
#[diag(attr_parsing_link_ordinal_out_of_range)]
|
||||
#[note]
|
||||
pub(crate) struct LinkOrdinalOutOfRange {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -533,33 +511,20 @@ pub(crate) struct LinkOrdinalOutOfRange {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("element count in `rustc_scalable_vector` is too large: `{$n}`")]
|
||||
#[note("the value may not exceed `u16::MAX`")]
|
||||
#[diag(attr_parsing_rustc_scalable_vector_count_out_of_range)]
|
||||
#[note]
|
||||
pub(crate) struct RustcScalableVectorCountOutOfRange {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
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> {
|
||||
ExpectedNoArgs,
|
||||
ExpectedStringLiteral {
|
||||
byte_string: Option<Span>,
|
||||
},
|
||||
ExpectedFilenameLiteral,
|
||||
ExpectedIntegerLiteral,
|
||||
ExpectedIntegerLiteralInRange {
|
||||
lower_bound: isize,
|
||||
upper_bound: isize,
|
||||
},
|
||||
ExpectedAtLeastOneArgument,
|
||||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
|
|
@ -617,7 +582,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
if let Some(start_point_span) = byte_string {
|
||||
diag.span_suggestion(
|
||||
start_point_span,
|
||||
"consider removing the prefix",
|
||||
fluent::attr_parsing_unsupported_literal_suggestion,
|
||||
"",
|
||||
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");
|
||||
}
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedFilenameLiteral => {
|
||||
diag.span_label(self.span, "expected a filename string literal here");
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedIntegerLiteral => {
|
||||
diag.span_label(self.span, "expected an integer literal here");
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedIntegerLiteralInRange {
|
||||
lower_bound,
|
||||
upper_bound,
|
||||
} => {
|
||||
diag.span_label(
|
||||
self.span,
|
||||
format!(
|
||||
"expected an integer literal in the range of {lower_bound}..={upper_bound}"
|
||||
),
|
||||
);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedSingleArgument => {
|
||||
diag.span_label(self.span, "expected a single argument here");
|
||||
diag.code(E0805);
|
||||
|
|
@ -785,27 +736,30 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`{$name}` is not an unsafe attribute")]
|
||||
#[note("extraneous unsafe is not allowed in attributes")]
|
||||
#[diag(attr_parsing_invalid_attr_unsafe)]
|
||||
#[note]
|
||||
pub(crate) struct InvalidAttrUnsafe {
|
||||
#[primary_span]
|
||||
#[label("this is not an unsafe attribute")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub name: AttrPath,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unsafe attribute used without unsafe")]
|
||||
#[diag(attr_parsing_unsafe_attr_outside_unsafe)]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafe {
|
||||
#[primary_span]
|
||||
#[label("usage of unsafe attribute")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<UnsafeAttrOutsideUnsafeSuggestion>,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[suggestion_part(code = "unsafe(")]
|
||||
pub left: Span,
|
||||
|
|
@ -814,7 +768,7 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("wrong meta list delimiters")]
|
||||
#[diag(attr_parsing_meta_bad_delim)]
|
||||
pub(crate) struct MetaBadDelim {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -824,7 +778,7 @@ pub(crate) struct MetaBadDelim {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
"the delimiters should be `(` and `)`",
|
||||
attr_parsing_meta_bad_delim_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct MetaBadDelimSugg {
|
||||
|
|
@ -835,7 +789,7 @@ pub(crate) struct MetaBadDelimSugg {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected a literal (`1u8`, `1.0f32`, `\"string\"`, etc.) here, found {$descr}")]
|
||||
#[diag(attr_parsing_invalid_meta_item)]
|
||||
pub(crate) struct InvalidMetaItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -844,15 +798,12 @@ pub(crate) struct InvalidMetaItem {
|
|||
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
|
||||
#[subdiagnostic]
|
||||
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
|
||||
#[label("{$descr}s are not allowed here")]
|
||||
#[label]
|
||||
pub label: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
"surround the identifier with quotation marks to make it into a string literal",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
#[multipart_suggestion(attr_parsing_quote_ident_sugg, applicability = "machine-applicable")]
|
||||
pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
||||
#[suggestion_part(code = "\"")]
|
||||
pub before: Span,
|
||||
|
|
@ -861,80 +812,73 @@ pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
|||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
"negative numbers are not literals, try removing the `-` sign",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
#[multipart_suggestion(attr_parsing_remove_neg_sugg, applicability = "machine-applicable")]
|
||||
pub(crate) struct InvalidMetaItemRemoveNegSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub negative_sign: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("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.)"
|
||||
)]
|
||||
#[diag(attr_parsing_suffixed_literal_in_attribute)]
|
||||
#[help]
|
||||
pub(crate) struct SuffixedLiteralInAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("link name must not be empty", code = E0454)]
|
||||
#[diag(attr_parsing_empty_link_name, code = E0454)]
|
||||
pub(crate) struct EmptyLinkName {
|
||||
#[primary_span]
|
||||
#[label("empty link name")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`wasm_import_module` is incompatible with other arguments in `#[link]` attributes")]
|
||||
#[diag(attr_parsing_incompatible_wasm_link)]
|
||||
pub(crate) struct IncompatibleWasmLink {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[link]` attribute requires a `name = \"string\"` argument", code = E0459)]
|
||||
#[diag(attr_parsing_link_requires_name, code = E0459)]
|
||||
pub(crate) struct LinkRequiresName {
|
||||
#[primary_span]
|
||||
#[label("missing `name` argument")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols"
|
||||
)]
|
||||
#[diag(attr_parsing_invalid_link_modifier)]
|
||||
pub(crate) struct InvalidLinkModifier {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("multiple `{$modifier}` modifiers in a single `modifiers` argument")]
|
||||
#[diag(attr_parsing_multiple_modifiers)]
|
||||
pub(crate) struct MultipleModifiers {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -942,61 +886,52 @@ pub(crate) struct MultipleModifiers {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("import name type is only supported on x86")]
|
||||
#[diag(attr_parsing_import_name_type_x86)]
|
||||
pub(crate) struct ImportNameTypeX86 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("linking modifier `bundle` is only compatible with `static` linking kind")]
|
||||
#[diag(attr_parsing_bundle_needs_static)]
|
||||
pub(crate) struct BundleNeedsStatic {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("linking modifier `export-symbols` is only compatible with `static` linking kind")]
|
||||
pub(crate) struct ExportSymbolsNeedsStatic {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("linking modifier `whole-archive` is only compatible with `static` linking kind")]
|
||||
#[diag(attr_parsing_whole_archive_needs_static)]
|
||||
pub(crate) struct WholeArchiveNeedsStatic {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds"
|
||||
)]
|
||||
#[diag(attr_parsing_as_needed_compatibility)]
|
||||
pub(crate) struct AsNeededCompatibility {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`limit` must be a non-negative integer")]
|
||||
#[diag(attr_parsing_limit_invalid)]
|
||||
pub(crate) struct LimitInvalid<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label("{$error_str}")]
|
||||
#[label]
|
||||
pub value_span: Span,
|
||||
pub error_str: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("wrong `cfg_attr` delimiters")]
|
||||
#[diag(attr_parsing_cfg_attr_bad_delim)]
|
||||
pub(crate) struct CfgAttrBadDelim {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -1005,25 +940,14 @@ pub(crate) struct CfgAttrBadDelim {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of strings `#[doc(alias(\"a\", \"b\"))]`"
|
||||
)]
|
||||
#[diag(attr_parsing_doc_alias_malformed)]
|
||||
pub(crate) struct DocAliasMalformed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("definition of an unknown lang item: `{$name}`", code = E0522)]
|
||||
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}::*)]`")]
|
||||
#[diag(attr_parsing_unsupported_instruction_set)]
|
||||
pub(crate) struct UnsupportedInstructionSet<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ pub(crate) fn allowed_targets_applied(
|
|||
];
|
||||
const IMPL_LIKE: &[Target] =
|
||||
&[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();
|
||||
filter_targets(
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ polonius-engine = "0.13.0"
|
|||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_graphviz = { path = "../rustc_graphviz" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
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 borrow = |activation_location| BorrowData {
|
||||
|
||||
let borrow = BorrowData {
|
||||
kind,
|
||||
region,
|
||||
reserve_location: location,
|
||||
activation_location,
|
||||
activation_location: TwoPhaseActivation::NotTwoPhase,
|
||||
borrowed_place,
|
||||
assigned_place: *assigned_place,
|
||||
};
|
||||
let (idx, _) = self.location_map.insert_full(location, borrow);
|
||||
let idx = BorrowIndex::from(idx);
|
||||
|
||||
let idx = if !kind.is_two_phase_borrow() {
|
||||
debug!(" -> {:?}", location);
|
||||
let (idx, _) = self
|
||||
.location_map
|
||||
.insert_full(location, borrow(TwoPhaseActivation::NotTwoPhase));
|
||||
BorrowIndex::from(idx)
|
||||
} else {
|
||||
// When we encounter a 2-phase borrow statement, it will always
|
||||
// be assigning into a temporary TEMP:
|
||||
//
|
||||
// TEMP = &foo
|
||||
//
|
||||
// so extract `temp`.
|
||||
let Some(temp) = assigned_place.as_local() else {
|
||||
span_bug!(
|
||||
self.body.source_info(location).span,
|
||||
"expected 2-phase borrow to assign to a local, not `{:?}`",
|
||||
assigned_place,
|
||||
);
|
||||
};
|
||||
|
||||
// Consider the borrow not activated to start. When we find an activation, we'll update
|
||||
// this field.
|
||||
let (idx, _) = self
|
||||
.location_map
|
||||
.insert_full(location, borrow(TwoPhaseActivation::NotActivated));
|
||||
let idx = BorrowIndex::from(idx);
|
||||
|
||||
// Insert `temp` into the list of pending activations. From
|
||||
// now on, we'll be on the lookout for a use of it. Note that
|
||||
// we are guaranteed that this use will come after the
|
||||
// assignment.
|
||||
let prev = self.pending_activations.insert(temp, idx);
|
||||
assert_eq!(prev, None, "temporary associated with multiple two phase borrows");
|
||||
|
||||
idx
|
||||
};
|
||||
self.insert_as_pending_if_two_phase(location, assigned_place, kind, 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)
|
||||
}
|
||||
}
|
||||
|
||||
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::{Applicability, Diag, DiagCtxtHandle, struct_span_code_err};
|
||||
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 crate::MirBorrowckCtxt;
|
||||
use crate::region_infer::values::RegionElement;
|
||||
use crate::session_diagnostics::{
|
||||
HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
|
||||
};
|
||||
|
|
@ -48,12 +49,11 @@ impl<'tcx> UniverseInfo<'tcx> {
|
|||
UniverseInfo::RelateTys { expected, found }
|
||||
}
|
||||
|
||||
/// Report an error where an element erroneously made its way into `placeholder`.
|
||||
pub(crate) fn report_erroneous_element(
|
||||
&self,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
|
||||
placeholder: ty::PlaceholderRegion<'tcx>,
|
||||
error_element: Option<ty::PlaceholderRegion<'tcx>>,
|
||||
error_element: RegionElement<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
) {
|
||||
match *self {
|
||||
|
|
@ -146,14 +146,14 @@ pub(crate) trait TypeOpInfo<'tcx> {
|
|||
) -> Option<Diag<'infcx>>;
|
||||
|
||||
/// Constraints require that `error_element` appear in the
|
||||
/// values of `placeholder`, but this cannot be proven to
|
||||
/// values of `placeholder`, but this cannot be proven to
|
||||
/// hold. Report an error.
|
||||
#[instrument(level = "debug", skip(self, mbcx))]
|
||||
fn report_erroneous_element(
|
||||
&self,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
|
||||
placeholder: ty::PlaceholderRegion<'tcx>,
|
||||
error_element: Option<ty::PlaceholderRegion<'tcx>>,
|
||||
error_element: RegionElement<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
) {
|
||||
let tcx = mbcx.infcx.tcx;
|
||||
|
|
@ -169,20 +169,22 @@ pub(crate) trait TypeOpInfo<'tcx> {
|
|||
|
||||
let placeholder_region = ty::Region::new_placeholder(
|
||||
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,
|
||||
// and this method shouldn't do anything.
|
||||
let error_region = error_element.and_then(|e| {
|
||||
let adjusted_universe = e.universe.as_u32().checked_sub(base_universe.as_u32());
|
||||
adjusted_universe.map(|adjusted| {
|
||||
ty::Region::new_placeholder(
|
||||
tcx,
|
||||
ty::PlaceholderRegion::new(adjusted.into(), e.bound),
|
||||
)
|
||||
})
|
||||
});
|
||||
let error_region =
|
||||
if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
|
||||
let adjusted_universe =
|
||||
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
|
||||
adjusted_universe.map(|adjusted| {
|
||||
ty::Region::new_placeholder(
|
||||
tcx,
|
||||
ty::Placeholder::new(adjusted.into(), error_placeholder.bound),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
debug!(?placeholder_region);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
// ignore-tidy-filelength
|
||||
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
|
|
@ -1256,7 +1259,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning_inner(err, ty, expr);
|
||||
}
|
||||
} 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| {
|
||||
variant
|
||||
.fields
|
||||
|
|
@ -1266,50 +1269,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
{
|
||||
let ty_span = self.infcx.tcx.def_span(def.did());
|
||||
let mut span: MultiSpan = ty_span.into();
|
||||
let mut derive_clone = false;
|
||||
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(ty_span, "consider implementing `Clone` for this type");
|
||||
span.push_span_label(expr.span, "you could clone this value");
|
||||
err.span_note(span, msg);
|
||||
if derive_clone {
|
||||
err.help("consider manually implementing `Clone` to avoid undesired bounds");
|
||||
}
|
||||
err.span_note(
|
||||
span,
|
||||
format!("if `{ty}` implemented `Clone`, you could clone the value"),
|
||||
);
|
||||
} else if let ty::Param(param) = ty.kind()
|
||||
&& let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
|
||||
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
|
||||
|
|
@ -2347,12 +2312,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
tcx: TyCtxt<'hir>,
|
||||
issue_span: Span,
|
||||
expr_span: Span,
|
||||
body_expr: Option<&'hir hir::Expr<'hir>> = None,
|
||||
loop_bind: Option<&'hir Ident> = None,
|
||||
loop_span: Option<Span> = None,
|
||||
head_span: Option<Span> = None,
|
||||
pat_span: Option<Span> = None,
|
||||
head: Option<&'hir hir::Expr<'hir>> = None,
|
||||
body_expr: Option<&'hir hir::Expr<'hir>>,
|
||||
loop_bind: Option<&'hir Ident>,
|
||||
loop_span: Option<Span>,
|
||||
head_span: Option<Span>,
|
||||
pat_span: Option<Span>,
|
||||
head: Option<&'hir hir::Expr<'hir>>,
|
||||
}
|
||||
impl<'hir> Visitor<'hir> for ExprFinder<'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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
if let Some(body_expr) = finder.body_expr
|
||||
|
|
@ -2653,13 +2628,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
struct ExpressionFinder<'tcx> {
|
||||
capture_span: Span,
|
||||
closure_change_spans: Vec<Span> = vec![],
|
||||
closure_arg_span: Option<Span> = None,
|
||||
in_closure: bool = false,
|
||||
suggest_arg: String = String::new(),
|
||||
closure_change_spans: Vec<Span>,
|
||||
closure_arg_span: Option<Span>,
|
||||
in_closure: bool,
|
||||
suggest_arg: String,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
closure_local_id: Option<hir::HirId> = None,
|
||||
closure_call_changes: Vec<(Span, String)> = vec![],
|
||||
closure_local_id: Option<hir::HirId>,
|
||||
closure_call_changes: Vec<(Span, String)>,
|
||||
}
|
||||
impl<'hir> Visitor<'hir> for ExpressionFinder<'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())
|
||||
&& let hir::Node::Expr(expr) = self.infcx.tcx.hir_node(body_id.hir_id)
|
||||
{
|
||||
let mut finder =
|
||||
ExpressionFinder { capture_span: *capture_kind_span, tcx: self.infcx.tcx, .. };
|
||||
let mut finder = ExpressionFinder {
|
||||
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);
|
||||
|
||||
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.
|
||||
|
||||
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_hir as hir;
|
||||
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
|
||||
// ensure that we don't emit live boring locals as explanations.
|
||||
let is_local_boring = |local| {
|
||||
if let Some(polonius_context) = self.polonius_context {
|
||||
polonius_context.boring_nll_locals.contains(&local)
|
||||
if let Some(polonius_diagnostics) = self.polonius_diagnostics {
|
||||
polonius_diagnostics.boring_nll_locals.contains(&local)
|
||||
} else {
|
||||
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_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::{
|
||||
self as hir, CoroutineKind, GenericBound, LangItem, WhereBoundPredicate, WherePredicateKind,
|
||||
|
|
@ -35,6 +35,7 @@ use tracing::debug;
|
|||
use super::MirBorrowckCtxt;
|
||||
use super::borrow_set::BorrowData;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::nll::ConstraintDescription;
|
||||
use crate::session_diagnostics::{
|
||||
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) {
|
||||
if count > 10 {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||
}
|
||||
self.buffer_error(diag);
|
||||
|
|
@ -233,6 +236,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// LL | for (key, value) in dict {
|
||||
/// | ^^^^
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
pub(super) fn add_moved_or_invoked_closure_note(
|
||||
&self,
|
||||
location: Location,
|
||||
|
|
@ -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)
|
||||
.is_some()
|
||||
{
|
||||
diag.span_note(pred.span, LIMITATION_NOTE);
|
||||
diag.span_note(pred.span, fluent::borrowck_limitations_implies_static);
|
||||
return;
|
||||
}
|
||||
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)
|
||||
.is_some()
|
||||
{
|
||||
diag.span_note(bound.span, LIMITATION_NOTE);
|
||||
diag.span_note(bound.span, fluent::borrowck_limitations_implies_static);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -816,6 +820,7 @@ impl UseSpans<'_> {
|
|||
}
|
||||
|
||||
/// Add a span label to the arguments of the closure, if it exists.
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
|
||||
if let UseSpans::ClosureUse { args_span, .. } = self {
|
||||
err.subdiagnostic(f(args_span));
|
||||
|
|
@ -824,6 +829,7 @@ impl UseSpans<'_> {
|
|||
|
||||
/// Add a span label to the use of the captured variable, if it exists.
|
||||
/// only adds label to the `path_span`
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn var_path_only_subdiag(
|
||||
self,
|
||||
err: &mut Diag<'_>,
|
||||
|
|
@ -855,6 +861,7 @@ impl UseSpans<'_> {
|
|||
}
|
||||
|
||||
/// Add a subdiagnostic to the use of the captured variable, if it exists.
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn var_subdiag(
|
||||
self,
|
||||
err: &mut Diag<'_>,
|
||||
|
|
@ -1218,6 +1225,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.borrow_spans(span, borrow.reserve_location)
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn explain_captures(
|
||||
&mut self,
|
||||
err: &mut Diag<'infcx>,
|
||||
|
|
@ -1311,7 +1320,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let mut span: MultiSpan = spans.clone().into();
|
||||
err.arg("ty", param_ty.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.remove_arg("ty");
|
||||
|
|
@ -1320,9 +1329,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
span.push_span_label(
|
||||
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 {
|
||||
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('_'))
|
||||
}
|
||||
}
|
||||
|
||||
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_errors::{Applicability, Diag};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -8,7 +10,7 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
||||
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::infer::InferCtxtExt;
|
||||
use tracing::debug;
|
||||
|
|
@ -473,30 +475,49 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if def_id.as_local() == Some(self.mir_def_id())
|
||||
&& let Some(upvar_field) = upvar_field =>
|
||||
{
|
||||
self.report_closure_move_error(
|
||||
span,
|
||||
move_place,
|
||||
*def_id,
|
||||
closure_args.as_closure().kind_ty(),
|
||||
upvar_field,
|
||||
ty::Asyncness::No,
|
||||
)
|
||||
}
|
||||
ty::CoroutineClosure(def_id, closure_args)
|
||||
if def_id.as_local() == Some(self.mir_def_id())
|
||||
&& let Some(upvar_field) = upvar_field
|
||||
&& self
|
||||
.get_closure_bound_clause_span(*def_id, ty::Asyncness::Yes)
|
||||
.is_some() =>
|
||||
{
|
||||
self.report_closure_move_error(
|
||||
span,
|
||||
move_place,
|
||||
*def_id,
|
||||
closure_args.as_coroutine_closure().kind_ty(),
|
||||
upvar_field,
|
||||
ty::Asyncness::Yes,
|
||||
)
|
||||
let closure_kind_ty = closure_args.as_closure().kind_ty();
|
||||
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 capture_description =
|
||||
format!("captured variable in an `{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!(
|
||||
"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",
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let source = self.borrowed_content_source(deref_base);
|
||||
|
|
@ -545,134 +566,45 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
err
|
||||
}
|
||||
|
||||
fn report_closure_move_error(
|
||||
&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> {
|
||||
fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
|
||||
let tcx = self.infcx.tcx;
|
||||
let typeck_result = tcx.typeck(self.mir_def_id());
|
||||
// Check whether the closure is an argument to a call, if so,
|
||||
// get the instantiated where-bounds of that call.
|
||||
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 {
|
||||
hir::ExprKind::Call(callee, _) => {
|
||||
let ty = typeck_result.node_type_opt(callee.hir_id)?;
|
||||
let ty::FnDef(fn_def_id, args) = ty.kind() else { return None };
|
||||
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 DUMMY_SP };
|
||||
tcx.predicates_of(fn_def_id).instantiate(tcx, args)
|
||||
}
|
||||
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);
|
||||
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]`
|
||||
// or `AsyncFn[Mut]`.
|
||||
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`.
|
||||
for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
|
||||
let dominated_by_fn_trait = self
|
||||
.closure_clause_kind(*pred, def_id, asyncness)
|
||||
.is_some_and(|kind| matches!(kind, ty::ClosureKind::Fn | ty::ClosureKind::FnMut));
|
||||
if dominated_by_fn_trait {
|
||||
// Found `<TyOfCapturingClosure as FnMut>` or
|
||||
// `<TyOfCapturingClosure as AsyncFnMut>`.
|
||||
// We point at the bound that coerced the closure, which could be changed
|
||||
// to `FnOnce()` or `AsyncFnOnce()` to avoid the move error.
|
||||
return Some(*span);
|
||||
if let Some(clause) = pred.as_trait_clause()
|
||||
&& let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
|
||||
&& *clause_closure_def_id == def_id
|
||||
&& (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
|
||||
|| tcx.lang_items().fn_trait() == Some(clause.def_id()))
|
||||
{
|
||||
// Found `<TyOfCapturingClosure as FnMut>`
|
||||
// We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
|
||||
// could be changed to `FnOnce()` to avoid the move error.
|
||||
return *span;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
DUMMY_SP
|
||||
}
|
||||
|
||||
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 either::Either;
|
||||
|
|
@ -354,71 +357,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
|
||||
{
|
||||
if snippet.starts_with("&mut ") {
|
||||
// In calls, `&mut &mut T` may be deref-coerced to `&mut T`, and
|
||||
// removing the extra `&mut` is the most direct suggestion. But for
|
||||
// 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(
|
||||
source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
|
||||
"if there is only one mutable reborrow, remove the `&mut`",
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
// 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(
|
||||
source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
|
||||
"if there is only one mutable reborrow, remove the `&mut`",
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
// This can occur with things like `(&mut self).foo()`.
|
||||
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 StatementKind::Assign(box (_, rvalue_new)) = &rhs_stmt_new.kind
|
||||
&& 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use either::Either;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
|
||||
//! outlives constraints.
|
||||
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Error reporting machinery for lifetime errors.
|
||||
|
||||
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::GenericBound::Trait;
|
||||
use rustc_hir::QPath::Resolved;
|
||||
|
|
@ -27,15 +27,16 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
|||
use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::{LIMITATION_NOTE, OutlivesSuggestionBuilder, RegionName, RegionNameSource};
|
||||
use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
|
||||
use crate::nll::ConstraintDescription;
|
||||
use crate::region_infer::values::RegionElement;
|
||||
use crate::region_infer::{BlameConstraint, TypeTest};
|
||||
use crate::session_diagnostics::{
|
||||
FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
|
||||
LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
|
||||
};
|
||||
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> {
|
||||
fn description(&self) -> &'static str {
|
||||
|
|
@ -103,9 +104,15 @@ pub(crate) enum RegionErrorKind<'tcx> {
|
|||
/// A generic bound failure for a type test (`T: 'a`).
|
||||
TypeTestError { type_test: TypeTest<'tcx> },
|
||||
|
||||
/// 'p outlives 'r, which does not hold. 'p is always a placeholder
|
||||
/// and 'r is some other region.
|
||||
PlaceholderOutlivesIllegalRegion { longer_fr: RegionVid, illegally_outlived_r: RegionVid },
|
||||
/// Higher-ranked subtyping error.
|
||||
BoundUniversalRegionError {
|
||||
/// 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.
|
||||
RegionError {
|
||||
|
|
@ -189,6 +196,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// For generic associated types (GATs) which implied 'static requirement
|
||||
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait
|
||||
// and the span which bounded to the trait for adding 'static lifetime suggestion
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
fn suggest_static_lifetime_for_gat_from_hrtb(
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
|
|
@ -258,7 +266,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }) = bound else {
|
||||
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())
|
||||
else {
|
||||
return;
|
||||
|
|
@ -291,7 +299,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if suggestions.len() > 0 {
|
||||
suggestions.dedup();
|
||||
diag.multipart_suggestion_verbose(
|
||||
msg!("consider restricting the type parameter to the `'static` lifetime"),
|
||||
fluent::borrowck_restrict_to_static,
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -353,11 +361,28 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
RegionErrorKind::PlaceholderOutlivesIllegalRegion {
|
||||
RegionErrorKind::BoundUniversalRegionError {
|
||||
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 } => {
|
||||
|
|
@ -388,43 +413,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
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
|
||||
/// `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`.
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub(crate) fn report_region_error(
|
||||
&mut self,
|
||||
fr: RegionVid,
|
||||
|
|
@ -586,6 +577,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// executing...
|
||||
/// = note: ...therefore, returned references to captured variables will escape the closure
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
fn report_fnmut_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo<'tcx>,
|
||||
|
|
@ -694,12 +686,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
|
||||
|
||||
if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.span_label(
|
||||
outlived_fr_span,
|
||||
format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
|
||||
diag.span_label(
|
||||
fr_span,
|
||||
|
|
@ -734,6 +732,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
|
||||
outlived_fr_region_name.highlight_region_name(&mut diag);
|
||||
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!(
|
||||
|
|
@ -765,6 +766,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
|
||||
/// | is returning data with lifetime `'b`
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
|
||||
let ErrorConstraintInfo { fr, outlived_fr, span, category, .. } = errci;
|
||||
|
||||
|
|
@ -822,6 +824,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn add_static_impl_trait_suggestion(
|
||||
&self,
|
||||
diag: &mut Diag<'_>,
|
||||
|
|
@ -885,7 +889,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
for alias_ty in alias_tys {
|
||||
if alias_ty.span.desugaring_kind().is_some() {
|
||||
// Skip `async` desugaring `impl Future`.
|
||||
continue;
|
||||
}
|
||||
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
|
||||
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);
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[instrument(skip(self, err), level = "debug")]
|
||||
fn suggest_constrain_dyn_trait_in_impl(
|
||||
&self,
|
||||
|
|
@ -980,18 +984,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
debug!("trait spans found: {:?}", traits);
|
||||
for span in &traits {
|
||||
let mut multi_span: MultiSpan = vec![*span].into();
|
||||
multi_span.push_span_label(
|
||||
*span,
|
||||
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"),
|
||||
);
|
||||
multi_span.push_span_label(*span, fluent::borrowck_implicit_static);
|
||||
multi_span.push_span_label(ident.span, fluent::borrowck_implicit_static_introduced);
|
||||
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
msg!("consider relaxing the implicit `'static` requirement"),
|
||||
fluent::borrowck_implicit_static_relax,
|
||||
" + '_",
|
||||
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
|
||||
/// corresponding trait bound and see if dereferencing the closure return value would satisfy
|
||||
/// 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 {
|
||||
diag.span_suggestion_verbose(
|
||||
tcx.hir_body(*body).value.peel_blocks().span.shrink_to_lo(),
|
||||
msg!("dereference the return value"),
|
||||
fluent::borrowck_dereference_suggestion,
|
||||
"*".repeat(count),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
|
||||
let body = self.infcx.tcx.hir_body_owned_by(self.mir_def_id());
|
||||
let expr = &body.value.peel_blocks();
|
||||
|
|
@ -1198,7 +1198,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if let Some(closure_span) = closure_span {
|
||||
diag.span_suggestion_verbose(
|
||||
closure_span,
|
||||
msg!("consider adding 'move' keyword before the nested closure"),
|
||||
fluent::borrowck_move_closure_suggestion,
|
||||
"move ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::fmt::{self, Display};
|
||||
use std::iter;
|
||||
|
||||
|
|
|
|||
|
|
@ -62,23 +62,57 @@ impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||
struct PlaceholderReachability {
|
||||
/// The largest-universed placeholder we can reach
|
||||
max_universe: (UniverseIndex, RegionVid),
|
||||
enum PlaceholderReachability {
|
||||
/// This SCC reaches no placeholders.
|
||||
NoPlaceholders,
|
||||
/// This SCC reaches at least one placeholder.
|
||||
Placeholders {
|
||||
/// The largest-universed placeholder we can reach
|
||||
max_universe: (UniverseIndex, RegionVid),
|
||||
|
||||
/// The placeholder with the smallest ID
|
||||
min_placeholder: RegionVid,
|
||||
/// The placeholder with the smallest ID
|
||||
min_placeholder: RegionVid,
|
||||
|
||||
/// The placeholder with the largest ID
|
||||
max_placeholder: RegionVid,
|
||||
/// The placeholder with the largest ID
|
||||
max_placeholder: RegionVid,
|
||||
},
|
||||
}
|
||||
|
||||
impl PlaceholderReachability {
|
||||
/// Merge the reachable placeholders of two graph components.
|
||||
fn merge(&mut self, other: &Self) {
|
||||
self.max_universe = self.max_universe.max(other.max_universe);
|
||||
self.min_placeholder = self.min_placeholder.min(other.min_placeholder);
|
||||
self.max_placeholder = self.max_placeholder.max(other.max_placeholder);
|
||||
fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability {
|
||||
use PlaceholderReachability::*;
|
||||
match (self, other) {
|
||||
(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.
|
||||
#[derive(Copy, Debug, Clone)]
|
||||
pub(crate) struct RegionTracker {
|
||||
reachable_placeholders: Option<PlaceholderReachability>,
|
||||
reachable_placeholders: PlaceholderReachability,
|
||||
|
||||
/// The largest universe nameable from this SCC.
|
||||
/// It is the smallest nameable universes of all
|
||||
|
|
@ -101,13 +135,13 @@ impl RegionTracker {
|
|||
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
|
||||
let reachable_placeholders =
|
||||
if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
|
||||
Some(PlaceholderReachability {
|
||||
PlaceholderReachability::Placeholders {
|
||||
max_universe: (definition.universe, rvid),
|
||||
min_placeholder: rvid,
|
||||
max_placeholder: rvid,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
None
|
||||
PlaceholderReachability::NoPlaceholders
|
||||
};
|
||||
|
||||
Self {
|
||||
|
|
@ -125,46 +159,43 @@ impl RegionTracker {
|
|||
}
|
||||
|
||||
pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
|
||||
self.reachable_placeholders.map(|pls| pls.max_universe.0).unwrap_or(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))
|
||||
if let Some((universe, _)) = self.reachable_placeholders.max_universe() {
|
||||
universe
|
||||
} else {
|
||||
UniverseIndex::ROOT
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine if we can name all the placeholders in `other`.
|
||||
pub(crate) fn can_name_all_placeholders(&self, other: Self) -> bool {
|
||||
// HACK: We first check whether we can name the highest existential universe
|
||||
// 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)
|
||||
other.reachable_placeholders.can_be_named_by(self.max_nameable_universe.0)
|
||||
}
|
||||
|
||||
/// If this SCC reaches a placeholder it can't name, return it.
|
||||
fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> {
|
||||
self.reachable_placeholders
|
||||
.filter(|pls| !self.max_nameable_universe().can_name(pls.max_universe.0))
|
||||
.map(|pls| pls.max_universe)
|
||||
self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| {
|
||||
!self.max_nameable_universe().can_name(placeholder_universe)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl scc::Annotation for RegionTracker {
|
||||
fn update_scc(&mut self, other: &Self) {
|
||||
fn merge_scc(self, other: Self) -> Self {
|
||||
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) {
|
||||
self.max_nameable_universe = self.max_nameable_universe.min(other.max_nameable_universe);
|
||||
match (self.reachable_placeholders.as_mut(), other.reachable_placeholders.as_ref()) {
|
||||
(None, None) | (Some(_), None) => (),
|
||||
(None, Some(theirs)) => self.reachable_placeholders = Some(*theirs),
|
||||
(Some(ours), Some(theirs)) => ours.merge(theirs),
|
||||
};
|
||||
fn merge_reached(self, other: Self) -> Self {
|
||||
Self {
|
||||
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
|
||||
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
|
||||
representative: self.representative,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(assert_matches))]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(default_field_values)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(negative_impls)]
|
||||
|
|
@ -63,10 +62,10 @@ use crate::diagnostics::{
|
|||
use crate::path_utils::*;
|
||||
use crate::place_ext::PlaceExt;
|
||||
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
||||
use crate::polonius::PoloniusContext;
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
};
|
||||
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
|
||||
use crate::prefixes::PrefixSet;
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
|
||||
|
|
@ -99,6 +98,8 @@ mod used_muts;
|
|||
/// A public API provided for the Rust compiler consumers.
|
||||
pub mod consumers;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
/// Associate some local constants with the `'tcx` lifetime
|
||||
struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
|
||||
|
||||
|
|
@ -121,11 +122,6 @@ fn mir_borrowck(
|
|||
let (input_body, _) = tcx.mir_promoted(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();
|
||||
if let Some(guar) = input_body.tainted_by_errors {
|
||||
debug!("Skipping borrowck because of tainted body");
|
||||
|
|
@ -424,7 +420,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
|||
polonius_output,
|
||||
opt_closure_req,
|
||||
nll_errors,
|
||||
polonius_context,
|
||||
polonius_diagnostics,
|
||||
} = nll::compute_regions(
|
||||
root_cx,
|
||||
&infcx,
|
||||
|
|
@ -448,7 +444,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
|||
®ioncx,
|
||||
&opt_closure_req,
|
||||
&borrow_set,
|
||||
polonius_context.as_ref(),
|
||||
polonius_diagnostics.as_ref(),
|
||||
);
|
||||
|
||||
// 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,
|
||||
move_errors: Vec::new(),
|
||||
diags_buffer,
|
||||
polonius_context: polonius_context.as_ref(),
|
||||
polonius_diagnostics: polonius_diagnostics.as_ref(),
|
||||
};
|
||||
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
|
||||
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
|
||||
|
|
@ -529,7 +525,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
|||
move_errors: Vec::new(),
|
||||
diags_buffer,
|
||||
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.
|
||||
|
|
@ -779,7 +775,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<&'a PoloniusOutput>,
|
||||
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
|
||||
polonius_context: Option<&'a PoloniusContext>,
|
||||
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
|
||||
}
|
||||
|
||||
// Check that:
|
||||
|
|
@ -1210,17 +1206,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
"access_place: suppressing error 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;
|
||||
}
|
||||
|
||||
|
|
@ -1316,7 +1301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
(Read(kind), BorrowKind::Mut { .. }) => {
|
||||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(this.dominators(), borrow, location) {
|
||||
assert!(borrow.kind.is_two_phase_borrow());
|
||||
assert!(borrow.kind.allows_two_phase_borrow());
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
|
|
@ -1479,7 +1464,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if bk.is_two_phase_borrow() {
|
||||
if bk.allows_two_phase_borrow() {
|
||||
(Deep, Reservation(wk))
|
||||
} else {
|
||||
(Deep, Write(wk))
|
||||
|
|
@ -1544,7 +1529,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
Rvalue::Use(operand)
|
||||
| Rvalue::Repeat(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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ use std::str::FromStr;
|
|||
|
||||
use polonius_engine::{Algorithm, AllFacts, Output};
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::mir::pretty::PrettyPrintMirOptions;
|
||||
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::points::DenseLocationMap;
|
||||
use rustc_session::config::MirIncludeSpans;
|
||||
use rustc_span::sym;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::consumers::RustcFacts;
|
||||
use crate::diagnostics::RegionErrors;
|
||||
use crate::handle_placeholders::compute_sccs_applying_placeholder_outlives_constraints;
|
||||
use crate::polonius::PoloniusContext;
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
};
|
||||
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::type_check::MirTypeckRegionConstraints;
|
||||
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.
|
||||
/// 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
|
||||
|
|
@ -122,7 +121,7 @@ pub(crate) fn compute_regions<'tcx>(
|
|||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
mut polonius_facts: Option<AllFacts<RustcFacts>>,
|
||||
mut polonius_context: Option<PoloniusContext>,
|
||||
polonius_context: Option<PoloniusContext>,
|
||||
) -> NllOutput<'tcx> {
|
||||
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();
|
||||
|
|
@ -154,9 +153,9 @@ pub(crate) fn compute_regions<'tcx>(
|
|||
|
||||
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
|
||||
// and use them to compute loan liveness.
|
||||
if let Some(polonius_context) = polonius_context.as_mut() {
|
||||
polonius_context.compute_loan_liveness(&mut regioncx, body, borrow_set)
|
||||
}
|
||||
let polonius_diagnostics = polonius_context.map(|polonius_context| {
|
||||
polonius_context.compute_loan_liveness(infcx.tcx, &mut regioncx, body, borrow_set)
|
||||
});
|
||||
|
||||
// If requested: dump NLL facts, and run legacy polonius analysis.
|
||||
let polonius_output = polonius_facts.as_ref().and_then(|polonius_facts| {
|
||||
|
|
@ -189,7 +188,7 @@ pub(crate) fn compute_regions<'tcx>(
|
|||
polonius_output,
|
||||
opt_closure_req: closure_region_requirements,
|
||||
nll_errors,
|
||||
polonius_context,
|
||||
polonius_diagnostics,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -231,13 +230,13 @@ pub(super) fn dump_nll_mir<'tcx>(
|
|||
dumper.dump_mir(body);
|
||||
|
||||
// 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)?;
|
||||
regioncx.dump_graphviz_raw_constraints(tcx, &mut 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)?;
|
||||
regioncx.dump_graphviz_scc_constraints(tcx, &mut file)?;
|
||||
};
|
||||
|
|
@ -288,6 +287,8 @@ pub(crate) fn emit_nll_mir<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub(super) fn dump_annotation<'tcx, 'infcx>(
|
||||
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
|
|
@ -296,7 +297,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
|||
) {
|
||||
let tcx = infcx.tcx;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_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,
|
||||
/// 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.
|
||||
|
|
@ -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
|
||||
/// variance.
|
||||
///
|
||||
/// The `source` origin at `from` flows into the `target` origin at `to`.
|
||||
///
|
||||
/// This dual of NLL's [crate::constraints::OutlivesConstraint] therefore encodes the
|
||||
/// position-dependent outlives constraints used by Polonius, to model the flow-sensitive loan
|
||||
/// propagation via reachability within a graph of localized constraints.
|
||||
///
|
||||
/// That `LocalizedConstraintGraph` can create these edges on-demand during traversal, and we
|
||||
/// therefore model them as a pair of `LocalizedNode` vertices.
|
||||
///
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(super) struct LocalizedNode {
|
||||
pub region: RegionVid,
|
||||
pub point: PointIndex,
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub(crate) struct LocalizedOutlivesConstraint {
|
||||
pub source: RegionVid,
|
||||
pub from: PointIndex,
|
||||
pub target: RegionVid,
|
||||
pub to: PointIndex,
|
||||
}
|
||||
|
||||
/// The localized constraint graph indexes the physical and logical edges to lazily compute a given
|
||||
/// node's successors during traversal.
|
||||
pub(super) struct LocalizedConstraintGraph {
|
||||
/// The actual, physical, edges we have recorded for a given node. We localize them on-demand
|
||||
/// when traversing from the node to the successor region.
|
||||
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>>,
|
||||
/// A container of [LocalizedOutlivesConstraint]s that can be turned into a traversable
|
||||
/// `rustc_data_structures` graph.
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub(crate) struct LocalizedOutlivesConstraintSet {
|
||||
pub outlives: Vec<LocalizedOutlivesConstraint>,
|
||||
}
|
||||
|
||||
/// The visitor interface when traversing a `LocalizedConstraintGraph`.
|
||||
pub(super) trait LocalizedConstraintGraphVisitor {
|
||||
/// Callback called when traversing a given `loan` encounters a localized `node` it hasn't
|
||||
/// visited before.
|
||||
fn on_node_traversed(&mut self, _loan: BorrowIndex, _node: LocalizedNode) {}
|
||||
|
||||
/// Callback called when discovering a new `successor` node for the `current_node`.
|
||||
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 })
|
||||
}
|
||||
impl LocalizedOutlivesConstraintSet {
|
||||
pub(crate) fn push(&mut self, constraint: LocalizedOutlivesConstraint) {
|
||||
if constraint.source == constraint.target && constraint.from == constraint.to {
|
||||
// 'a@p: 'a@p is pretty uninteresting
|
||||
return;
|
||||
}
|
||||
self.outlives.push(constraint);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ use rustc_session::config::MirIncludeSpans;
|
|||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::polonius::{LocalizedConstraintGraphVisitor, LocalizedNode, PoloniusContext};
|
||||
use crate::polonius::{
|
||||
LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet, PoloniusDiagnosticsContext,
|
||||
};
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
use crate::{BorrowckInferCtxt, ClosureRegionRequirements, RegionInferenceContext};
|
||||
|
|
@ -22,7 +24,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
polonius_context: Option<&PoloniusContext>,
|
||||
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
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 polonius_context =
|
||||
polonius_context.expect("missing polonius 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 polonius_diagnostics =
|
||||
polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`");
|
||||
|
||||
let extra_data = &|pass_where, out: &mut dyn io::Write| {
|
||||
emit_polonius_mir(
|
||||
|
|
@ -54,7 +42,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
regioncx,
|
||||
closure_region_requirements,
|
||||
borrow_set,
|
||||
&collector.constraints,
|
||||
&polonius_diagnostics.localized_outlives_constraints,
|
||||
pass_where,
|
||||
out,
|
||||
)
|
||||
|
|
@ -70,36 +58,19 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
|
||||
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)?;
|
||||
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 NLL MIR
|
||||
/// - the list of polonius localized constraints
|
||||
|
|
@ -111,7 +82,7 @@ fn emit_polonius_dump<'tcx>(
|
|||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
// Prepare the HTML dump file prologue.
|
||||
|
|
@ -222,7 +193,7 @@ fn emit_polonius_mir<'tcx>(
|
|||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
pass_where: PassWhere,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
|
|
@ -241,10 +212,10 @@ fn emit_polonius_mir<'tcx>(
|
|||
// Add localized outlives constraints
|
||||
match pass_where {
|
||||
PassWhere::BeforeCFG => {
|
||||
if localized_outlives_constraints.len() > 0 {
|
||||
if localized_outlives_constraints.outlives.len() > 0 {
|
||||
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 from = liveness.location_from_point(*from);
|
||||
let to = liveness.location_from_point(*to);
|
||||
|
|
@ -428,7 +399,7 @@ fn emit_mermaid_nll_sccs<'tcx>(
|
|||
fn emit_mermaid_constraint_graph<'tcx>(
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<usize> {
|
||||
let location_name = |location: Location| {
|
||||
|
|
@ -467,7 +438,7 @@ fn emit_mermaid_constraint_graph<'tcx>(
|
|||
// The regions subgraphs containing the region/point nodes.
|
||||
let mut points_per_region: FxIndexMap<RegionVid, FxIndexSet<PointIndex>> =
|
||||
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.target).or_default().insert(constraint.to);
|
||||
}
|
||||
|
|
@ -480,7 +451,7 @@ fn emit_mermaid_constraint_graph<'tcx>(
|
|||
}
|
||||
|
||||
// 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.
|
||||
writeln!(
|
||||
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
|
||||
// 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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if bk.is_two_phase_borrow() {
|
||||
if bk.allows_two_phase_borrow() {
|
||||
(Deep, Reservation(wk))
|
||||
} else {
|
||||
(Deep, Write(wk))
|
||||
|
|
@ -297,9 +297,8 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
Rvalue::Use(operand)
|
||||
| Rvalue::Repeat(operand, _)
|
||||
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
||||
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) => {
|
||||
self.consume_operand(location, operand)
|
||||
}
|
||||
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
|
||||
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand),
|
||||
|
||||
&Rvalue::Discriminant(place) => {
|
||||
self.access_place(
|
||||
|
|
@ -385,7 +384,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(this.dominators, borrow, location) {
|
||||
// If the borrow isn't active yet, reads don't invalidate it
|
||||
assert!(borrow.kind.is_two_phase_borrow());
|
||||
assert!(borrow.kind.allows_two_phase_borrow());
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,22 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::bit_set::SparseBitMatrix;
|
||||
use rustc_middle::mir::{Body, Location};
|
||||
use rustc_middle::ty::relate::{
|
||||
self, Relate, RelateResult, TypeRelation, relate_args_with_variances,
|
||||
};
|
||||
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;
|
||||
|
||||
impl PoloniusContext {
|
||||
impl PoloniusLivenessContext {
|
||||
/// Record the variance of each region contained within the given value.
|
||||
pub(crate) fn record_live_region_variance<'tcx>(
|
||||
&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
|
||||
/// `rustc_infer`'s `Generalizer`: we try to relate a type with itself to track and extract the
|
||||
/// 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/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 dump;
|
||||
pub(crate) mod legacy;
|
||||
mod liveness_constraints;
|
||||
mod loan_liveness;
|
||||
mod typeck_constraints;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_index::bit_set::SparseBitMatrix;
|
||||
use rustc_index::interval::SparseIntervalMatrix;
|
||||
use rustc_middle::mir::{Body, Local};
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
|
||||
pub(self) use self::constraints::*;
|
||||
pub(crate) use self::constraints::*;
|
||||
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::region_infer::values::LivenessValues;
|
||||
use crate::{BorrowSet, RegionInferenceContext};
|
||||
|
||||
pub(crate) type LiveLoans = SparseBitMatrix<PointIndex, BorrowIndex>;
|
||||
|
||||
/// This struct holds the necessary
|
||||
/// - liveness data, created during MIR typeck, and which will be used to lazily compute the
|
||||
/// polonius localized constraints, during NLL region inference as well as MIR dumping,
|
||||
/// - data needed by the borrowck error computation and diagnostics.
|
||||
/// This struct holds the liveness data created during MIR typeck, and which will be used later in
|
||||
/// the process, to compute the polonius localized constraints.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct PoloniusContext {
|
||||
/// The graph from which we extract the localized outlives constraints.
|
||||
graph: Option<LocalizedConstraintGraph>,
|
||||
|
||||
pub(crate) struct PoloniusLivenessContext {
|
||||
/// 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.
|
||||
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
|
||||
|
|
@ -74,6 +84,27 @@ pub(crate) struct PoloniusContext {
|
|||
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
|
||||
/// variance.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
|
|
@ -89,6 +120,26 @@ enum ConstraintDirection {
|
|||
}
|
||||
|
||||
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`.
|
||||
///
|
||||
/// 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.
|
||||
pub(crate) fn compute_loan_liveness<'tcx>(
|
||||
&mut self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
regioncx: &mut RegionInferenceContext<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) {
|
||||
let liveness = regioncx.liveness_constraints();
|
||||
) -> PoloniusDiagnosticsContext {
|
||||
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
|
||||
// trace throughout localized constraints.
|
||||
if borrow_set.len() > 0 {
|
||||
// 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 localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
|
||||
convert_typeck_constraints(
|
||||
tcx,
|
||||
body,
|
||||
regioncx.liveness_constraints(),
|
||||
regioncx.outlives_constraints(),
|
||||
regioncx.universal_regions(),
|
||||
&mut localized_outlives_constraints,
|
||||
);
|
||||
|
||||
let mut live_loans = LiveLoans::new(borrow_set.len());
|
||||
let mut visitor = LoanLivenessVisitor { liveness, live_loans: &mut live_loans };
|
||||
graph.traverse(
|
||||
body,
|
||||
liveness,
|
||||
&self.live_region_variances,
|
||||
regioncx.universal_regions(),
|
||||
borrow_set,
|
||||
&mut visitor,
|
||||
);
|
||||
regioncx.record_live_loans(live_loans);
|
||||
create_liveness_constraints(
|
||||
body,
|
||||
regioncx.liveness_constraints(),
|
||||
&self.live_regions,
|
||||
&live_region_variances,
|
||||
regioncx.universal_regions(),
|
||||
&mut localized_outlives_constraints,
|
||||
);
|
||||
|
||||
// The graph can be traversed again during MIR dumping, so we store it here.
|
||||
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);
|
||||
}
|
||||
// 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,
|
||||
&localized_outlives_constraints,
|
||||
);
|
||||
regioncx.record_live_loans(live_loans);
|
||||
|
||||
PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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))
|
||||
}
|
||||
ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(),
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => {
|
||||
ty::BoundRegionKind::NamedAnon(_) => {
|
||||
bug!("only used for pretty printing")
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1379,11 +1379,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
.elements_contained_in(longer_fr_scc)
|
||||
.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.
|
||||
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesIllegalRegion {
|
||||
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
|
||||
longer_fr,
|
||||
illegally_outlived_r,
|
||||
error_element,
|
||||
placeholder,
|
||||
});
|
||||
} else {
|
||||
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`.
|
||||
fn region_from_element(
|
||||
pub(crate) fn region_from_element(
|
||||
&self,
|
||||
longer_fr: RegionVid,
|
||||
element: &RegionElement<'tcx>,
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use super::reverse_sccs::ReverseSccGraph;
|
||||
use crate::BorrowckInferCtxt;
|
||||
use crate::consumers::RegionInferenceContext;
|
||||
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
|
||||
use crate::type_check::canonical::fully_perform_op_raw;
|
||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use crate::universal_regions::{RegionClassification, UniversalRegions};
|
||||
use crate::{BorrowckInferCtxt, CollectRegionConstraintsResult};
|
||||
|
||||
mod member_constraints;
|
||||
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
|
||||
/// expects the hidden type to be mapped to the definition parameters of the opaque
|
||||
/// 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
|
||||
/// recheck all uses of the opaques regardless.
|
||||
pub(crate) fn compute_definition_site_hidden_types<'tcx>(
|
||||
def_id: LocalDefId,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
||||
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
|
||||
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
|
||||
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
|
||||
// the opaque type definition. This is stored in the `root_cx`.
|
||||
compute_definition_site_hidden_types_from_defining_uses(
|
||||
def_id,
|
||||
&rcx,
|
||||
hidden_types,
|
||||
unconstrained_hidden_type_errors,
|
||||
&defining_uses,
|
||||
&mut errors,
|
||||
);
|
||||
|
|
@ -303,10 +274,8 @@ fn collect_defining_uses<'tcx>(
|
|||
|
||||
#[instrument(level = "debug", skip(rcx, hidden_types, defining_uses, errors))]
|
||||
fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
||||
def_id: LocalDefId,
|
||||
rcx: &RegionCtxt<'_, 'tcx>,
|
||||
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
|
||||
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
|
||||
defining_uses: &[DefiningUse<'tcx>],
|
||||
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
|
||||
) {
|
||||
|
|
@ -324,29 +293,16 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
|||
Ok(hidden_type) => hidden_type,
|
||||
Err(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 {
|
||||
hidden_type,
|
||||
opaque_type_key,
|
||||
member_region: ty::Region::new_var(tcx, r),
|
||||
});
|
||||
let guar = tcx.dcx().span_delayed_bug(
|
||||
hidden_type.span,
|
||||
"opaque type with non-universal region args",
|
||||
);
|
||||
ty::ProvisionalHiddenType::new_error(tcx, guar)
|
||||
}
|
||||
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
|
||||
hidden_type,
|
||||
opaque_type_key,
|
||||
member_region: ty::Region::new_var(tcx, r),
|
||||
});
|
||||
let guar = tcx.dcx().span_delayed_bug(
|
||||
hidden_type.span,
|
||||
"opaque type with non-universal region args",
|
||||
);
|
||||
ty::ProvisionalHiddenType::new_error(tcx, guar)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -614,40 +570,6 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
|
|||
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.
|
||||
/// 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 tracing::debug;
|
||||
|
||||
use crate::BorrowIndex;
|
||||
use crate::polonius::LiveLoans;
|
||||
use crate::{BorrowIndex, TyCtxt};
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A single integer representing a `ty::Placeholder`.
|
||||
|
|
@ -131,17 +131,9 @@ impl LivenessValues {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns whether `region` is marked live at the given
|
||||
/// [`location`][rustc_middle::mir::Location].
|
||||
/// Returns whether `region` is marked live at the given `location`.
|
||||
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
|
||||
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 {
|
||||
points.row(region).is_some_and(|r| r.contains(point))
|
||||
} else {
|
||||
|
|
@ -428,18 +420,18 @@ impl ToElementIndex<'_> for RegionVid {
|
|||
impl<'tcx> ToElementIndex<'tcx> for ty::PlaceholderRegion<'tcx> {
|
||||
fn add_to_row<N: Idx>(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool
|
||||
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);
|
||||
values.placeholders.insert(row, index)
|
||||
}
|
||||
|
||||
fn contained_in_row<N: Idx>(self, values: &RegionValues<'tcx, N>, row: N) -> bool
|
||||
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);
|
||||
values.placeholders.contains(row, index)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ use smallvec::SmallVec;
|
|||
use crate::consumers::BorrowckConsumer;
|
||||
use crate::nll::compute_closure_requirements_modulo_opaques;
|
||||
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,
|
||||
handle_unconstrained_hidden_type_errors,
|
||||
};
|
||||
use crate::type_check::{Locations, constraint_conversion};
|
||||
use crate::{
|
||||
|
|
@ -27,12 +26,7 @@ use crate::{
|
|||
pub(super) struct BorrowCheckRootCtxt<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
root_def_id: LocalDefId,
|
||||
/// This contains fully resolved hidden types or `ty::Error`.
|
||||
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
|
||||
/// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
|
||||
/// their parents.
|
||||
|
|
@ -55,7 +49,6 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
tcx,
|
||||
root_def_id,
|
||||
hidden_types: Default::default(),
|
||||
unconstrained_hidden_type_errors: Default::default(),
|
||||
collect_region_constraints_results: Default::default(),
|
||||
propagated_borrowck_results: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
|
|
@ -91,32 +84,23 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
|
||||
fn handle_opaque_type_uses(&mut self) {
|
||||
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(
|
||||
&input.infcx,
|
||||
&input.universal_region_relations,
|
||||
&mut input.constraints,
|
||||
);
|
||||
input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
|
||||
*def_id,
|
||||
&input.infcx,
|
||||
&input.universal_region_relations,
|
||||
&input.constraints,
|
||||
Rc::clone(&input.location_map),
|
||||
&mut self.hidden_types,
|
||||
&mut self.unconstrained_hidden_type_errors,
|
||||
&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
|
||||
self.collect_region_constraints_results.values_mut().zip(per_body_info)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@ use rustc_span::Span;
|
|||
use crate::diagnostics::RegionName;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("cannot move a value of type `{$ty}`", code = E0161)]
|
||||
#[diag(borrowck_move_unsized, code = E0161)]
|
||||
pub(crate) struct MoveUnsized<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
#[primary_span]
|
||||
#[label("the size of `{$ty}` cannot be statically determined")]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("higher-ranked lifetime error")]
|
||||
#[diag(borrowck_higher_ranked_lifetime_error)]
|
||||
pub(crate) struct HigherRankedLifetimeError {
|
||||
#[subdiagnostic]
|
||||
pub cause: Option<HigherRankedErrorCause>,
|
||||
|
|
@ -26,21 +26,21 @@ pub(crate) struct HigherRankedLifetimeError {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum HigherRankedErrorCause {
|
||||
#[note("could not prove `{$predicate}`")]
|
||||
#[note(borrowck_could_not_prove)]
|
||||
CouldNotProve { predicate: String },
|
||||
#[note("could not normalize `{$value}`")]
|
||||
#[note(borrowck_could_not_normalize)]
|
||||
CouldNotNormalize { value: String },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("higher-ranked subtype error")]
|
||||
#[diag(borrowck_higher_ranked_subtype_error)]
|
||||
pub(crate) struct HigherRankedSubtypeError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`{$kind}` does not live long enough")]
|
||||
#[diag(borrowck_generic_does_not_live_long_enough)]
|
||||
pub(crate) struct GenericDoesNotLiveLongEnough {
|
||||
pub kind: String,
|
||||
#[primary_span]
|
||||
|
|
@ -48,20 +48,15 @@ pub(crate) struct GenericDoesNotLiveLongEnough {
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag("variable does not need to be mutable")]
|
||||
#[diag(borrowck_var_does_not_need_mut)]
|
||||
pub(crate) struct VarNeedNotMut {
|
||||
#[suggestion(
|
||||
"remove this `mut`",
|
||||
style = "short",
|
||||
applicability = "machine-applicable",
|
||||
code = ""
|
||||
)]
|
||||
#[suggestion(style = "short", applicability = "machine-applicable", code = "")]
|
||||
pub span: Span,
|
||||
}
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("captured variable cannot escape `FnMut` closure body")]
|
||||
#[note("`FnMut` closures only have access to their captured variables while they are executing...")]
|
||||
#[note("...therefore, they cannot allow references to captured variables to escape")]
|
||||
#[diag(borrowck_var_cannot_escape_closure)]
|
||||
#[note]
|
||||
#[note(borrowck_cannot_escape)]
|
||||
pub(crate) struct FnMutError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -71,17 +66,17 @@ pub(crate) struct FnMutError {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum VarHereDenote {
|
||||
#[label("variable captured here")]
|
||||
#[label(borrowck_var_here_captured)]
|
||||
Captured {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label("variable defined here")]
|
||||
#[label(borrowck_var_here_defined)]
|
||||
Defined {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label("inferred to be a `FnMut` closure")]
|
||||
#[label(borrowck_closure_inferred_mut)]
|
||||
FnMutInferred {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -90,21 +85,17 @@ pub(crate) enum VarHereDenote {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum FnMutReturnTypeErr {
|
||||
#[label(
|
||||
"returns a closure that contains a reference to a captured variable, which then escapes the closure body"
|
||||
)]
|
||||
#[label(borrowck_returned_closure_escaped)]
|
||||
ReturnClosure {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(
|
||||
"returns an `async` block that contains a reference to a captured variable, which then escapes the closure body"
|
||||
)]
|
||||
#[label(borrowck_returned_async_block_escaped)]
|
||||
ReturnAsyncBlock {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label("returns a reference to a captured variable which escapes the closure body")]
|
||||
#[label(borrowck_returned_ref_escaped)]
|
||||
ReturnRef {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -112,7 +103,7 @@ pub(crate) enum FnMutReturnTypeErr {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("lifetime may not live long enough")]
|
||||
#[diag(borrowck_lifetime_constraints_error)]
|
||||
pub(crate) struct LifetimeOutliveErr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -120,9 +111,7 @@ pub(crate) struct LifetimeOutliveErr {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
||||
#[label(
|
||||
"{$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`"
|
||||
)]
|
||||
#[label(borrowck_returned_lifetime_wrong)]
|
||||
WrongReturn {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -130,9 +119,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
|||
outlived_fr_name: RegionName,
|
||||
fr_name: &'a RegionName,
|
||||
},
|
||||
#[label(
|
||||
"{$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`"
|
||||
)]
|
||||
#[label(borrowck_returned_lifetime_short)]
|
||||
ShortReturn {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -144,7 +131,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum RequireStaticErr {
|
||||
#[note("the used `impl` has a `'static` requirement")]
|
||||
#[note(borrowck_used_impl_require_static)]
|
||||
UsedImpl {
|
||||
#[primary_span]
|
||||
multi_span: MultiSpan,
|
||||
|
|
@ -153,42 +140,42 @@ pub(crate) enum RequireStaticErr {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureVarPathUseCause {
|
||||
#[label("borrow occurs due to use in coroutine")]
|
||||
#[label(borrowck_borrow_due_to_use_coroutine)]
|
||||
BorrowInCoroutine {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label("use occurs due to use in coroutine")]
|
||||
#[label(borrowck_use_due_to_use_coroutine)]
|
||||
UseInCoroutine {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label("assign occurs due to use in coroutine")]
|
||||
#[label(borrowck_assign_due_to_use_coroutine)]
|
||||
AssignInCoroutine {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label("assign to part occurs due to use in coroutine")]
|
||||
#[label(borrowck_assign_part_due_to_use_coroutine)]
|
||||
AssignPartInCoroutine {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label("borrow occurs due to use in closure")]
|
||||
#[label(borrowck_borrow_due_to_use_closure)]
|
||||
BorrowInClosure {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label("use occurs due to use in closure")]
|
||||
#[label(borrowck_use_due_to_use_closure)]
|
||||
UseInClosure {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label("assignment occurs due to use in closure")]
|
||||
#[label(borrowck_assign_due_to_use_closure)]
|
||||
AssignInClosure {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label("assignment to part occurs due to use in closure")]
|
||||
#[label(borrowck_assign_part_due_to_use_closure)]
|
||||
AssignPartInClosure {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
|
|
@ -197,17 +184,17 @@ pub(crate) enum CaptureVarPathUseCause {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureVarKind {
|
||||
#[label("capture is immutable because of use here")]
|
||||
#[label(borrowck_capture_immute)]
|
||||
Immut {
|
||||
#[primary_span]
|
||||
kind_span: Span,
|
||||
},
|
||||
#[label("capture is mutable because of use here")]
|
||||
#[label(borrowck_capture_mut)]
|
||||
Mut {
|
||||
#[primary_span]
|
||||
kind_span: Span,
|
||||
},
|
||||
#[label("capture is moved because of use here")]
|
||||
#[label(borrowck_capture_move)]
|
||||
Move {
|
||||
#[primary_span]
|
||||
kind_span: Span,
|
||||
|
|
@ -216,97 +203,77 @@ pub(crate) enum CaptureVarKind {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureVarCause {
|
||||
#[label(
|
||||
"{$is_single_var ->
|
||||
*[true] borrow occurs
|
||||
[false] borrows occur
|
||||
} due to use of {$place} in coroutine"
|
||||
)]
|
||||
#[label(borrowck_var_borrow_by_use_place_in_coroutine)]
|
||||
BorrowUsePlaceCoroutine {
|
||||
is_single_var: bool,
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(
|
||||
"{$is_single_var ->
|
||||
*[true] borrow occurs
|
||||
[false] borrows occur
|
||||
} due to use of {$place} in closure"
|
||||
)]
|
||||
#[label(borrowck_var_borrow_by_use_place_in_closure)]
|
||||
BorrowUsePlaceClosure {
|
||||
is_single_var: bool,
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label("borrow occurs due to use in coroutine")]
|
||||
#[label(borrowck_var_borrow_by_use_in_coroutine)]
|
||||
BorrowUseInCoroutine {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label("borrow occurs due to use in closure")]
|
||||
#[label(borrowck_var_borrow_by_use_in_closure)]
|
||||
BorrowUseInClosure {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label("move occurs due to use in coroutine")]
|
||||
#[label(borrowck_var_move_by_use_in_coroutine)]
|
||||
MoveUseInCoroutine {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label("move occurs due to use in closure")]
|
||||
#[label(borrowck_var_move_by_use_in_closure)]
|
||||
MoveUseInClosure {
|
||||
#[primary_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 {
|
||||
place: String,
|
||||
#[primary_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 {
|
||||
place: String,
|
||||
#[primary_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 {
|
||||
place: String,
|
||||
#[primary_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 {
|
||||
place: String,
|
||||
#[primary_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 {
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(
|
||||
"variable {$is_partial ->
|
||||
[true] partially moved
|
||||
*[false] moved
|
||||
} due to use in coroutine"
|
||||
)]
|
||||
#[label(borrowck_partial_var_move_by_use_in_coroutine)]
|
||||
PartialMoveUseInCoroutine {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
is_partial: bool,
|
||||
},
|
||||
#[label(
|
||||
"variable {$is_partial ->
|
||||
[true] partially moved
|
||||
*[false] moved
|
||||
} due to use in closure"
|
||||
)]
|
||||
#[label(borrowck_partial_var_move_by_use_in_closure)]
|
||||
PartialMoveUseInClosure {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
|
|
@ -315,57 +282,34 @@ pub(crate) enum CaptureVarCause {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("cannot move out of {$place ->
|
||||
[value] value
|
||||
*[other] {$place}
|
||||
} because it is borrowed", code = E0505)]
|
||||
#[diag(borrowck_cannot_move_when_borrowed, code = E0505)]
|
||||
pub(crate) struct MoveBorrow<'a> {
|
||||
pub place: &'a str,
|
||||
pub borrow_place: &'a str,
|
||||
pub value_place: &'a str,
|
||||
#[primary_span]
|
||||
#[label(
|
||||
"move out of {$value_place ->
|
||||
[value] value
|
||||
*[other] {$value_place}
|
||||
} occurs here"
|
||||
)]
|
||||
#[label(borrowck_move_label)]
|
||||
pub span: Span,
|
||||
#[label(
|
||||
"borrow of {$borrow_place ->
|
||||
[value] value
|
||||
*[other] {$borrow_place}
|
||||
} occurs here"
|
||||
)]
|
||||
#[label]
|
||||
pub borrow_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("opaque type used twice with different lifetimes")]
|
||||
#[diag(borrowck_opaque_type_lifetime_mismatch)]
|
||||
pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> {
|
||||
pub arg: GenericArg<'tcx>,
|
||||
pub prev: GenericArg<'tcx>,
|
||||
#[primary_span]
|
||||
#[label("lifetime `{$arg}` 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"
|
||||
)]
|
||||
#[label]
|
||||
#[note]
|
||||
pub span: Span,
|
||||
#[label("lifetime `{$prev}` previously used here")]
|
||||
#[label(borrowck_prev_lifetime_label)]
|
||||
pub prev_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureReasonLabel<'a> {
|
||||
#[label(
|
||||
"{$place_name} {$is_partial ->
|
||||
[true] partially moved
|
||||
*[false] moved
|
||||
} due to this {$is_loop_message ->
|
||||
[true] call, in previous iteration of loop
|
||||
*[false] call
|
||||
}"
|
||||
)]
|
||||
#[label(borrowck_moved_due_to_call)]
|
||||
Call {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -373,15 +317,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(
|
||||
"{$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
|
||||
}"
|
||||
)]
|
||||
#[label(borrowck_moved_due_to_usage_in_operator)]
|
||||
OperatorUse {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -389,15 +325,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(
|
||||
"{$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()`
|
||||
}"
|
||||
)]
|
||||
#[label(borrowck_moved_due_to_implicit_into_iter_call)]
|
||||
ImplicitCall {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -405,15 +333,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(
|
||||
"{$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
|
||||
}"
|
||||
)]
|
||||
#[label(borrowck_moved_due_to_method_call)]
|
||||
MethodCall {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -421,15 +341,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(
|
||||
"{$place_name} {$is_partial ->
|
||||
[true] partially moved
|
||||
*[false] moved
|
||||
} due to this {$is_loop_message ->
|
||||
[true] await, in previous iteration of loop
|
||||
*[false] await
|
||||
}"
|
||||
)]
|
||||
#[label(borrowck_moved_due_to_await)]
|
||||
Await {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -437,18 +349,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(
|
||||
"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] {\"\"}
|
||||
}"
|
||||
)]
|
||||
#[label(borrowck_value_moved_here)]
|
||||
MovedHere {
|
||||
#[primary_span]
|
||||
move_span: Span,
|
||||
|
|
@ -456,7 +357,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_move_msg: 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 {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
|
|
@ -465,22 +366,22 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
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 {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[note("calling this operator moves the value")]
|
||||
#[note(borrowck_calling_operator_moves)]
|
||||
UnOpMoveByOperator {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note("calling this operator moves the left-hand side")]
|
||||
#[note(borrowck_calling_operator_moves_lhs)]
|
||||
LhsMoveByOperator {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note("`{$func}` takes ownership of the receiver `self`, which moves {$place_name}")]
|
||||
#[note(borrowck_func_take_self_moved_place)]
|
||||
FuncTakeSelf {
|
||||
func: String,
|
||||
place_name: String,
|
||||
|
|
@ -492,7 +393,7 @@ pub(crate) enum CaptureReasonNote {
|
|||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureReasonSuggest<'tcx> {
|
||||
#[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",
|
||||
code = "&",
|
||||
style = "verbose"
|
||||
|
|
@ -503,7 +404,7 @@ pub(crate) enum CaptureReasonSuggest<'tcx> {
|
|||
span: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
"consider reborrowing the `Pin` instead of moving it",
|
||||
borrowck_suggest_create_fresh_reborrow,
|
||||
applicability = "maybe-incorrect",
|
||||
code = ".as_mut()",
|
||||
style = "verbose"
|
||||
|
|
@ -516,18 +417,13 @@ pub(crate) enum CaptureReasonSuggest<'tcx> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureArgLabel {
|
||||
#[label(
|
||||
"value captured {$is_within ->
|
||||
[true] here by coroutine
|
||||
*[false] here
|
||||
}"
|
||||
)]
|
||||
#[label(borrowck_value_capture_here)]
|
||||
Capture {
|
||||
is_within: bool,
|
||||
#[primary_span]
|
||||
args_span: Span,
|
||||
},
|
||||
#[label("{$place} is moved here")]
|
||||
#[label(borrowck_move_out_place_here)]
|
||||
MoveOutPlace {
|
||||
place: String,
|
||||
#[primary_span]
|
||||
|
|
@ -537,17 +433,13 @@ pub(crate) enum CaptureArgLabel {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum OnClosureNote<'a> {
|
||||
#[note(
|
||||
"closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment"
|
||||
)]
|
||||
#[note(borrowck_closure_invoked_twice)]
|
||||
InvokedTwice {
|
||||
place_name: &'a str,
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(
|
||||
"closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment"
|
||||
)]
|
||||
#[note(borrowck_closure_moved_twice)]
|
||||
MovedTwice {
|
||||
place_name: &'a str,
|
||||
#[primary_span]
|
||||
|
|
@ -557,12 +449,7 @@ pub(crate) enum OnClosureNote<'a> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
||||
#[label(
|
||||
"{$is_partial_move ->
|
||||
[true] partial move
|
||||
*[false] move
|
||||
} occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait"
|
||||
)]
|
||||
#[label(borrowck_ty_no_impl_copy)]
|
||||
Label {
|
||||
is_partial_move: bool,
|
||||
ty: Ty<'tcx>,
|
||||
|
|
@ -570,24 +457,12 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
|||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(
|
||||
"{$is_partial_move ->
|
||||
[true] partial move
|
||||
*[false] move
|
||||
} occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait"
|
||||
)]
|
||||
#[note(borrowck_ty_no_impl_copy)]
|
||||
Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"{$arg ->
|
||||
[1] 1st
|
||||
[2] 2nd
|
||||
[3] 3rd
|
||||
*[other] {$arg}th
|
||||
} argument of `{$intrinsic}` is required to be a `const` item"
|
||||
)]
|
||||
#[diag(borrowck_simd_intrinsic_arg_const)]
|
||||
pub(crate) struct SimdIntrinsicArgConst {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -596,8 +471,8 @@ pub(crate) struct SimdIntrinsicArgConst {
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag("relative drop order changing in Rust 2024")]
|
||||
#[diag(borrowck_tail_expr_drop_order)]
|
||||
pub(crate) struct TailExprDropOrder {
|
||||
#[label("this temporary value will be dropped at the end of the block")]
|
||||
#[label]
|
||||
pub borrowed: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,15 +343,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
// This is a hack. `body.local_decls` are not necessarily normalized in the old
|
||||
// solver due to not deeply normalizing in writeback. So we must re-normalize here.
|
||||
//
|
||||
// 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)),
|
||||
};
|
||||
// FIXME: Ideally MIR types are normalized, but this is not always true.
|
||||
let mir_ty = self.normalize(mir_ty, Locations::All(span));
|
||||
|
||||
let cause = ObligationCause::dummy_with_span(span);
|
||||
let param_env = self.infcx.param_env;
|
||||
|
|
@ -360,10 +353,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ConstraintCategory::Boring,
|
||||
type_op::custom::CustomTypeOp::new(
|
||||
|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);
|
||||
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
|
||||
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